From a10676ced484004e3b6a0589cd47d207c808c640 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 4 Sep 2024 06:10:07 +0000 Subject: [PATCH 01/79] wip --- noir-projects/aztec-nr/aztec/src/lib.nr | 1 + .../aztec/src/macros/functions/mod.nr | 148 ++++++++++++++++++ .../aztec-nr/aztec/src/macros/mod.nr | 3 + .../aztec-nr/aztec/src/macros/note/mod.nr | 9 ++ .../aztec-nr/aztec/src/macros/utils.nr | 72 +++++++++ .../aztec/src/note/note_getter/mod.nr | 4 +- .../src/easy_private_uint.nr | 2 +- .../contracts/counter_contract/src/main.nr | 98 ++++++------ .../crates/types/src/traits.nr | 5 +- .../types/src/abi/contract_artifact.ts | 6 +- yarn-project/types/src/noir/index.ts | 1 + 11 files changed, 293 insertions(+), 56 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr create mode 100644 noir-projects/aztec-nr/aztec/src/macros/mod.nr create mode 100644 noir-projects/aztec-nr/aztec/src/macros/note/mod.nr create mode 100644 noir-projects/aztec-nr/aztec/src/macros/utils.nr diff --git a/noir-projects/aztec-nr/aztec/src/lib.nr b/noir-projects/aztec-nr/aztec/src/lib.nr index af7f03c1f51..5e50e7a72aa 100644 --- a/noir-projects/aztec-nr/aztec/src/lib.nr +++ b/noir-projects/aztec-nr/aztec/src/lib.nr @@ -15,5 +15,6 @@ mod encrypted_logs; mod unencrypted_logs; use dep::protocol_types; mod utils; +mod macros; mod test; diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr new file mode 100644 index 00000000000..dae031485b2 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -0,0 +1,148 @@ +use std::meta::unquote; +use std::meta::type_of; + +use crate::macros::utils::{modify_fn_body, serialize_to_hasher, get_fn_visibility, is_fn_private, fn_body_as_quoted}; + +pub comptime fn internal(func: FunctionDefinition) { + let internal_check = quote { assert(context.msg_sender() == context.this_address(), r"Function $func.name() can only be called internally"); }; + modify_fn_body(func, internal_check, quote {}); +} + +pub comptime fn view(func: FunctionDefinition) { + let static_check = if is_fn_private(func) { + quote { assert(context.inputs.call_context.is_static_call == true, r"Function $func.name() can only be called statically"); } + } else { + quote { assert(context.inputs.call_context.is_static_call == true, r"Function $func.name() can only be called statically"); } + }; + modify_fn_body(func, static_check, quote {}); +} + +pub comptime fn initializer(func: FunctionDefinition) { + let to_prepend = if is_fn_private(func) { + quote { + dep::aztec::initializer::assert_initialization_matches_address_preimage_private(context); + } + } else { + quote { + dep::aztec::initializer::assert_initialization_matches_address_preimage_public(context); + } + }; + modify_fn_body(func, to_prepend, quote {}); +} + +fn create_init_check(func: FunctionDefinition) -> Quoted { + if is_fn_private(func) { + quote { dep::aztec::initializer::assert_is_initialized_private(&mut context); } + } else { + quote { dep::aztec::initializer::assert_is_initialized_public(&mut context); } + } +} + +fn create_fn_abi_export(func: FunctionDefinition) -> Quoted { + let name = func.name(); + // Remove first arg (inputs) + let mut parameters = func.parameters().pop_front().1.map( + | (name, typ): (Quoted, Type) | { + quote { $name: $typ } + } + ).join(quote{,}); + + let parameters_struct_name = name.join_tokens(quote {_parameters }); + let parameters = quote { + struct $parameters_struct_name { + $parameters + } + }; + + let return_value_type = func.return_type(); + let return_type_quote = if !return_value_type.eq(type_of(())) { + quote { return_type: $return_value_type } + } else { + quote {} + }; + + let abi_struct_name = name.join_tokens(quote {_abi}); + + let result = quote { + + $parameters + + #[abi(functions)] + struct $abi_struct_name { + parameters: $parameters_struct_name, + $return_type_quote + } + }; + result +} + +pub comptime fn private(func: FunctionDefinition) { + let current_params = func.parameters(); + func.set_parameters( + &[ + ( + quote { inputs }, quote { crate::context::inputs::private_context_inputs::PrivateContextInputs }.as_type() + ) + ].append(current_params) + ); + let mut body = func.body().as_block().unwrap(); + let args_hasher_name_quote = quote { args_hasher }; + let args_hasher_quote = current_params.fold( + quote { + let mut $args_hasher_name_quote = dep::aztec::hash::ArgsHasher::new(); + }, + |args_hasher_quote, param: (Quoted, Type)| { + let (name, typ) = param; + let appended_arg_quote = serialize_to_hasher(args_hasher_name_quote, name, typ); + quote { + $args_hasher_quote + $appended_arg_quote + } + } + ); + let context_creation_quote = quote { let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); }; + let storage_init_quote = quote { let storage = Storage::init(&mut context); }; + let init_check = create_init_check(func); + + let return_value_type = func.return_type(); + + let return_value_quote = if !return_value_type.eq(type_of(())) { + let (body_without_return, return_value) = body.pop_back(); + let return_value_quote = return_value.quoted(); + let return_hasher_name_quote = quote { return_hasher }; + let return_value_into_hasher_quote = serialize_to_hasher( + return_hasher_name_quote, + return_value_quote, + return_value_type + ); + + body = body_without_return; + + quote { + let $return_hasher_name_quote = dep::aztec::hash::ArgsHasher::new(); + $return_value_into_hasher_quote + context.set_return_hash($return_hasher_name_quote); + } + } else { + quote {} + }; + + let context_finish_quote = quote { context.finish() }; + + let to_prepend = quote { + $args_hasher_quote + $context_creation_quote + $storage_init_quote + $init_check + }; + + let to_append = quote { + $return_value_quote + $context_finish_quote + }; + + modify_fn_body(func, to_prepend, to_append); + func.set_return_type( + quote { dep::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs }.as_type() + ); +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr new file mode 100644 index 00000000000..6420b3b8f3d --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -0,0 +1,3 @@ +mod functions; +mod utils; +mod note; diff --git a/noir-projects/aztec-nr/aztec/src/macros/note/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/note/mod.nr new file mode 100644 index 00000000000..175e429ebe9 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/macros/note/mod.nr @@ -0,0 +1,9 @@ +comptime fn note(s: StructDefinition) { + // Automatically inject header if not present + let filtered_header = s.fields().filter( + | (field, typ): (Quoted, Type) | typ.eq(quote { dep::aztec::note::note_header::NoteHeader}.as_type()) + ); + if (filtered_header.len() == 0) { + let _ = s.fields().push_back((quote { header }, quote { dep::aztec::note::note_header::NoteHeader}.as_type())); + } +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr new file mode 100644 index 00000000000..ce4f109c82d --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -0,0 +1,72 @@ +use std::meta::unquote; +use std::meta::type_of; + +fn get_fn_visibility(func: FunctionDefinition) -> Quoted { + if func.has_named_attribute(quote { private }) { + quote { private } + } else { + quote { public } + } +} + +fn is_fn_private(func: FunctionDefinition) -> bool { + func.has_named_attribute(quote { private }) +} + +fn is_fn_public(func: FunctionDefinition) -> bool { + func.has_named_attribute(quote { public }) +} + +fn fn_body_as_quoted(func: FunctionDefinition) -> Quoted { + let body = func.body().as_block(); + assert(body.is_some(), "Function body must be a block"); + body.unwrap().fold( + quote {}, + |body_quote, expr: Expr| { + let expr_quote = expr.quoted(); + quote { + $body_quote + $expr_quote + } + } + ) +} + +fn modify_fn_body(func: FunctionDefinition, prepend: Quoted, append: Quoted) { + let mut body_quote = fn_body_as_quoted(func); + body_quote = quote { + { + $prepend + $body_quote + $append + } + }; + let body_expr = body_quote.as_expr(); + assert(body_expr.is_some(), "Body is not an expression"); + func.set_body(body_expr.unwrap()); +} + +fn serialize_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted { + if typ.is_field() | typ.as_integer().is_some() { + quote { $hasher_name.add($name as Field); } + } else if typ.as_struct().is_some() { + quote { $hasher_name.add_multiple($name.serialize()); } + } else if typ.as_array().is_some() { + let (element_type, _) = typ.as_array().unwrap(); + if element_type.is_field() | element_type.as_integer().is_some() { + quote { $hasher_name.add_multiple($name as Field); } + } else if element_type.as_struct().is_some() { + quote { $hasher_name.add_multiple($name.serialize()); } + } else { + assert(false, f"Unsupported type for serialization of argument {name}"); + std::mem::zeroed() + } + } else if typ.as_str().is_some() { + quote { + $hasher_name.add_multiple($name.to_bytes()); + } + } else { + assert(false, f"Unsupported type for serialization of argument {name}"); + std::mem::zeroed() + } +} diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index 576d05a0885..92881101b09 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -14,7 +14,7 @@ fn extract_property_value_from_selector( serialized_note: [Field; N], selector: PropertySelector ) -> Field { - // Selectors use PropertySelectors in order to locate note properties inside the serialized note. + // Selectors use PropertySelectors in order to locate note properties inside the serialized note. // This allows easier packing and custom (de)serialization schemas. A note property is located // inside the serialized note using the index inside the array, a byte offset and a length. let value = serialized_note[selector.index].to_be_bytes(32); @@ -264,7 +264,7 @@ unconstrained pub fn view_notes( notes } -unconstrained fn flatten_options( +unconstrained fn flatten_options( selects: BoundedVec, N>, sorts: BoundedVec, N> ) -> (u8, [u8; N], [u8; N], [u8; N], [Field; N], [u8; N], [u8; N], [u8; N], [u8; N], [u8; N]) { diff --git a/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr b/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr index 4f829187d07..944c29603a6 100644 --- a/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr +++ b/noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr @@ -21,7 +21,7 @@ impl EasyPrivateUint { } } -impl EasyPrivateUint<&mut PrivateContext> { +impl EasyPrivateUint<&mut PrivateContext> { // Very similar to `value_note::utils::increment`. pub fn add(self, addend: u64, owner: AztecAddress, outgoing_viewer: AztecAddress) { let owner_keys = get_current_public_keys(self.context, owner); diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 97e5e40dec3..82168e8e154 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -1,8 +1,9 @@ contract Counter { // docs:start:imports use dep::aztec::prelude::{AztecAddress, Map}; - use dep::value_note::{balance_utils, value_note::{ValueNote, VALUE_NOTE_LEN}}; + use dep::value_note::{balance_utils, value_note::ValueNote}; use dep::easy_private_state::EasyPrivateUint; + use dep::aztec::macros::{functions::{initializer, private}}; // docs:end:imports // docs:start:storage_struct @@ -13,8 +14,8 @@ contract Counter { // docs:end:storage_struct // docs:start:constructor - #[aztec(private)] - #[aztec(initializer)] + #[initializer] + #[private] // We can name our initializer anything we want as long as it's marked as aztec(initializer) fn initialize(headstart: u64, owner: AztecAddress, outgoing_viewer: AztecAddress) { let counters = storage.counters; @@ -23,9 +24,11 @@ contract Counter { // docs:end:constructor // docs:start:increment - #[aztec(private)] + #[private] fn increment(owner: AztecAddress, outgoing_viewer: AztecAddress) { - dep::aztec::oracle::debug_log::debug_log_format("Incrementing counter for owner {0}", [owner.to_field()]); + unsafe { + dep::aztec::oracle::debug_log::debug_log_format("Incrementing counter for owner {0}", [owner.to_field()]); + } let counters = storage.counters; counters.at(owner).add(1, owner, outgoing_viewer); } @@ -37,51 +40,46 @@ contract Counter { balance_utils::get_balance(counters.at(owner).set) } // docs:end:get_counter - // docs:start:test_imports - use dep::aztec::test::{helpers::{cheatcodes, test_environment::TestEnvironment}}; - use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; - use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; - use dep::aztec::note::note_viewer_options::NoteViewerOptions; + // use dep::aztec::test::{helpers::{cheatcodes, test_environment::TestEnvironment}}; + // use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; + // use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; + // use dep::aztec::note::note_viewer_options::NoteViewerOptions; // docs:end:test_imports - - // docs:start:txe_test_increment - #[test] - fn test_increment() { - // Setup env, generate keys - let mut env = TestEnvironment::new(); - let owner = env.create_account(); - let outgoing_viewer = env.create_account(); - let initial_value: Field = 5; - env.impersonate(owner); - - // Deploy contract and initialize - let initializer = Counter::interface().initialize(initial_value as u64, owner, outgoing_viewer); - let counter_contract = env.deploy_self("Counter").with_private_initializer(initializer); - let contract_address = counter_contract.to_address(); - - // docs:start:txe_test_read_notes - // Read the stored value in the note - env.impersonate(contract_address); - let counter_slot = Counter::storage().counters.slot; - let owner_slot = derive_storage_slot_in_map(counter_slot, owner); - let mut options = NoteViewerOptions::new(); - let notes: BoundedVec = view_notes(owner_slot, options); - let initial_note_value = notes.get(0).value; - assert( - initial_note_value == initial_value, f"Expected {initial_value} but got {initial_note_value}" - ); - // docs:end:txe_test_read_notes - - // Increment the counter - let increment_call_interface = Counter::at(contract_address).increment(owner, outgoing_viewer); - env.call_private_void(increment_call_interface); - // get_counter is an unconstrained function, so we call it directly (we're in the same module) - let current_value_for_owner = get_counter(owner); - let expected_current_value = initial_value + 1; - assert( - expected_current_value == current_value_for_owner, f"Expected {expected_current_value} but got {current_value_for_owner}" - ); - } - // docs:end:txe_test_increment + // // docs:start:txe_test_increment + // #[test] + // fn test_increment() { + // // Setup env, generate keys + // let mut env = TestEnvironment::new(); + // let owner = env.create_account(); + // let outgoing_viewer = env.create_account(); + // let initial_value: Field = 5; + // env.impersonate(owner); + // // Deploy contract and initialize + // let initializer = Counter::interface().initialize(initial_value as u64, owner, outgoing_viewer); + // let counter_contract = env.deploy_self("Counter").with_private_initializer(initializer); + // let contract_address = counter_contract.to_address(); + // // docs:start:txe_test_read_notes + // // Read the stored value in the note + // env.impersonate(contract_address); + // let counter_slot = Counter::storage().counters.slot; + // let owner_slot = derive_storage_slot_in_map(counter_slot, owner); + // let mut options = NoteViewerOptions::new(); + // let notes: BoundedVec = view_notes(owner_slot, options); + // let initial_note_value = notes.get(0).value; + // assert( + // initial_note_value == initial_value, f"Expected {initial_value} but got {initial_note_value}" + // ); + // // docs:end:txe_test_read_notes + // // Increment the counter + // let increment_call_interface = Counter::at(contract_address).increment(owner, outgoing_viewer); + // env.call_private_void(increment_call_interface); + // // get_counter is an unconstrained function, so we call it directly (we're in the same module) + // let current_value_for_owner = get_counter(owner); + // let expected_current_value = initial_value + 1; + // assert( + // expected_current_value == current_value_for_owner, f"Expected {expected_current_value} but got {current_value_for_owner}" + // ); + // } + // // docs:end:txe_test_increment } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr index 774197d3082..8083402384a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr @@ -1,4 +1,5 @@ use crate::utils::field::field_from_bytes; +use std::meta::quoted; // Trait: is_empty // @@ -6,8 +7,8 @@ use crate::utils::field::field_from_bytes; // and it defines empty for the basic data types as 0. // // If a Field is equal to zero, then it is regarded as zero. -// We will go with this definition for now, however it can be problematic -// if a value can actually be zero. In a future refactor, we can +// We will go with this definition for now, however it can be problematic +// if a value can actually be zero. In a future refactor, we can // use the optional type for safety. Doing it now would lead to a worse devex // and would make it harder to sync up with the cpp code. // Preferred over Default trait to convey intent, as default doesn't necessarily mean empty. diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index e8cbbb3aabf..01973e0459f 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -17,6 +17,7 @@ import { Fr } from '@aztec/foundation/fields'; import { AZTEC_INITIALIZER_ATTRIBUTE, AZTEC_INTERNAL_ATTRIBUTE, + AZTEC_META_PRIVATE_ATTRIBUTE, AZTEC_PRIVATE_ATTRIBUTE, AZTEC_PUBLIC_ATTRIBUTE, AZTEC_PUBLIC_VM_ATTRIBUTE, @@ -186,7 +187,10 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: No } function getFunctionType(fn: NoirCompiledContractFunction): FunctionType { - if (fn.custom_attributes.includes(AZTEC_PRIVATE_ATTRIBUTE)) { + if ( + fn.custom_attributes.includes(AZTEC_PRIVATE_ATTRIBUTE) || + fn.custom_attributes.includes(AZTEC_META_PRIVATE_ATTRIBUTE) + ) { return FunctionType.PRIVATE; } else if ( fn.custom_attributes.includes(AZTEC_PUBLIC_ATTRIBUTE) || diff --git a/yarn-project/types/src/noir/index.ts b/yarn-project/types/src/noir/index.ts index b56d32762a0..ba00d6f550c 100644 --- a/yarn-project/types/src/noir/index.ts +++ b/yarn-project/types/src/noir/index.ts @@ -8,6 +8,7 @@ import { } from '@aztec/foundation/abi'; export const AZTEC_PRIVATE_ATTRIBUTE = 'aztec(private)'; +export const AZTEC_META_PRIVATE_ATTRIBUTE = 'aztec_private'; export const AZTEC_PUBLIC_ATTRIBUTE = 'aztec(public)'; export const AZTEC_PUBLIC_VM_ATTRIBUTE = 'aztec(public-vm)'; export const AZTEC_INTERNAL_ATTRIBUTE = 'aztec(internal)'; From b73cd7e9565af4ca3f15f6164f0945a17daba496 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 6 Sep 2024 10:39:12 +0000 Subject: [PATCH 02/79] derive serialize, contract interfaces, full private, lfg --- .../aztec/src/macros/functions/mod.nr | 209 +++++++++++++++--- .../aztec-nr/aztec/src/macros/mod.nr | 46 ++++ .../aztec-nr/aztec/src/macros/storage/mod.nr | 0 .../aztec-nr/aztec/src/macros/utils.nr | 156 +++++++++++-- noir-projects/aztec-nr/aztec/src/prelude.nr | 4 +- .../contracts/counter_contract/src/main.nr | 82 +++---- .../crates/types/src/address/mod.nr | 10 +- .../crates/types/src/lib.nr | 5 +- .../crates/types/src/meta/mod.nr | 105 +++++++++ .../crates/types/src/traits.nr | 14 +- 10 files changed, 523 insertions(+), 108 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 27a6bc38637..831cd1d0ce3 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -1,39 +1,45 @@ -use std::meta::type_of; +use std::meta::{unquote, type_of}; -use crate::macros::utils::{modify_fn_body, serialize_to_hasher, is_fn_private}; -use super::utils::get_fn_visibility; +use super::utils::{ + modify_fn_body, is_fn_private, get_fn_visibility, add_to_hasher, is_fn_view, compute_fn_selector, + add_to_field_slice +}; -pub comptime fn internal(func: FunctionDefinition) { - let name = func.name(); - let internal_check = quote { assert(context.msg_sender() == context.this_address(), f"Function {name} can only be called internally"); }; - modify_fn_body(func, internal_check, quote {}); +comptime mut global STUBS: [Quoted] = &[]; + +pub comptime fn internal(f: FunctionDefinition) { + let name = f.name(); + let assertion_message = f"Function {name} can only be called internally"; + let internal_check = quote { assert(context.msg_sender() == context.this_address(), $assertion_message); }; + modify_fn_body(f, internal_check, quote {}); } -pub comptime fn view(func: FunctionDefinition) { - let name = func.name(); - let static_check = if is_fn_private(func) { - quote { assert(context.inputs.call_context.is_static_call == true, f"Function {name} can only be called statically"); } +pub comptime fn view(f: FunctionDefinition) { + let name = f.name(); + let assertion_message = f"Function {name} can only be called statically"; + let static_check = if is_fn_private(f) { + quote { assert(context.inputs.call_context.is_static_call == true, $assertion_message); } } else { - quote { assert(context.inputs.is_static_call == true, f"Function {name} can only be called statically"); } + quote { assert(context.inputs.is_static_call == true, $assertion_message); } }; - modify_fn_body(func, static_check, quote {}); + modify_fn_body(f, static_check, quote {}); } -pub comptime fn initializer(func: FunctionDefinition) { - let fn_visibility = get_fn_visibility(func); +pub comptime fn initializer(f: FunctionDefinition) { + let fn_visibility = get_fn_visibility(f); let to_prepend = f"dep::aztec::initializer::assert_initialization_matches_address_preimage_{fn_visibility}(context);".quoted_contents(); - modify_fn_body(func, to_prepend, quote {}); + modify_fn_body(f, to_prepend, quote {}); } -fn create_init_check(func: FunctionDefinition) -> Quoted { - let fn_visibility = get_fn_visibility(func); +fn create_init_check(f: FunctionDefinition) -> Quoted { + let fn_visibility = get_fn_visibility(f); f"dep::aztec::initializer::assert_is_initialized_{fn_visibility}(&mut context);".quoted_contents() } -fn create_fn_abi_export(func: FunctionDefinition) -> Quoted { - let name = func.name(); +fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { + let name = f.name(); // Remove first arg (inputs) - let mut parameters = func.parameters().pop_front().1.map( + let mut parameters = f.parameters().pop_front().1.map( | (name, typ): (Quoted, Type) | { quote { $name: $typ } } @@ -46,7 +52,7 @@ fn create_fn_abi_export(func: FunctionDefinition) -> Quoted { } }; - let return_value_type = func.return_type(); + let return_value_type = f.return_type(); let return_type_quote = if !return_value_type.eq(type_of(())) { quote { return_type: $return_value_type } } else { @@ -68,17 +74,20 @@ fn create_fn_abi_export(func: FunctionDefinition) -> Quoted { result } -pub comptime fn private(func: FunctionDefinition) -> Quoted { - let fn_abi = create_fn_abi_export(func); - let current_params = func.parameters(); - func.set_parameters( +pub comptime fn private(f: FunctionDefinition) -> Quoted { + let fn_abi = create_fn_abi_export(f); + let fn_stub = stub_fn(f); + STUBS = STUBS.push_back(fn_stub); + + let current_params = f.parameters(); + f.set_parameters( &[ ( quote { inputs }, quote { crate::context::inputs::private_context_inputs::PrivateContextInputs }.as_type() ) ].append(current_params) ); - let mut body = func.body().as_block().unwrap(); + let mut body = f.body().as_block().unwrap(); let args_hasher_name_quote = quote { args_hasher }; let args_hasher_quote = current_params.fold( quote { @@ -86,7 +95,7 @@ pub comptime fn private(func: FunctionDefinition) -> Quoted { }, |args_hasher_quote, param: (Quoted, Type)| { let (name, typ) = param; - let appended_arg_quote = serialize_to_hasher(args_hasher_name_quote, name, typ); + let appended_arg_quote = add_to_hasher(args_hasher_name_quote, name, typ); quote { $args_hasher_quote $appended_arg_quote @@ -95,15 +104,15 @@ pub comptime fn private(func: FunctionDefinition) -> Quoted { ); let context_creation_quote = quote { let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); }; let storage_init_quote = quote { let storage = Storage::init(&mut context); }; - let init_check = create_init_check(func); + let init_check = create_init_check(f); - let return_value_type = func.return_type(); + let return_value_type = f.return_type(); let return_value_quote = if !return_value_type.eq(type_of(())) { let (body_without_return, return_value) = body.pop_back(); let return_value_quote = return_value.quoted(); let return_hasher_name_quote = quote { return_hasher }; - let return_value_into_hasher_quote = serialize_to_hasher( + let return_value_into_hasher_quote = add_to_hasher( return_hasher_name_quote, return_value_quote, return_value_type @@ -134,9 +143,143 @@ pub comptime fn private(func: FunctionDefinition) -> Quoted { $context_finish_quote }; - modify_fn_body(func, to_prepend, to_append); - func.set_return_type( + modify_fn_body(f, to_prepend, to_append); + f.add_attribute("recursive"); + f.set_return_public(true); + f.set_return_type( quote { dep::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs }.as_type() ); fn_abi } + +pub fn un_constrained(f: FunctionDefinition) { + let context_creation_quote = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); }; + let storage_init_quote = quote { let storage = Storage::init(context); }; + let to_prepend = quote { + $context_creation_quote + $storage_init_quote + }; + + modify_fn_body(f, to_prepend, quote {}); +} + +pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { + let fn_name = f.name(); + let fn_parameters = f.parameters(); + let fn_return_type = f.return_type(); + let fn_visibility = get_fn_visibility(f); + let is_static_call = is_fn_view(f); + let is_void: bool = fn_return_type.eq(type_of(())); + let fn_visibility_capitalized = if fn_visibility.eq(quote { private }) { + quote { Private } + } else { + quote { Public } + }; + let is_static_call_capitalized = if is_static_call { + quote { Static } + } else { + quote { } + }; + let is_void_capitalized = if is_void { quote { Void } } else { quote { } }; + let args_acc_name_quote = quote { args_acc }; + let args_acc_quote = fn_parameters.fold( + quote { + let mut $args_acc_name_quote = &[]; + }, + |args_hasher_quote, param: (Quoted, Type)| { + let (name, typ) = param; + let appended_arg_quote = add_to_field_slice(args_acc_name_quote, name, typ); + quote { + $args_hasher_quote + $appended_arg_quote + } + } + ); + + let args_hash_name_quote = if fn_visibility == quote { private } { + quote { args_hash } + } else { + quote {} + }; + + let args_quote = if fn_visibility == quote { private } { + quote { + $args_acc_quote + let $args_hash_name_quote = dep::aztec::hash::hash_args($args_acc_name_quote); + } + } else { + args_acc_quote + }; + + let fn_parameters_quote = fn_parameters.map( + | (name, typ): (Quoted, Type) | { + quote { $name: $typ } + } + ).join(quote{,}); + + let fn_name_str_quote = fn_name.as_str_quote(); + + let fn_name_len: u32 = unquote!(quote { $fn_name_str_quote.as_bytes().len()}); + + let arg_types_list = fn_parameters.map(|(_, typ): (_, Type)| quote { $typ }).join(quote {,}); + let arg_types = if fn_parameters.len() == 1 { + f"({arg_types_list},)".quoted_contents() + } else { + f"({arg_types_list})".quoted_contents() + }; + + let generics = if is_void { + f"{arg_types}>".quoted_contents() + } else { + f"{arg_types}, {fn_return_type}>".quoted_contents() + }; + + let call_interface_name_quote = f"dep::aztec::context::call_interfaces::{fn_visibility_capitalized}{is_static_call_capitalized}{is_void_capitalized}CallInterface".quoted_contents(); + let call_interface_name_w_generics_quote = f"{call_interface_name_quote}<{fn_name_len}, {generics}".quoted_contents(); + + let fn_selector: Field = compute_fn_selector(f); + + let gas_opts = if fn_visibility.eq(quote { public }) { + quote { gas_opts: dep::aztec::context::gas::GasOpts::default() } + } else { + quote {} + }; + + let input_type = f"crate::context::inputs::{fn_visibility_capitalized}ContextInputs".quoted_contents().as_type(); + + let return_type_hint = if fn_visibility.eq(quote { private }) { + quote { protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs }.as_type() + } else { + fn_return_type + }; + + let parameter_names_quote = if fn_parameters.len() > 0 { + let params = fn_parameters.map(|(name, _): (Quoted, _)| name).join(quote {,}); + f",{params}".quoted_contents() + } else { + quote {} + }; + + let original = quote { + | inputs: $input_type | -> $return_type_hint { + $fn_name(inputs $parameter_names_quote) + } + }; + + quote { + pub fn $fn_name(self, $fn_parameters_quote) -> $call_interface_name_w_generics_quote { + $args_quote + let selector = dep::aztec::protocol_types::abis::function_selector::FunctionSelector::from_field($fn_selector); + $call_interface_name_quote { + target_contract: self.target_contract, + selector, + name: $fn_name_str_quote, + $args_hash_name_quote, + args: $args_acc_name_quote, + original: $original, + is_static: $is_static_call, + $gas_opts + } + } + } +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 6420b3b8f3d..48ae92550b1 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -1,3 +1,49 @@ mod functions; mod utils; mod note; +mod storage; + +use functions::STUBS; + +pub comptime fn generate_contract_interface(m: Module) -> Quoted { + let module_name = m.name(); + let fn_stubs_quote = STUBS.join(quote {}); + + quote { + struct $module_name { + target_contract: dep::aztec::protocol_types::address::AztecAddress + } + + impl $module_name { + $fn_stubs_quote + + pub fn at( + target_contract: aztec::protocol_types::address::AztecAddress + ) -> Self { + Self { target_contract } + } + + pub fn interface() -> Self { + Self { target_contract: aztec::protocol_types::address::AztecAddress::zero() } + } + } + + #[contract_library_method] + pub fn at( + target_contract: aztec::protocol_types::address::AztecAddress + ) -> $module_name { + $module_name { target_contract } + } + + #[contract_library_method] + pub fn interface() -> $module_name { + $module_name { target_contract: aztec::protocol_types::address::AztecAddress::zero() } + } + } +} + +pub comptime fn aztec_contract(m: Module) -> Quoted { + let interface = generate_contract_interface(m); + + interface +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index d2d6c5b69e0..32384eb37ed 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -1,21 +1,27 @@ -pub(crate) fn get_fn_visibility(func: FunctionDefinition) -> Quoted { - if func.has_named_attribute(quote { private }) { +use std::meta::unquote; + +pub(crate) fn get_fn_visibility(f: FunctionDefinition) -> Quoted { + if f.has_named_attribute(quote { private }) { quote { private } } else { quote { public } } } -pub(crate) fn is_fn_private(func: FunctionDefinition) -> bool { - func.has_named_attribute(quote { private }) +pub(crate) fn is_fn_private(f: FunctionDefinition) -> bool { + f.has_named_attribute(quote { private }) +} + +pub(crate) fn is_fn_public(f: FunctionDefinition) -> bool { + f.has_named_attribute(quote { public }) } -pub(crate) fn is_fn_public(func: FunctionDefinition) -> bool { - func.has_named_attribute(quote { public }) +pub(crate) fn is_fn_view(f: FunctionDefinition) -> bool { + f.has_named_attribute(quote { view }) } -pub(crate) fn fn_body_as_quoted(func: FunctionDefinition) -> Quoted { - let body = func.body().as_block(); +pub(crate) fn fn_body_as_quoted(f: FunctionDefinition) -> Quoted { + let body = f.body().as_block(); assert(body.is_some(), "Function body must be a block"); body.unwrap().fold( quote {}, @@ -29,8 +35,8 @@ pub(crate) fn fn_body_as_quoted(func: FunctionDefinition) -> Quoted { ) } -pub(crate) fn modify_fn_body(func: FunctionDefinition, prepend: Quoted, append: Quoted) { - let mut body_quote = fn_body_as_quoted(func); +pub(crate) fn modify_fn_body(f: FunctionDefinition, prepend: Quoted, append: Quoted) { + let mut body_quote = fn_body_as_quoted(f); body_quote = quote { { $prepend @@ -40,30 +46,138 @@ pub(crate) fn modify_fn_body(func: FunctionDefinition, prepend: Quoted, append: }; let body_expr = body_quote.as_expr(); assert(body_expr.is_some(), "Body is not an expression"); - func.set_body(body_expr.unwrap()); + f.set_body(body_expr.unwrap()); } -pub(crate) fn serialize_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted { +pub(crate) fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: Type) -> Quoted { + if typ.is_field() | typ.as_integer().is_some() { + quote { $slice_name = $slice_name.push_back($name as Field); } + } else if typ.as_struct().is_some() { + quote { $slice_name = $slice_name.append($name.serialize()); } + } else if typ.as_array().is_some() { + let (element_type, _) = typ.as_array().unwrap(); + let serialized_name = f"{name}_serialized".quoted_contents(); + quote { + let $serialized_name = $name.map(|x: $element_type | x.serialize()); + for i in 0..$name.len() { + $slice_name = $slice_name.append($serialized_name[i].as_slice()); + } + } + } else if typ.as_str().is_some() { + quote { + $slice_name = $slice_name.append($name.to_bytes()); + } + } else { + assert(false, f"Cannot add to slice: unsupported type {typ} variable {name}"); + std::mem::zeroed() + } +} + +pub(crate) fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted { if typ.is_field() | typ.as_integer().is_some() { quote { $hasher_name.add($name as Field); } } else if typ.as_struct().is_some() { quote { $hasher_name.add_multiple($name.serialize()); } } else if typ.as_array().is_some() { let (element_type, _) = typ.as_array().unwrap(); - if element_type.is_field() | element_type.as_integer().is_some() { - quote { $hasher_name.add_multiple($name as Field); } - } else if element_type.as_struct().is_some() { - quote { $hasher_name.add_multiple($name.serialize()); } - } else { - assert(false, f"Unsupported type for serialization of argument {name}"); - std::mem::zeroed() - } + let serialized_name = f"{name}_serialized".quoted_contents(); + quote { + let $serialized_name = $name.map(|x: $element_type | x.serialize()); + for i in 0..$name.len() { + args_acc = args_acc.append($serialized_name[i].as_slice()); + } + } } else if typ.as_str().is_some() { quote { $hasher_name.add_multiple($name.to_bytes()); } } else { - assert(false, f"Unsupported type for serialization of argument {name}"); + assert(false, f"Cannot add to hasher: unsupported type {typ} of variable {name}"); std::mem::zeroed() } } + +fn signature_of_type(typ: Type) -> Quoted { + if typ.is_field() { + quote{Field} + } else if typ.as_integer().is_some() { + let (is_signed, bit_size) = typ.as_integer().unwrap(); + if is_signed { + f"i{bit_size}".quoted_contents() + } else { + f"u{bit_size}".quoted_contents() + } + } else if typ.as_struct().is_some() { + let (s, _) = typ.as_struct().unwrap(); + let field_signatures = s.fields().map( + | (_, typ): (Quoted, Type) | { + signature_of_type(typ) + } + ).join(quote {,}); + f"({field_signatures})".quoted_contents() + } else if typ.as_array().is_some() { + let (element_type, array_len) = typ.as_array().unwrap(); + let array_len = array_len.as_constant().unwrap(); + let element_typ_quote = signature_of_type(element_type); + f"[{element_typ_quote};{array_len}]".quoted_contents() + } else if typ.as_str().is_some() { + let str_len_typ = typ.as_str().unwrap(); + let str_len = str_len_typ.as_constant().unwrap(); + f"str<{str_len}>".quoted_contents() + } else if typ.as_tuple().is_some() { + let types = typ.as_tuple().unwrap(); + let field_signatures = types.map( + | typ: Type | { + signature_of_type(typ) + } + ).join(quote {,}); + f"({field_signatures})".quoted_contents() + } else { + assert(false, f"Unsupported type {typ}"); + std::mem::zeroed() + } +} + +trait AsStrQuote { + fn as_str_quote(self) -> Quoted; +} + +impl AsStrQuote for Quoted { + // Used to convert an arbirary quoted type into a quoted string, removing whitespace between tokens + comptime fn as_str_quote(self) -> Quoted { + let tokens = self.tokens(); + let mut acc: [u8] = &[]; + let mut total_len: u32 = 0; + for token in tokens { + let token_as_fmt_str = f"{token}"; + let token_as_str = unquote!(quote {$token_as_fmt_str}); + let token_len = unquote!(quote { $token_as_str.as_bytes().len() }); + let token_as_bytes = unquote!(quote { $token_as_str.as_bytes() }); + total_len+= token_len; + acc = acc.append(token_as_bytes); + } + let result = unquote!( + quote { + let signature_as_array: [u8; $total_len] = $acc.as_array(); + signature_as_array.as_str_unchecked() + } + ); + quote { $result } + } +} + +pub(crate) comptime fn compute_fn_selector(f: FunctionDefinition) -> Field { + let fn_name = f.name(); + let args_signatures = f.parameters().map( + | (_, typ): (Quoted, Type) | { + signature_of_type(typ) + } + ).join(quote {,}); + let signature_quote = quote { $fn_name($args_signatures) }; + let signature_str_quote = signature_quote.as_str_quote(); + + let computation_quote = quote { + protocol_types::abis::function_selector::FunctionSelector::from_signature($signature_str_quote).to_field() + }; + unquote!(computation_quote) +} diff --git a/noir-projects/aztec-nr/aztec/src/prelude.nr b/noir-projects/aztec-nr/aztec/src/prelude.nr index 5b2744d20af..21bac4ea1b4 100644 --- a/noir-projects/aztec-nr/aztec/src/prelude.nr +++ b/noir-projects/aztec-nr/aztec/src/prelude.nr @@ -1,9 +1,9 @@ // docs:start:prelude -use dep::protocol_types::{ +pub use dep::protocol_types::{ address::{AztecAddress, EthAddress}, abis::function_selector::FunctionSelector, point::Point, traits::{Serialize, Deserialize} }; -use crate::{ +pub use crate::{ state_vars::{ map::Map, private_immutable::PrivateImmutable, private_mutable::PrivateMutable, public_immutable::PublicImmutable, public_mutable::PublicMutable, private_set::PrivateSet, diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index ed9506ddb28..4e59489ee13 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -1,9 +1,12 @@ +use dep::aztec::macros::aztec_contract; + +#[aztec_contract] contract Counter { // docs:start:imports use dep::aztec::prelude::{AztecAddress, Map}; use dep::value_note::{balance_utils, value_note::ValueNote}; use dep::easy_private_state::EasyPrivateUint; - use dep::aztec::macros::{functions::{initializer, private}}; + use dep::aztec::macros::{functions::{initializer, private, un_constrained}}; // docs:end:imports // docs:start:storage_struct @@ -35,51 +38,52 @@ contract Counter { // docs:end:increment // docs:start:get_counter + #[un_constrained] unconstrained fn get_counter(owner: AztecAddress) -> pub Field { let counters = storage.counters; balance_utils::get_balance(counters.at(owner).set) } // docs:end:get_counter // docs:start:test_imports - // use dep::aztec::test::{helpers::{cheatcodes, test_environment::TestEnvironment}}; - // use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; - // use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; - // use dep::aztec::note::note_viewer_options::NoteViewerOptions; + use dep::aztec::test::{helpers::{cheatcodes, test_environment::TestEnvironment}}; + use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; + use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; + use dep::aztec::note::note_viewer_options::NoteViewerOptions; // docs:end:test_imports // docs:start:txe_test_increment - // #[test] - // fn test_increment() { - // // Setup env, generate keys - // let mut env = TestEnvironment::new(); - // let owner = env.create_account(); - // let outgoing_viewer = env.create_account(); - // let initial_value: Field = 5; - // env.impersonate(owner); - // // Deploy contract and initialize - // let initializer = Counter::interface().initialize(initial_value as u64, owner, outgoing_viewer); - // let counter_contract = env.deploy_self("Counter").with_private_initializer(initializer); - // let contract_address = counter_contract.to_address(); - // // docs:start:txe_test_read_notes - // // Read the stored value in the note - // env.impersonate(contract_address); - // let counter_slot = Counter::storage().counters.slot; - // let owner_slot = derive_storage_slot_in_map(counter_slot, owner); - // let mut options = NoteViewerOptions::new(); - // let notes: BoundedVec = view_notes(owner_slot, options); - // let initial_note_value = notes.get(0).value; - // assert( - // initial_note_value == initial_value, f"Expected {initial_value} but got {initial_note_value}" - // ); - // // docs:end:txe_test_read_notes - // // Increment the counter - // let increment_call_interface = Counter::at(contract_address).increment(owner, outgoing_viewer); - // env.call_private_void(increment_call_interface); - // // get_counter is an unconstrained function, so we call it directly (we're in the same module) - // let current_value_for_owner = get_counter(owner); - // let expected_current_value = initial_value + 1; - // assert( - // expected_current_value == current_value_for_owner, f"Expected {expected_current_value} but got {current_value_for_owner}" - // ); - // } + #[test] + fn test_increment() { + // Setup env, generate keys + let mut env = TestEnvironment::new(); + let owner = env.create_account(); + let outgoing_viewer = env.create_account(); + let initial_value: Field = 5; + env.impersonate(owner); + // Deploy contract and initialize + let initializer = Counter::interface().initialize(initial_value as u64, owner, outgoing_viewer); + let counter_contract = env.deploy_self("Counter").with_private_initializer(initializer); + let contract_address = counter_contract.to_address(); + // docs:start:txe_test_read_notes + // Read the stored value in the note + env.impersonate(contract_address); + let counter_slot = Counter::storage().counters.slot; + let owner_slot = derive_storage_slot_in_map(counter_slot, owner); + let mut options = NoteViewerOptions::new(); + let notes: BoundedVec = view_notes(owner_slot, options); + let initial_note_value = notes.get(0).value; + assert( + initial_note_value == initial_value, f"Expected {initial_value} but got {initial_note_value}" + ); + // docs:end:txe_test_read_notes + // Increment the counter + let increment_call_interface = Counter::at(contract_address).increment(owner, outgoing_viewer); + env.call_private_void(increment_call_interface); + // get_counter is an unconstrained function, so we call it directly (we're in the same module) + let current_value_for_owner = get_counter(owner); + let expected_current_value = initial_value + 1; + assert( + expected_current_value == current_value_for_owner, f"Expected {expected_current_value} but got {current_value_for_owner}" + ); + } // docs:end:txe_test_increment } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/mod.nr index 636a6b26578..f2e9aa5b6f9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/mod.nr @@ -4,11 +4,11 @@ mod partial_address; mod public_keys_hash; mod salted_initialization_hash; -use crate::address::aztec_address::AztecAddress; -use crate::address::eth_address::EthAddress; -use crate::address::partial_address::PartialAddress; -use crate::address::public_keys_hash::PublicKeysHash; -use crate::address::salted_initialization_hash::SaltedInitializationHash; +pub use crate::address::aztec_address::AztecAddress; +pub use crate::address::eth_address::EthAddress; +pub use crate::address::partial_address::PartialAddress; +pub use crate::address::public_keys_hash::PublicKeysHash; +pub use crate::address::salted_initialization_hash::SaltedInitializationHash; use crate::{constants::GENERATOR_INDEX__CONSTRUCTOR, hash::poseidon2_hash_with_separator}; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr index 7e36c845512..c01c9d119ca 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr @@ -3,8 +3,8 @@ mod address; mod debug_log; mod point; mod scalar; -// This is intentionally spelled like this -// since contract is a reserved keyword, so it cannot +// This is intentionally spelled like this +// since contract is a reserved keyword, so it cannot // be used as an ident. mod contrakt; mod transaction; @@ -35,3 +35,4 @@ mod recursion; mod data; mod storage; mod validate; +mod meta; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr new file mode 100644 index 00000000000..94da2cfa3f9 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -0,0 +1,105 @@ +use super::traits::Serialize; + +pub(crate) fn flatten_to_fields(name: Quoted, typ: Type) -> ([Quoted], [Quoted]) { + let mut fields = &[]; + let mut aux_vars = &[]; + if typ.is_field() | typ.as_integer().is_some() { + fields = fields.push_back(quote { $name as Field }); + } else if typ.as_struct().is_some() { + let nested_struct = typ.as_struct().unwrap(); + let params = nested_struct.0.fields(); + let struct_flattened = params.map( + | (param_name, param_type): (Quoted, Type) | flatten_to_fields(quote {$name.$param_name}, param_type) + ); + let struct_flattened_fields = struct_flattened.fold( + &[], + | acc: [Quoted], (fields, _): (_, [Quoted]) | acc.append(fields) + ); + let struct_flattened_aux_vars = struct_flattened.fold( + &[], + |acc: [Quoted], (_, aux_vars): ([Quoted], _) | acc.append(aux_vars) + ); + fields = fields.append(struct_flattened_fields); + aux_vars = aux_vars.append(struct_flattened_aux_vars); + } else if typ.as_array().is_some() { + let (element_type, array_len) = typ.as_array().unwrap(); + let array_len = array_len.as_constant().unwrap(); + for i in 0..array_len { + let (element_fields, element_aux_vars) = flatten_to_fields(quote { $name[$i] }, element_type); + fields = fields.append(element_fields); + aux_vars = aux_vars.append(element_aux_vars); + } + } else if typ.as_str().is_some() { + let length_type = typ.as_str().unwrap(); + let str_len = length_type.as_constant().unwrap(); + let var_name = name.as_expr().unwrap().as_member_access().unwrap().1; + let as_bytes_name = f"{var_name}_as_bytes".quoted_contents(); + let as_bytes = quote { let $as_bytes_name = $name.as_bytes() }; + for i in 0..str_len { + fields = fields.push_back(quote { $as_bytes_name[$i] as Field } ); + } + aux_vars = aux_vars.push_back(as_bytes); + } else { + assert(false, f"Unsupported type for serialization of argument {name} and type {typ}"); + std::mem::zeroed() + } + (fields, aux_vars) +} + +pub(crate) comptime fn derive_serialize(s: StructDefinition) -> Quoted { + let typ = s.as_type(); + let (fields, aux_vars) = flatten_to_fields(quote { self }, typ); + let aux_vars_quote = if aux_vars.len() > 0 { + let joint = aux_vars.join(quote {;}); + quote { $joint; } + } else { + quote {} + }; + + let field_serializations = fields.join(quote {,}); + let serialized_len = fields.len(); + quote { + impl Serialize<$serialized_len> for $typ { + fn serialize(self) -> [Field; $serialized_len] { + $aux_vars_quote + [ $field_serializations ] + } + } + } +} + +#[derive(Serialize)] +struct Smol { + a: Field, + b: Field, +} + +#[derive(Serialize)] +struct Fancier { + a: Smol, + b: [Field; 2], + c: [u8; 3], + d: str<16>, +} + +fn main() { + assert(false); +} + +#[test] +fn smol_test() { + let smol = Smol { a: 1, b: 2 }; + let serialized = smol.serialize(); + assert(serialized == [1, 2], serialized); +} + +#[test] +fn fancier_test() { + let fancier = Fancier { a: Smol { a: 1, b: 2 }, b: [0, 1], c: [1, 2, 3], d: "metaprogramming!" }; + let serialized = fancier.serialize(); + assert( + serialized == [ + 1, 2, 0, 1, 1, 2, 3, 0x6d, 0x65, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x21 + ], serialized + ); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr index 8083402384a..fe54c0e750b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr @@ -1,5 +1,5 @@ use crate::utils::field::field_from_bytes; -use std::meta::quoted; +use crate::meta::derive_serialize; // Trait: is_empty // @@ -85,6 +85,7 @@ impl FromField for U128 { } // docs:start:serialize +#[derive_via(derive_serialize)] trait Serialize { fn serialize(self) -> [Field; N]; } @@ -95,14 +96,15 @@ impl Serialize for [Field; N] { self } } + impl Serialize for str { fn serialize(self) -> [Field; N] { - let mut result = [0; N]; - let bytes: [u8; N] = self.as_bytes(); - for i in 0..N { - result[i] = field_from_bytes([bytes[i];1], true); + let bytes = self.as_bytes(); + let mut fields = [0; N]; + for i in 0..bytes.len() { + fields[i] = bytes[i] as Field; } - result + fields } } From 53f0e8f59d66ae730e0bf42f299a28c09bd574fa Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 6 Sep 2024 14:40:17 +0000 Subject: [PATCH 03/79] almost finished storage --- .../aztec-nr/aztec/src/macros/mod.nr | 10 ++ .../aztec-nr/aztec/src/macros/storage/mod.nr | 91 +++++++++++++++++++ .../aztec-nr/easy-private-state/src/lib.nr | 2 +- .../contracts/counter_contract/src/main.nr | 10 +- .../docs_example_contract/src/main.nr | 14 +-- 5 files changed, 114 insertions(+), 13 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 48ae92550b1..caf9af342e1 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -4,6 +4,7 @@ mod note; mod storage; use functions::STUBS; +use storage::STORAGE_LAYOUT_NAME; pub comptime fn generate_contract_interface(m: Module) -> Quoted { let module_name = m.name(); @@ -26,6 +27,10 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { pub fn interface() -> Self { Self { target_contract: aztec::protocol_types::address::AztecAddress::zero() } } + + pub fn storage_layout() -> StorageLayout { + $STORAGE_LAYOUT_NAME + } } #[contract_library_method] @@ -39,6 +44,11 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { pub fn interface() -> $module_name { $module_name { target_contract: aztec::protocol_types::address::AztecAddress::zero() } } + + #[contract_library_method] + pub fn storage_layout() -> StorageLayout { + $STORAGE_LAYOUT_NAME + } } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index e69de29bb2d..dbaa418cf50 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -0,0 +1,91 @@ +use std::meta::typ::fresh_type_variable; + +comptime mut global STORAGE_LAYOUT_NAME: Quoted = quote {}; + +comptime fn any_map() -> Type { + let context = fresh_type_variable(); + let key = fresh_type_variable(); + let value = fresh_type_variable(); + quote { crate::storageMap<$context, $key, $value> }.as_type() +} + +pub fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map: bool) -> (Quoted, u32) { + assert( + typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container`, or Map" + ); + let (_, generics) = typ.as_struct().unwrap(); + let maybe_map = if generics.len() == 3 { + let maybe_context = generics[0]; + let maybe_key = generics[1]; + let maybe_value = generics[2]; + quote { crate::state_vars::map::Map<$maybe_context, $maybe_key, $maybe_value> }.as_type() + } else { + quote {()}.as_type() + }; + + if typ == maybe_map { + let (value_constructor, _) = generate_storage_field_constructor(generics[1], quote { slot }, true); + + let serialized_size = 1; + ( + quote { $typ::new(context, $slot, | context, slot | { $value_constructor }) }, serialized_size + ) + } else { + let (container_struct, _) = typ.as_struct().unwrap(); + let serialized_size = if parent_is_map | container_struct.has_named_attribute(quote { note }) { + 1 + } else { + assert( + container_struct.generics().len() != 2, "Storable containers must be generic over a serializable type and Context" + ); + let stored_struct = container_struct.generics()[0]; + assert(stored_struct.as_struct().is_some(), "Storable items must be Serializable structs"); + let any = fresh_type_variable(); + let maybe_serialize_impl = stored_struct.get_trait_impl(quote { Serialize<$any> }.as_trait_constraint()); + assert(maybe_serialize_impl.is_some(), "Storable items must implement Serialize"); + let serialize_impl = maybe_serialize_impl.unwrap(); + serialize_impl.trait_generic_args()[0].as_constant().unwrap() + }; + (quote { $typ::new(context, $slot)}, serialized_size) + } +} + +pub comptime fn storage(s: StructDefinition) -> Quoted { + let mut slot: u32 = 1; + let mut storage_vars_constructors = &[]; + let mut storage_layout_fields = &[]; + let mut storage_layout_constructors = &[]; + for field in s.fields() { + let (name, typ) = field; + let (storage_field_constructor, serialized_size) = generate_storage_field_constructor(typ, quote { $slot }, false); + storage_vars_constructors = storage_vars_constructors.push_back(quote { $name: $storage_field_constructor }); + storage_layout_fields = storage_layout_fields.push_back(quote { $name: dep::aztec::prelude::Storable }); + storage_layout_constructors = storage_layout_constructors.push_back(quote { $name: dep::aztec::prelude::Storable { slot: $slot } }); + slot += serialized_size; + } + + let storage_vars_constructors = storage_vars_constructors.join(quote {,}); + let storage_layout_fields = storage_layout_fields.join(quote {,}); + let storage_layout_constructors = storage_layout_constructors.join(quote {,}); + + STORAGE_LAYOUT_NAME = quote { STORAGE_LAYOUT }; + + quote { + impl Storage { + fn init(context: Context) -> Self { + Self { + $storage_vars_constructors + } + } + } + + struct StorageLayout { + $storage_layout_fields + } + + #[abi(storage)] + global $STORAGE_LAYOUT_NAME = StorageLayout { + $storage_layout_constructors + }; + } +} diff --git a/noir-projects/aztec-nr/easy-private-state/src/lib.nr b/noir-projects/aztec-nr/easy-private-state/src/lib.nr index ad5150bfbb0..4e9a4b0b741 100644 --- a/noir-projects/aztec-nr/easy-private-state/src/lib.nr +++ b/noir-projects/aztec-nr/easy-private-state/src/lib.nr @@ -1,3 +1,3 @@ mod easy_private_uint; -use crate::easy_private_uint::EasyPrivateUint; +pub use crate::easy_private_uint::EasyPrivateUint; diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 4e59489ee13..eba0a281c1b 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -6,13 +6,13 @@ contract Counter { use dep::aztec::prelude::{AztecAddress, Map}; use dep::value_note::{balance_utils, value_note::ValueNote}; use dep::easy_private_state::EasyPrivateUint; - use dep::aztec::macros::{functions::{initializer, private, un_constrained}}; + use dep::aztec::macros::{storage::storage, functions::{initializer, private, un_constrained}}; // docs:end:imports // docs:start:storage_struct - #[aztec(storage)] - struct Storage { - counters: Map, + #[storage] + struct Storage { + counters: Map, Context>, } // docs:end:storage_struct @@ -66,7 +66,7 @@ contract Counter { // docs:start:txe_test_read_notes // Read the stored value in the note env.impersonate(contract_address); - let counter_slot = Counter::storage().counters.slot; + let counter_slot = Counter::storage_layout().counters.slot; let owner_slot = derive_storage_slot_in_map(counter_slot, owner); let mut options = NoteViewerOptions::new(); let notes: BoundedVec = view_notes(owner_slot, options); diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index 1bb4a1c5397..715e79c5762 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -6,7 +6,7 @@ mod types; // (tests ordering in the circuit) // you have a card (PrivateMutable). Anyone can create a bigger card. Whoever is bigger will be the leader. -// it also has dummy methods and other examples used for documentation e.g. +// it also has dummy methods and other examples used for documentation e.g. // how to create custom notes, a custom struct for public state, a custom note that may be unencrypted // also has `options.nr` which shows various ways of using `NoteGetterOptions` to query notes // it also shows what our macros do behind the scenes! @@ -33,7 +33,7 @@ contract DocsExample { // docs:start:storage-private-mutable-declaration legendary_card: PrivateMutable, // docs:end:storage-private-mutable-declaration - // just used for docs example to show how to create a private mutable map. + // just used for docs example to show how to create a private mutable map. profiles: Map>, // docs:start:storage-set-declaration set: PrivateSet, @@ -112,7 +112,7 @@ contract DocsExample { fn get_shared_immutable_constrained_private_indirect() -> pub Leader { // This is a private function that calls another private function // and returns the response. - // Used to test that we can retrieve values through calls and + // Used to test that we can retrieve values through calls and // correctly return them in the simulation let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_private().view(&mut context); leader.points += 1; @@ -123,7 +123,7 @@ contract DocsExample { fn get_shared_immutable_constrained_public_indirect() -> pub Leader { // This is a public function that calls another public function // and returns the response. - // Used to test that we can retrieve values through calls and + // Used to test that we can retrieve values through calls and // correctly return them in the simulation let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_public().view(&mut context); leader.points += 1; @@ -327,13 +327,13 @@ contract DocsExample { // Our original inputs! a: Field, - b: Field // The actual return type of our circuit is the PrivateCircuitPublicInputs struct, this will be the - // input to our kernel! + b: Field // The actual return type of our circuit is the PrivateCircuitPublicInputs struct, this will be the + // input to our kernel! // docs:start:context-example-return ) -> pub PrivateCircuitPublicInputs { // docs:end:context-example-return // ************************************************************ - // The hasher is a structure used to generate a hash of the circuits inputs. + // The hasher is a structure used to generate a hash of the circuits inputs. // docs:start:context-example-hasher let mut args_hasher = dep::aztec::hash::ArgsHasher::new(); args_hasher.add(a); From e5a9ca19f57a6c9282d5ca712b1ec90f7eaef27b Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 6 Sep 2024 17:25:40 +0000 Subject: [PATCH 04/79] more things working --- .../aztec/src/macros/functions/mod.nr | 10 ++++++-- .../aztec-nr/aztec/src/macros/mod.nr | 6 ++++- .../aztec-nr/aztec/src/macros/storage/mod.nr | 25 ++++++------------- .../aztec-nr/aztec/src/macros/utils.nr | 10 +++++++- .../contracts/counter_contract/src/main.nr | 5 ++-- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 831cd1d0ce3..e4d49d4cd2f 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -79,6 +79,8 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { let fn_stub = stub_fn(f); STUBS = STUBS.push_back(fn_stub); + let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| f.has_named_attribute(quote { initializer })); + let current_params = f.parameters(); f.set_parameters( &[ @@ -104,7 +106,11 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { ); let context_creation_quote = quote { let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); }; let storage_init_quote = quote { let storage = Storage::init(&mut context); }; - let init_check = create_init_check(f); + let init_check = if module_has_initializer & !f.has_named_attribute(quote { no_init_check }) { + create_init_check(f) + } else { + quote {} + } let return_value_type = f.return_type(); @@ -152,7 +158,7 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { fn_abi } -pub fn un_constrained(f: FunctionDefinition) { +pub fn transform_unconstrained(f: FunctionDefinition) { let context_creation_quote = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); }; let storage_init_quote = quote { let storage = Storage::init(context); }; let to_prepend = quote { diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index caf9af342e1..4a46364b8a2 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -5,6 +5,7 @@ mod storage; use functions::STUBS; use storage::STORAGE_LAYOUT_NAME; +use functions::transform_unconstrained; pub comptime fn generate_contract_interface(m: Module) -> Quoted { let module_name = m.name(); @@ -54,6 +55,9 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { pub comptime fn aztec_contract(m: Module) -> Quoted { let interface = generate_contract_interface(m); - + let functions = m.functions(); + for f in functions.filter(| f | f.) { + transform_unconstrained(f); + } interface } diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index dbaa418cf50..56ca389dd9d 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -1,19 +1,12 @@ -use std::meta::typ::fresh_type_variable; +use super::utils::get_serialized_size; comptime mut global STORAGE_LAYOUT_NAME: Quoted = quote {}; -comptime fn any_map() -> Type { - let context = fresh_type_variable(); - let key = fresh_type_variable(); - let value = fresh_type_variable(); - quote { crate::storageMap<$context, $key, $value> }.as_type() -} - pub fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map: bool) -> (Quoted, u32) { assert( typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container`, or Map" ); - let (_, generics) = typ.as_struct().unwrap(); + let (container_struct, generics) = typ.as_struct().unwrap(); let maybe_map = if generics.len() == 3 { let maybe_context = generics[0]; let maybe_key = generics[1]; @@ -23,12 +16,12 @@ pub fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map quote {()}.as_type() }; + let struct_name_quote = container_struct.name(); + if typ == maybe_map { let (value_constructor, _) = generate_storage_field_constructor(generics[1], quote { slot }, true); - - let serialized_size = 1; ( - quote { $typ::new(context, $slot, | context, slot | { $value_constructor }) }, serialized_size + quote { $struct_name_quote::new(context, $slot, | context, slot | { $value_constructor }) }, 1 ) } else { let (container_struct, _) = typ.as_struct().unwrap(); @@ -40,13 +33,9 @@ pub fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map ); let stored_struct = container_struct.generics()[0]; assert(stored_struct.as_struct().is_some(), "Storable items must be Serializable structs"); - let any = fresh_type_variable(); - let maybe_serialize_impl = stored_struct.get_trait_impl(quote { Serialize<$any> }.as_trait_constraint()); - assert(maybe_serialize_impl.is_some(), "Storable items must implement Serialize"); - let serialize_impl = maybe_serialize_impl.unwrap(); - serialize_impl.trait_generic_args()[0].as_constant().unwrap() + get_serialized_size(stored_struct) }; - (quote { $typ::new(context, $slot)}, serialized_size) + (quote { $struct_name_quote::new(context, $slot)}, serialized_size) } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 32384eb37ed..97d2c560039 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -1,4 +1,4 @@ -use std::meta::unquote; +use std::meta::{typ::fresh_type_variable, unquote}; pub(crate) fn get_fn_visibility(f: FunctionDefinition) -> Quoted { if f.has_named_attribute(quote { private }) { @@ -181,3 +181,11 @@ pub(crate) comptime fn compute_fn_selector(f: FunctionDefinition) -> Field { }; unquote!(computation_quote) } + +pub(crate) comptime fn get_serialized_size(typ: Type) -> u32 { + let any = fresh_type_variable(); + let maybe_serialize_impl = typ.get_trait_impl(quote { Serialize<$any> }.as_trait_constraint()); + assert(maybe_serialize_impl.is_some(), "Storable items must implement Serialize"); + let serialize_impl = maybe_serialize_impl.unwrap(); + serialize_impl.trait_generic_args()[0].as_constant().unwrap() +} diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index eba0a281c1b..b13e8a8191b 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -38,21 +38,20 @@ contract Counter { // docs:end:increment // docs:start:get_counter - #[un_constrained] unconstrained fn get_counter(owner: AztecAddress) -> pub Field { let counters = storage.counters; balance_utils::get_balance(counters.at(owner).set) } // docs:end:get_counter // docs:start:test_imports - use dep::aztec::test::{helpers::{cheatcodes, test_environment::TestEnvironment}}; + use dep::aztec::test::{helpers::{test_environment::TestEnvironment}}; use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; use dep::aztec::note::note_viewer_options::NoteViewerOptions; // docs:end:test_imports // docs:start:txe_test_increment #[test] - fn test_increment() { + unconstrained fn test_increment() { // Setup env, generate keys let mut env = TestEnvironment::new(); let owner = env.create_account(); From f7d11eb2ef3360682562be4875bd62282853d8ea Mon Sep 17 00:00:00 2001 From: thunkar Date: Thu, 12 Sep 2024 06:17:16 +0000 Subject: [PATCH 05/79] align with noir --- .../aztec/src/macros/functions/mod.nr | 8 ++-- .../aztec-nr/aztec/src/macros/mod.nr | 6 +-- .../aztec-nr/aztec/src/macros/storage/mod.nr | 40 ++++++++++++++----- .../aztec-nr/aztec/src/macros/utils.nr | 20 +++++----- .../contracts/counter_contract/src/main.nr | 3 +- .../crates/types/src/meta/mod.nr | 2 +- .../crates/types/src/utils/arrays/sort_by.nr | 24 ++++++++++- 7 files changed, 72 insertions(+), 31 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index e4d49d4cd2f..362c0b4dd5b 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -31,12 +31,12 @@ pub comptime fn initializer(f: FunctionDefinition) { modify_fn_body(f, to_prepend, quote {}); } -fn create_init_check(f: FunctionDefinition) -> Quoted { +comptime fn create_init_check(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); f"dep::aztec::initializer::assert_is_initialized_{fn_visibility}(&mut context);".quoted_contents() } -fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { +comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { let name = f.name(); // Remove first arg (inputs) let mut parameters = f.parameters().pop_front().1.map( @@ -110,7 +110,7 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { create_init_check(f) } else { quote {} - } + }; let return_value_type = f.return_type(); @@ -158,7 +158,7 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { fn_abi } -pub fn transform_unconstrained(f: FunctionDefinition) { +pub comptime fn transform_unconstrained(f: FunctionDefinition) { let context_creation_quote = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); }; let storage_init_quote = quote { let storage = Storage::init(context); }; let to_prepend = quote { diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 4a46364b8a2..a1f37023745 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -56,8 +56,8 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { pub comptime fn aztec_contract(m: Module) -> Quoted { let interface = generate_contract_interface(m); let functions = m.functions(); - for f in functions.filter(| f | f.) { - transform_unconstrained(f); - } + // for f in functions.filter(| f | f.) { + // transform_unconstrained(f); + // } interface } diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index 56ca389dd9d..492c72adcc2 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -2,23 +2,31 @@ use super::utils::get_serialized_size; comptime mut global STORAGE_LAYOUT_NAME: Quoted = quote {}; -pub fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map: bool) -> (Quoted, u32) { +pub comptime fn is_storage_map(typ: Type) -> bool { + if typ.as_struct().is_some() { + let (_, generics) = typ.as_struct().unwrap(); + let maybe_map = if generics.len() == 3 { + let maybe_key = generics[0]; + let maybe_value = generics[1]; + let maybe_context = generics[2]; + quote { crate::state_vars::map::Map<$maybe_key, $maybe_value, $maybe_context> }.as_type() + } else { + quote {()}.as_type() + }; + typ == maybe_map + } else { + false + } +} + +pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map: bool) -> (Quoted, u32) { assert( typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container`, or Map" ); let (container_struct, generics) = typ.as_struct().unwrap(); - let maybe_map = if generics.len() == 3 { - let maybe_context = generics[0]; - let maybe_key = generics[1]; - let maybe_value = generics[2]; - quote { crate::state_vars::map::Map<$maybe_context, $maybe_key, $maybe_value> }.as_type() - } else { - quote {()}.as_type() - }; - let struct_name_quote = container_struct.name(); - if typ == maybe_map { + if is_storage_map(typ) { let (value_constructor, _) = generate_storage_field_constructor(generics[1], quote { slot }, true); ( quote { $struct_name_quote::new(context, $slot, | context, slot | { $value_constructor }) }, 1 @@ -39,17 +47,27 @@ pub fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map } } +// comptime fn add_context_generic(typ: Type) -> Type { +// let generics = typ.generics(); +// let context_generic = quote { Context }; +// let generics = generics.push_back(context_generic); +// quote { $typ<$generics> }.as_type() +// } + pub comptime fn storage(s: StructDefinition) -> Quoted { let mut slot: u32 = 1; let mut storage_vars_constructors = &[]; let mut storage_layout_fields = &[]; let mut storage_layout_constructors = &[]; + let mut new_storage_fields = &[]; + //let context_generic = s.add_generic("Context"); for field in s.fields() { let (name, typ) = field; let (storage_field_constructor, serialized_size) = generate_storage_field_constructor(typ, quote { $slot }, false); storage_vars_constructors = storage_vars_constructors.push_back(quote { $name: $storage_field_constructor }); storage_layout_fields = storage_layout_fields.push_back(quote { $name: dep::aztec::prelude::Storable }); storage_layout_constructors = storage_layout_constructors.push_back(quote { $name: dep::aztec::prelude::Storable { slot: $slot } }); + //new_storage_fields = new_storage_fields.push_back((name, quote )); slot += serialized_size; } diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 97d2c560039..8ff99522aed 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -1,6 +1,6 @@ use std::meta::{typ::fresh_type_variable, unquote}; -pub(crate) fn get_fn_visibility(f: FunctionDefinition) -> Quoted { +pub(crate) comptime fn get_fn_visibility(f: FunctionDefinition) -> Quoted { if f.has_named_attribute(quote { private }) { quote { private } } else { @@ -8,19 +8,19 @@ pub(crate) fn get_fn_visibility(f: FunctionDefinition) -> Quoted { } } -pub(crate) fn is_fn_private(f: FunctionDefinition) -> bool { +pub(crate) comptime fn is_fn_private(f: FunctionDefinition) -> bool { f.has_named_attribute(quote { private }) } -pub(crate) fn is_fn_public(f: FunctionDefinition) -> bool { +pub(crate) comptime fn is_fn_public(f: FunctionDefinition) -> bool { f.has_named_attribute(quote { public }) } -pub(crate) fn is_fn_view(f: FunctionDefinition) -> bool { +pub(crate) comptime fn is_fn_view(f: FunctionDefinition) -> bool { f.has_named_attribute(quote { view }) } -pub(crate) fn fn_body_as_quoted(f: FunctionDefinition) -> Quoted { +pub(crate) comptime fn fn_body_as_quoted(f: FunctionDefinition) -> Quoted { let body = f.body().as_block(); assert(body.is_some(), "Function body must be a block"); body.unwrap().fold( @@ -35,7 +35,7 @@ pub(crate) fn fn_body_as_quoted(f: FunctionDefinition) -> Quoted { ) } -pub(crate) fn modify_fn_body(f: FunctionDefinition, prepend: Quoted, append: Quoted) { +pub(crate) comptime fn modify_fn_body(f: FunctionDefinition, prepend: Quoted, append: Quoted) { let mut body_quote = fn_body_as_quoted(f); body_quote = quote { { @@ -49,7 +49,7 @@ pub(crate) fn modify_fn_body(f: FunctionDefinition, prepend: Quoted, append: Quo f.set_body(body_expr.unwrap()); } -pub(crate) fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: Type) -> Quoted { +pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: Type) -> Quoted { if typ.is_field() | typ.as_integer().is_some() { quote { $slice_name = $slice_name.push_back($name as Field); } } else if typ.as_struct().is_some() { @@ -73,7 +73,7 @@ pub(crate) fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: Type) -> } } -pub(crate) fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted { +pub(crate) comptime fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted { if typ.is_field() | typ.as_integer().is_some() { quote { $hasher_name.add($name as Field); } } else if typ.as_struct().is_some() { @@ -97,7 +97,7 @@ pub(crate) fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quo } } -fn signature_of_type(typ: Type) -> Quoted { +comptime fn signature_of_type(typ: Type) -> Quoted { if typ.is_field() { quote{Field} } else if typ.as_integer().is_some() { @@ -139,7 +139,7 @@ fn signature_of_type(typ: Type) -> Quoted { } trait AsStrQuote { - fn as_str_quote(self) -> Quoted; + fn as_str_quote(self) -> Self; } impl AsStrQuote for Quoted { diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index b13e8a8191b..5a4ad6b9daa 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -6,7 +6,7 @@ contract Counter { use dep::aztec::prelude::{AztecAddress, Map}; use dep::value_note::{balance_utils, value_note::ValueNote}; use dep::easy_private_state::EasyPrivateUint; - use dep::aztec::macros::{storage::storage, functions::{initializer, private, un_constrained}}; + use dep::aztec::macros::{storage::storage, functions::{initializer, private, transform_unconstrained}}; // docs:end:imports // docs:start:storage_struct @@ -38,6 +38,7 @@ contract Counter { // docs:end:increment // docs:start:get_counter + #[transform_unconstrained] unconstrained fn get_counter(owner: AztecAddress) -> pub Field { let counters = storage.counters; balance_utils::get_balance(counters.at(owner).set) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 94da2cfa3f9..7b08330c36f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -1,6 +1,6 @@ use super::traits::Serialize; -pub(crate) fn flatten_to_fields(name: Quoted, typ: Type) -> ([Quoted], [Quoted]) { +pub(crate) comptime fn flatten_to_fields(name: Quoted, typ: Type) -> ([Quoted], [Quoted]) { let mut fields = &[]; let mut aux_vars = &[]; if typ.is_field() | typ.as_integer().is_some() { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/sort_by.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/sort_by.nr index 0b6e155be74..8a12b76558e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/sort_by.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/sort_by.nr @@ -1,12 +1,34 @@ use crate::utils::arrays::find_index_hint; +/// Returns the index of the elements in the array that would sort it, using the provided custom sorting function. +unconstrained fn get_sorting_index(some_array: [T; N], ordering: fn[Env](T, T) -> bool) -> [u32; N] { + let mut result = [0; N]; + let mut a = some_array; + for i in 0..N { + result[i] = i; + } + for i in 1..N { + for j in 0..i { + if ordering(a[i], a[j]) { + let old_a_j = a[j]; + a[j] = a[i]; + a[i] = old_a_j; + let old_j = result[j]; + result[j] = result[i]; + result[i] = old_j; + } + } + } + result +} + // Copied from the stdlib Array.sort_via. // But this one doesn't use `ordering` to check that the array is sorted. // This is to allow preserving the order of equal values. unconstrained pub fn sort_by(array: [T; N], ordering: fn[Env](T, T) -> bool) -> [T; N] { let mut result = array; let sorted_index = unsafe { - array.get_sorting_index(ordering) + get_sorting_index(array, ordering) }; // Ensure the indexes are correct for i in 0..N { From 687fd85fc64823ac3ca46f997610158f5b1ef1bf Mon Sep 17 00:00:00 2001 From: thunkar Date: Thu, 12 Sep 2024 15:17:39 +0000 Subject: [PATCH 06/79] more stuff --- .../aztec/src/macros/functions/mod.nr | 237 ++++++++++++------ .../aztec-nr/aztec/src/macros/mod.nr | 92 ++++++- .../aztec-nr/aztec/src/macros/note/mod.nr | 9 - .../aztec-nr/aztec/src/macros/notes/mod.nr | 26 ++ .../aztec-nr/aztec/src/macros/storage/mod.nr | 41 ++- .../aztec-nr/value-note/src/value_note.nr | 6 +- .../contracts/counter_contract/src/main.nr | 9 +- .../contracts/router_contract/src/main.nr | 21 +- 8 files changed, 316 insertions(+), 125 deletions(-) delete mode 100644 noir-projects/aztec-nr/aztec/src/macros/note/mod.nr create mode 100644 noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 362c0b4dd5b..565ef8530de 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -1,34 +1,42 @@ use std::meta::{unquote, type_of}; use super::utils::{ - modify_fn_body, is_fn_private, get_fn_visibility, add_to_hasher, is_fn_view, compute_fn_selector, - add_to_field_slice + modify_fn_body, is_fn_private, get_fn_visibility, is_fn_view, compute_fn_selector, + add_to_field_slice, add_to_hasher }; +use super::storage::STORAGE_LAYOUT_NAME; +use super::utils::is_fn_public; comptime mut global STUBS: [Quoted] = &[]; -pub comptime fn internal(f: FunctionDefinition) { +// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] +pub comptime fn internal(_f: FunctionDefinition) {} + +comptime fn create_internal_check(f: FunctionDefinition) -> Quoted { let name = f.name(); let assertion_message = f"Function {name} can only be called internally"; - let internal_check = quote { assert(context.msg_sender() == context.this_address(), $assertion_message); }; - modify_fn_body(f, internal_check, quote {}); + quote { assert(context.msg_sender() == context.this_address(), $assertion_message); } } -pub comptime fn view(f: FunctionDefinition) { +// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] +pub comptime fn view(_f: FunctionDefinition) {} + +comptime fn create_view_check(f: FunctionDefinition) -> Quoted { let name = f.name(); let assertion_message = f"Function {name} can only be called statically"; - let static_check = if is_fn_private(f) { + if is_fn_private(f) { quote { assert(context.inputs.call_context.is_static_call == true, $assertion_message); } } else { quote { assert(context.inputs.is_static_call == true, $assertion_message); } - }; - modify_fn_body(f, static_check, quote {}); + } } -pub comptime fn initializer(f: FunctionDefinition) { +// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] +pub comptime fn initializer(_f: FunctionDefinition) {} + +comptime fn create_assert_initializer(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); - let to_prepend = f"dep::aztec::initializer::assert_initialization_matches_address_preimage_{fn_visibility}(context);".quoted_contents(); - modify_fn_body(f, to_prepend, quote {}); + f"dep::aztec::initializer::assert_initialization_matches_address_preimage_{fn_visibility}(context);".quoted_contents() } comptime fn create_init_check(f: FunctionDefinition) -> Quoted { @@ -36,6 +44,11 @@ comptime fn create_init_check(f: FunctionDefinition) -> Quoted { f"dep::aztec::initializer::assert_is_initialized_{fn_visibility}(&mut context);".quoted_contents() } +comptime fn create_mark_as_initialized(f: FunctionDefinition) -> Quoted { + let fn_visibility = get_fn_visibility(f); + f"dep::aztec::initializer::mark_as_initialized_{fn_visibility}(&mut context);".quoted_contents() +} + comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { let name = f.name(); // Remove first arg (inputs) @@ -53,7 +66,7 @@ comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { }; let return_value_type = f.return_type(); - let return_type_quote = if !return_value_type.eq(type_of(())) { + let return_type = if return_value_type != type_of(()) { quote { return_type: $return_value_type } } else { quote {} @@ -68,7 +81,7 @@ comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { #[abi(functions)] struct $abi_struct_name { parameters: $parameters_struct_name, - $return_type_quote + $return_type } }; result @@ -80,6 +93,7 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { STUBS = STUBS.push_back(fn_stub); let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| f.has_named_attribute(quote { initializer })); + let module_has_storage = STORAGE_LAYOUT_NAME != quote { }; let current_params = f.parameters(); f.set_parameters( @@ -90,22 +104,41 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { ].append(current_params) ); let mut body = f.body().as_block().unwrap(); - let args_hasher_name_quote = quote { args_hasher }; - let args_hasher_quote = current_params.fold( + let args_hasher_name = quote { args_hasher }; + let args_hasher = current_params.fold( quote { - let mut $args_hasher_name_quote = dep::aztec::hash::ArgsHasher::new(); + let mut $args_hasher_name = dep::aztec::hash::ArgsHasher::new(); }, - |args_hasher_quote, param: (Quoted, Type)| { + |args_hasher, param: (Quoted, Type)| { let (name, typ) = param; - let appended_arg_quote = add_to_hasher(args_hasher_name_quote, name, typ); + let appended_arg = add_to_hasher(args_hasher_name, name, typ); quote { - $args_hasher_quote - $appended_arg_quote + $args_hasher + $appended_arg } } ); - let context_creation_quote = quote { let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); }; - let storage_init_quote = quote { let storage = Storage::init(&mut context); }; + let context_creation = quote { let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); }; + let internal_check = if f.has_named_attribute(quote { internal }) { + create_internal_check(f) + } else { + quote {} + }; + let view_check = if f.has_named_attribute(quote { view }) { + create_view_check(f) + } else { + quote {} + }; + let (assert_initializer, mark_as_initialized) = if f.has_named_attribute(quote { initializer }) { + (create_assert_initializer(f), create_mark_as_initialized(f)) + } else { + (quote {}, quote {}) + }; + let storage_init = if module_has_storage { + quote { let storage = Storage::init(&mut context); } + } else { + quote {} + }; let init_check = if module_has_initializer & !f.has_named_attribute(quote { no_init_check }) { create_init_check(f) } else { @@ -114,39 +147,39 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { let return_value_type = f.return_type(); - let return_value_quote = if !return_value_type.eq(type_of(())) { + let return_value = if return_value_type != type_of(()) { let (body_without_return, return_value) = body.pop_back(); - let return_value_quote = return_value.quoted(); - let return_hasher_name_quote = quote { return_hasher }; - let return_value_into_hasher_quote = add_to_hasher( - return_hasher_name_quote, - return_value_quote, - return_value_type - ); + let return_value = return_value.quoted(); + let return_hasher_name = quote { return_hasher }; + let return_value_into_hasher = add_to_hasher(return_hasher_name, return_value, return_value_type); body = body_without_return; quote { - let $return_hasher_name_quote = dep::aztec::hash::ArgsHasher::new(); - $return_value_into_hasher_quote - context.set_return_hash($return_hasher_name_quote); + let $return_hasher_name = dep::aztec::hash::ArgsHasher::new(); + $return_value_into_hasher + context.set_return_hash($return_hasher_name); } } else { quote {} }; - let context_finish_quote = quote { context.finish() }; + let context_finish = quote { context.finish() }; let to_prepend = quote { - $args_hasher_quote - $context_creation_quote - $storage_init_quote + $args_hasher + $context_creation + $assert_initializer $init_check + $internal_check + $view_check + $storage_init }; let to_append = quote { - $return_value_quote - $context_finish_quote + $return_value + $mark_as_initialized + $context_finish }; modify_fn_body(f, to_prepend, to_append); @@ -158,12 +191,60 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { fn_abi } +pub comptime fn public(f: FunctionDefinition) -> Quoted { + let fn_abi = create_fn_abi_export(f); + let fn_stub = stub_fn(f); + STUBS = STUBS.push_back(fn_stub); + + let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| f.has_named_attribute(quote { initializer })); + let module_has_storage = STORAGE_LAYOUT_NAME != quote { }; + + let current_params = f.parameters(); + f.set_parameters( + &[ + ( + quote { inputs }, quote { crate::context::inputs::public_context_inputs::PublicContextInputs }.as_type() + ) + ].append(current_params) + ); + let context_creation = quote { let mut context = dep::aztec::context::public_context::PublicContext::new(inputs); }; + let storage_init = if module_has_storage { + quote { let storage = Storage::init(&mut context); } + } else { + quote {} + }; + let init_check = if module_has_initializer & !f.has_named_attribute(quote { no_init_check }) { + create_init_check(f) + } else { + quote {} + }; + + let to_prepend = quote { + $context_creation + $storage_init + $init_check + }; + + let to_append = quote {}; + + modify_fn_body(f, to_prepend, to_append); + f.set_unconstrained(true); + f.set_return_public(true); + fn_abi +} + pub comptime fn transform_unconstrained(f: FunctionDefinition) { - let context_creation_quote = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); }; - let storage_init_quote = quote { let storage = Storage::init(context); }; + let context_creation = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); }; + let module_has_storage = STORAGE_LAYOUT_NAME != quote { }; + + let storage_init = if module_has_storage { + quote { let storage = Storage::init(context); } + } else { + quote {} + }; let to_prepend = quote { - $context_creation_quote - $storage_init_quote + $context_creation + $storage_init }; modify_fn_body(f, to_prepend, quote {}); @@ -175,8 +256,8 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let fn_return_type = f.return_type(); let fn_visibility = get_fn_visibility(f); let is_static_call = is_fn_view(f); - let is_void: bool = fn_return_type.eq(type_of(())); - let fn_visibility_capitalized = if fn_visibility.eq(quote { private }) { + let is_void = fn_return_type == type_of(()); + let fn_visibility_capitalized = if is_fn_private(f) { quote { Private } } else { quote { Public } @@ -187,45 +268,45 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { quote { } }; let is_void_capitalized = if is_void { quote { Void } } else { quote { } }; - let args_acc_name_quote = quote { args_acc }; - let args_acc_quote = fn_parameters.fold( + let args_acc_name = quote { args_acc }; + let args_acc = fn_parameters.fold( quote { - let mut $args_acc_name_quote = &[]; + let mut $args_acc_name = &[]; }, - |args_hasher_quote, param: (Quoted, Type)| { + |args_hasher, param: (Quoted, Type)| { let (name, typ) = param; - let appended_arg_quote = add_to_field_slice(args_acc_name_quote, name, typ); + let appended_arg = add_to_field_slice(args_acc_name, name, typ); quote { - $args_hasher_quote - $appended_arg_quote + $args_hasher + $appended_arg } } ); - let args_hash_name_quote = if fn_visibility == quote { private } { + let args_hash_name = if fn_visibility == quote { private } { quote { args_hash } } else { quote {} }; - let args_quote = if fn_visibility == quote { private } { + let args = if fn_visibility == quote { private } { quote { - $args_acc_quote - let $args_hash_name_quote = dep::aztec::hash::hash_args($args_acc_name_quote); + $args_acc + let $args_hash_name = dep::aztec::hash::hash_args($args_acc_name); } } else { - args_acc_quote + args_acc }; - let fn_parameters_quote = fn_parameters.map( + let fn_parameters_list = fn_parameters.map( | (name, typ): (Quoted, Type) | { quote { $name: $typ } } ).join(quote{,}); - let fn_name_str_quote = fn_name.as_str_quote(); + let fn_name_str = fn_name.as_str_quote(); - let fn_name_len: u32 = unquote!(quote { $fn_name_str_quote.as_bytes().len()}); + let fn_name_len: u32 = unquote!(quote { $fn_name_str.as_bytes().len()}); let arg_types_list = fn_parameters.map(|(_, typ): (_, Type)| quote { $typ }).join(quote {,}); let arg_types = if fn_parameters.len() == 1 { @@ -237,29 +318,29 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let generics = if is_void { f"{arg_types}>".quoted_contents() } else { - f"{arg_types}, {fn_return_type}>".quoted_contents() + f"{fn_return_type}, {arg_types}>".quoted_contents() }; - let call_interface_name_quote = f"dep::aztec::context::call_interfaces::{fn_visibility_capitalized}{is_static_call_capitalized}{is_void_capitalized}CallInterface".quoted_contents(); - let call_interface_name_w_generics_quote = f"{call_interface_name_quote}<{fn_name_len}, {generics}".quoted_contents(); + let call_interface_name = f"dep::aztec::context::call_interfaces::{fn_visibility_capitalized}{is_static_call_capitalized}{is_void_capitalized}CallInterface".quoted_contents(); + let call_interface_name_w_generics = f"{call_interface_name}<{fn_name_len}, {generics}".quoted_contents(); let fn_selector: Field = compute_fn_selector(f); - let gas_opts = if fn_visibility.eq(quote { public }) { - quote { gas_opts: dep::aztec::context::gas::GasOpts::default() } + let gas_opts = if is_fn_public(f) { + quote { gas_opts: dep::aztec::context::gas::GasOpts::default() } } else { quote {} }; let input_type = f"crate::context::inputs::{fn_visibility_capitalized}ContextInputs".quoted_contents().as_type(); - let return_type_hint = if fn_visibility.eq(quote { private }) { + let return_type_hint = if is_fn_private(f) { quote { protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs }.as_type() } else { fn_return_type }; - let parameter_names_quote = if fn_parameters.len() > 0 { + let parameter_names = if fn_parameters.len() > 0 { let params = fn_parameters.map(|(name, _): (Quoted, _)| name).join(quote {,}); f",{params}".quoted_contents() } else { @@ -268,20 +349,26 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let original = quote { | inputs: $input_type | -> $return_type_hint { - $fn_name(inputs $parameter_names_quote) + $fn_name(inputs $parameter_names) } }; + let args_hash = if fn_visibility == quote { private } { + quote { $args_hash_name, } + } else { + quote {} + }; + quote { - pub fn $fn_name(self, $fn_parameters_quote) -> $call_interface_name_w_generics_quote { - $args_quote + pub fn $fn_name(self, $fn_parameters_list) -> $call_interface_name_w_generics { + $args let selector = dep::aztec::protocol_types::abis::function_selector::FunctionSelector::from_field($fn_selector); - $call_interface_name_quote { + $call_interface_name { target_contract: self.target_contract, selector, - name: $fn_name_str_quote, - $args_hash_name_quote, - args: $args_acc_name_quote, + name: $fn_name_str, + $args_hash + args: $args_acc_name, original: $original, is_static: $is_static_call, $gas_opts diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index a1f37023745..e39910a5c14 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -1,16 +1,38 @@ mod functions; mod utils; -mod note; +mod notes; mod storage; use functions::STUBS; use storage::STORAGE_LAYOUT_NAME; +use notes::NOTES; + use functions::transform_unconstrained; pub comptime fn generate_contract_interface(m: Module) -> Quoted { let module_name = m.name(); let fn_stubs_quote = STUBS.join(quote {}); + let has_storage = STORAGE_LAYOUT_NAME != quote {}; + let storage_layout_getter = if has_storage { + quote { + pub fn storage_layout() -> StorageLayout { + $STORAGE_LAYOUT_NAME + } + } + } else { + quote {} + }; + + let library_storage_layout_getter = if has_storage { + quote { + #[contract_library_method] + $storage_layout_getter + } + } else { + quote {} + }; + quote { struct $module_name { target_contract: dep::aztec::protocol_types::address::AztecAddress @@ -29,9 +51,7 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { Self { target_contract: aztec::protocol_types::address::AztecAddress::zero() } } - pub fn storage_layout() -> StorageLayout { - $STORAGE_LAYOUT_NAME - } + $storage_layout_getter } #[contract_library_method] @@ -46,18 +66,66 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { $module_name { target_contract: aztec::protocol_types::address::AztecAddress::zero() } } - #[contract_library_method] - pub fn storage_layout() -> StorageLayout { - $STORAGE_LAYOUT_NAME + $library_storage_layout_getter + + } +} + +pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { + let mut max_note_length: u32 = 0; + let body = if NOTES.len() == 0 { + quote { + assert(false, "This contract does not use private notes"); + [0, 0, 0, 0] + } + } else { + max_note_length = NOTES.fold(0, | acc, (_, len): (StructDefinition, u32) | { + acc + len + }); + let if_statements = NOTES.map( + | (note, _): (StructDefinition, u32) | { + let note_name = note.name(); + quote { + if note_type_id == $note_name::get_note_type_id() { + aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($note_name::deserialize_content, note_header, compute_nullifier, serialized_note) + } + } + } + ).join(quote{}); + + quote { + let note_header = aztec::prelude::NoteHeader::new(contract_address, nonce, storage_slot); + $if_statements + else { + assert(false, "Unknown note type ID"); + [0, 0, 0, 0] + } + } + }; + + quote { + unconstrained fn compute_note_hash_and_optionally_a_nullifier( + contract_address: aztec::protocol_types::address::AztecAddress, + nonce: Field, + storage_slot: Field, + note_type_id: Field, + compute_nullifier: bool, + serialized_note: [Field; $max_note_length], + ) -> pub [Field; 4] { + $body } } } pub comptime fn aztec_contract(m: Module) -> Quoted { let interface = generate_contract_interface(m); - let functions = m.functions(); - // for f in functions.filter(| f | f.) { - // transform_unconstrained(f); - // } - interface + let unconstrained_functions = m.functions().filter(| f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute(quote { test })); + let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); + for f in unconstrained_functions { + transform_unconstrained(f); + } + quote { + $interface + $compute_note_hash_and_optionally_a_nullifier + } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/note/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/note/mod.nr deleted file mode 100644 index 175e429ebe9..00000000000 --- a/noir-projects/aztec-nr/aztec/src/macros/note/mod.nr +++ /dev/null @@ -1,9 +0,0 @@ -comptime fn note(s: StructDefinition) { - // Automatically inject header if not present - let filtered_header = s.fields().filter( - | (field, typ): (Quoted, Type) | typ.eq(quote { dep::aztec::note::note_header::NoteHeader}.as_type()) - ); - if (filtered_header.len() == 0) { - let _ = s.fields().push_back((quote { header }, quote { dep::aztec::note::note_header::NoteHeader}.as_type())); - } -} diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr new file mode 100644 index 00000000000..4514e86042f --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -0,0 +1,26 @@ +use std::meta::typ::fresh_type_variable; + +comptime mut global NOTES = &[]; + +pub comptime fn note(s: StructDefinition) { + // Automatically inject header if not present + // let filtered_header = s.fields().filter( + // | (_, typ): (Quoted, Type) | typ.eq(quote { dep::aztec::note::note_header::NoteHeader}.as_type()) + // ); + // if (filtered_header.len() == 0) { + // let new_fields = s.fields().push_back((quote { header }, quote { dep::aztec::note::note_header::NoteHeader}.as_type())); + // s.set_fields(new_fields); + // } + + let serialized_len_generic = fresh_type_variable(); + let bytes_len_generic = fresh_type_variable(); + let maybe_note_interface_impl = s.as_type().get_trait_impl( + quote { crate::note::note_interface::NoteInterface<$serialized_len_generic, $bytes_len_generic> }.as_trait_constraint() + ); + assert(maybe_note_interface_impl.is_some(), "Note must implement NoteInterface"); + let note_interface_impl = maybe_note_interface_impl.unwrap(); + let note_serialized_len = note_interface_impl.trait_generic_args()[0].as_constant().unwrap(); + // Register note here + NOTES = NOTES.push_back((s, note_serialized_len)); + //note_interface_impl. +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index 492c72adcc2..5fd4b705fc4 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -24,13 +24,11 @@ pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, pare typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container`, or Map" ); let (container_struct, generics) = typ.as_struct().unwrap(); - let struct_name_quote = container_struct.name(); + let struct_name = container_struct.name(); if is_storage_map(typ) { let (value_constructor, _) = generate_storage_field_constructor(generics[1], quote { slot }, true); - ( - quote { $struct_name_quote::new(context, $slot, | context, slot | { $value_constructor }) }, 1 - ) + (quote { $struct_name::new(context, $slot, | context, slot | { $value_constructor }) }, 1) } else { let (container_struct, _) = typ.as_struct().unwrap(); let serialized_size = if parent_is_map | container_struct.has_named_attribute(quote { note }) { @@ -43,23 +41,36 @@ pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, pare assert(stored_struct.as_struct().is_some(), "Storable items must be Serializable structs"); get_serialized_size(stored_struct) }; - (quote { $struct_name_quote::new(context, $slot)}, serialized_size) + (quote { $struct_name::new(context, $slot)}, serialized_size) } } -// comptime fn add_context_generic(typ: Type) -> Type { -// let generics = typ.generics(); -// let context_generic = quote { Context }; -// let generics = generics.push_back(context_generic); -// quote { $typ<$generics> }.as_type() -// } +comptime fn add_context_generic(typ: Type, context_generic: Type) -> Type { + assert( + typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container<..., Context>`" + ); + if is_storage_map(typ) { + let (def, mut generics) = typ.as_struct().unwrap(); + let name = def.name(); + generics[generics.len() - 2] = add_context_generic(generics[1], context_generic); + generics[generics.len() - 1] = context_generic; + let generics = generics.map(|typ: Type| quote{$typ}).join(quote{,}); + quote { $name<$generics> }.as_type() + } else { + let (def, mut generics) = typ.as_struct().unwrap(); + let name = def.name(); + generics[generics.len() - 1] = context_generic; + let generics = generics.map(|typ: Type| quote{$typ}).join(quote{,}); + quote { $name<$generics> }.as_type() + } +} pub comptime fn storage(s: StructDefinition) -> Quoted { let mut slot: u32 = 1; let mut storage_vars_constructors = &[]; let mut storage_layout_fields = &[]; let mut storage_layout_constructors = &[]; - let mut new_storage_fields = &[]; + //let mut new_storage_fields = &[]; //let context_generic = s.add_generic("Context"); for field in s.fields() { let (name, typ) = field; @@ -67,10 +78,14 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { storage_vars_constructors = storage_vars_constructors.push_back(quote { $name: $storage_field_constructor }); storage_layout_fields = storage_layout_fields.push_back(quote { $name: dep::aztec::prelude::Storable }); storage_layout_constructors = storage_layout_constructors.push_back(quote { $name: dep::aztec::prelude::Storable { slot: $slot } }); - //new_storage_fields = new_storage_fields.push_back((name, quote )); + //let with_context_generic = add_context_generic(typ, context_generic); + //println(with_context_generic); + //new_storage_fields = new_storage_fields.push_back((name, with_context_generic )); slot += serialized_size; } + //s.set_fields(new_storage_fields); + let storage_vars_constructors = storage_vars_constructors.join(quote {,}); let storage_layout_fields = storage_layout_fields.join(quote {,}); let storage_layout_constructors = storage_layout_constructors.join(quote {,}); diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 38809bc7e54..bceb6230ee5 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -1,9 +1,10 @@ use dep::aztec::{ generators::{Ga1 as G_amt, Ga2 as G_npk, Ga3 as G_rnd, G_slot}, protocol_types::{ - address::AztecAddress, traits::{Deserialize, Serialize}, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, point::{Point, POINT_LENGTH} + traits::Serialize, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator, + point::{Point, POINT_LENGTH} }, + macros::notes::note, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_nullify}, oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext }; @@ -15,6 +16,7 @@ global VALUE_NOTE_BYTES_LEN: Field = 3 * 32 + 64; // docs:start:value-note-def #[aztec(note)] +#[note] struct ValueNote { value: Field, // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 5a4ad6b9daa..f001ddfe652 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -3,10 +3,10 @@ use dep::aztec::macros::aztec_contract; #[aztec_contract] contract Counter { // docs:start:imports - use dep::aztec::prelude::{AztecAddress, Map}; - use dep::value_note::{balance_utils, value_note::ValueNote}; - use dep::easy_private_state::EasyPrivateUint; - use dep::aztec::macros::{storage::storage, functions::{initializer, private, transform_unconstrained}}; + use aztec::prelude::{AztecAddress, Map}; + use value_note::{balance_utils, value_note::ValueNote}; + use easy_private_state::EasyPrivateUint; + use aztec::macros::{storage::storage, functions::{initializer, private}}; // docs:end:imports // docs:start:storage_struct @@ -38,7 +38,6 @@ contract Counter { // docs:end:increment // docs:start:get_counter - #[transform_unconstrained] unconstrained fn get_counter(owner: AztecAddress) -> pub Field { let counters = storage.counters; balance_utils::get_balance(counters.at(owner).set) diff --git a/noir-projects/noir-contracts/contracts/router_contract/src/main.nr b/noir-projects/noir-contracts/contracts/router_contract/src/main.nr index fd614c18c54..0b229474e8f 100644 --- a/noir-projects/noir-contracts/contracts/router_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/router_contract/src/main.nr @@ -1,23 +1,26 @@ mod test; mod utils; +use aztec::macros::aztec_contract; + /// The purpose of this contract is to perform a check in public without revealing what contract enqued the public /// call. This is achieved by having a private function on this contract that enques the public call and hence /// the `msg_sender` in the public call is the address of this contract. +#[aztec_contract] contract Router { - use aztec::utils::comparison::compare; + use aztec::{macros::functions::{private, public}, utils::comparison::compare}; // docs:start:check_timestamp /// Asserts that the current timestamp in the enqueued public call satisfies the `operation` with respect /// to the `value. - #[aztec(private)] + #[private] fn check_timestamp(operation: u8, value: u64) { Router::at(context.this_address())._check_timestamp(operation, value).enqueue_view(&mut context); } - #[aztec(public)] - #[aztec(internal)] - #[aztec(view)] + #[public] + #[internal] + #[view] fn _check_timestamp(operation: u8, value: u64) { let lhs_field = context.timestamp() as Field; let rhs_field = value as Field; @@ -27,14 +30,14 @@ contract Router { /// Asserts that the current block number in the enqueued public call satisfies the `operation` with respect /// to the `value. - #[aztec(private)] + #[private] fn check_block_number(operation: u8, value: Field) { Router::at(context.this_address())._check_block_number(operation, value).enqueue_view(&mut context); } - #[aztec(public)] - #[aztec(internal)] - #[aztec(view)] + #[public] + #[internal] + #[view] fn _check_block_number(operation: u8, value: Field) { assert(compare(context.block_number(), operation, value), "Block number mismatch."); } From 3305098778e7bc5784a587bb6450131fd71ffa49 Mon Sep 17 00:00:00 2001 From: thunkar Date: Thu, 12 Sep 2024 19:37:41 +0000 Subject: [PATCH 07/79] separated note interface + arithmetic generics --- .../encrypted_event_emission.nr | 44 ++++----- .../encrypted_logs/encrypted_note_emission.nr | 33 +++---- .../aztec/src/encrypted_logs/incoming_body.nr | 92 ++++++++++------- .../aztec/src/encrypted_logs/payload.nr | 8 +- .../aztec/src/event/event_interface.nr | 6 +- .../aztec/src/history/note_inclusion.nr | 6 +- .../aztec/src/history/note_validity.nr | 6 +- .../aztec/src/history/nullifier_inclusion.nr | 6 +- .../src/history/nullifier_non_inclusion.nr | 11 ++- .../aztec-nr/aztec/src/macros/notes/mod.nr | 3 +- .../aztec-nr/aztec/src/note/lifecycle.nr | 18 ++-- .../aztec/src/note/note_getter/mod.nr | 26 ++--- .../aztec/src/note/note_getter_options.nr | 10 +- .../aztec-nr/aztec/src/note/note_interface.nr | 10 +- .../aztec/src/note/note_viewer_options.nr | 6 +- .../aztec-nr/aztec/src/note/utils.nr | 33 ++++--- .../aztec-nr/aztec/src/oracle/notes.nr | 4 +- .../aztec/src/state_vars/private_immutable.nr | 11 ++- .../aztec/src/state_vars/private_mutable.nr | 12 +-- .../aztec/src/state_vars/private_set.nr | 14 +-- .../src/test/helpers/test_environment.nr | 2 +- .../aztec/src/test/mocks/mock_note.nr | 37 +++---- .../unencrypted_event_emission.nr | 30 ++++-- .../aztec-nr/value-note/src/utils.nr | 4 +- .../aztec-nr/value-note/src/value_note.nr | 98 ++++++++++++++++--- 25 files changed, 317 insertions(+), 213 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr index 90752c29467..a709ef477a6 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr @@ -6,7 +6,7 @@ use crate::{ }; use dep::protocol_types::{address::AztecAddress, hash::sha256_to_field}; -unconstrained fn compute_unconstrained( +unconstrained fn compute_unconstrained( contract_address: AztecAddress, randomness: Field, ovsk_app: Field, @@ -14,7 +14,7 @@ unconstrained fn compute_unconstrained ([u8; OB], Field) where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> ([u8; OB], Field) where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { compute( contract_address, randomness, @@ -26,7 +26,7 @@ unconstrained fn compute_unconstrained( +fn compute( contract_address: AztecAddress, randomness: Field, ovsk_app: Field, @@ -34,7 +34,7 @@ fn compute( ivpk: IvpkM, recipient: AztecAddress, event: Event -) -> ([u8; OB], Field) where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> ([u8; OB], Field) where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { let encrypted_log: [u8; OB] = compute_encrypted_event_log( contract_address, randomness, @@ -48,7 +48,7 @@ fn compute( (encrypted_log, log_hash) } -fn emit_with_keys( +fn emit_with_keys( context: &mut PrivateContext, randomness: Field, event: Event, @@ -56,18 +56,18 @@ fn emit_with_keys( ivpk: IvpkM, iv: AztecAddress, inner_compute: fn(AztecAddress, Field, Field, OvpkM, IvpkM, AztecAddress, Event) -> ([u8; OB], Field) -) where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { let contract_address: AztecAddress = context.this_address(); let ovsk_app: Field = context.request_ovsk_app(ovpk.hash()); let (encrypted_log, log_hash) = inner_compute(contract_address, randomness, ovsk_app, ovpk, ivpk, iv, event); context.emit_raw_event_log_with_masked_address(randomness, encrypted_log, log_hash); } -pub fn encode_and_encrypt_event( +pub fn encode_and_encrypt_event( context: &mut PrivateContext, ov: AztecAddress, iv: AztecAddress -) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](Event) -> () where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](Event) -> () where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { | e: Event | { let ovpk = get_current_public_keys(context, ov).ovpk_m; let ivpk = get_current_public_keys(context, iv).ivpk_m; @@ -76,11 +76,11 @@ pub fn encode_and_encrypt_event( } } -pub fn encode_and_encrypt_event_unconstrained( +pub fn encode_and_encrypt_event_unconstrained( context: &mut PrivateContext, ov: AztecAddress, iv: AztecAddress -) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](Event) -> () where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](Event) -> () where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { | e: Event | { let ovpk = get_current_public_keys(context, ov).ovpk_m; let ivpk = get_current_public_keys(context, iv).ivpk_m; @@ -89,12 +89,12 @@ pub fn encode_and_encrypt_event_unconstrained( +pub fn encode_and_encrypt_event_with_randomness( context: &mut PrivateContext, randomness: Field, ov: AztecAddress, iv: AztecAddress -) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress, Field)](Event) -> () where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress, Field)](Event) -> () where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { | e: Event | { let ovpk = get_current_public_keys(context, ov).ovpk_m; let ivpk = get_current_public_keys(context, iv).ivpk_m; @@ -102,12 +102,12 @@ pub fn encode_and_encrypt_event_with_randomness( +pub fn encode_and_encrypt_event_with_randomness_unconstrained( context: &mut PrivateContext, randomness: Field, ov: AztecAddress, iv: AztecAddress -) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress, Field)](Event) -> () where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress, Field)](Event) -> () where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { | e: Event | { let ovpk = get_current_public_keys(context, ov).ovpk_m; let ivpk = get_current_public_keys(context, iv).ivpk_m; @@ -115,49 +115,49 @@ pub fn encode_and_encrypt_event_with_randomness_unconstrained( +pub fn encode_and_encrypt_event_with_keys( context: &mut PrivateContext, ovpk: OvpkM, ivpk: IvpkM, recipient: AztecAddress -) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](Event) -> () where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](Event) -> () where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { | e: Event | { let randomness = unsafe_rand(); emit_with_keys(context, randomness, e, ovpk, ivpk, recipient, compute); } } -pub fn encode_and_encrypt_event_with_keys_unconstrained( +pub fn encode_and_encrypt_event_with_keys_unconstrained( context: &mut PrivateContext, ovpk: OvpkM, ivpk: IvpkM, recipient: AztecAddress -) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](Event) -> () where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](Event) -> () where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { | e: Event | { let randomness = unsafe_rand(); emit_with_keys(context, randomness, e, ovpk, ivpk, recipient, compute_unconstrained); } } -pub fn encode_and_encrypt_event_with_keys_with_randomness( +pub fn encode_and_encrypt_event_with_keys_with_randomness( context: &mut PrivateContext, randomness: Field, ovpk: OvpkM, ivpk: IvpkM, recipient: AztecAddress -) -> fn[(&mut PrivateContext, Field, OvpkM, IvpkM, AztecAddress)](Event) -> () where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> fn[(&mut PrivateContext, Field, OvpkM, IvpkM, AztecAddress)](Event) -> () where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { | e: Event | { emit_with_keys(context, randomness, e, ovpk, ivpk, recipient, compute); } } -pub fn encode_and_encrypt_event_with_keys_with_randomness_unconstrained( +pub fn encode_and_encrypt_event_with_keys_with_randomness_unconstrained( context: &mut PrivateContext, randomness: Field, ovpk: OvpkM, ivpk: IvpkM, recipient: AztecAddress -) -> fn[(&mut PrivateContext, Field, OvpkM, IvpkM, AztecAddress)](Event) -> () where Event: EventInterface, [u8; NB]: LensForEncryptedEvent { +) -> fn[(&mut PrivateContext, Field, OvpkM, IvpkM, AztecAddress)](Event) -> () where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { | e: Event | { emit_with_keys(context, randomness, e, ovpk, ivpk, recipient, compute_unconstrained); } diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr index 542c0830e8d..b6331f73c6c 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr @@ -3,12 +3,9 @@ use crate::{ keys::{getters::get_current_public_keys, public_keys::{OvpkM, IvpkM}}, encrypted_logs::payload::compute_encrypted_note_log, oracle::logs_traits::LensForEncryptedLog }; -use dep::protocol_types::{ - hash::sha256_to_field, address::AztecAddress, point::Point, abis::note_hash::NoteHash, - constants::MAX_NOTE_HASHES_PER_CALL -}; +use dep::protocol_types::{hash::sha256_to_field, address::AztecAddress, abis::note_hash::NoteHash}; -unconstrained fn compute_unconstrained( +unconstrained fn compute_unconstrained( contract_address: AztecAddress, storage_slot: Field, ovsk_app: Field, @@ -16,7 +13,7 @@ unconstrained fn compute_unconstrained ([u8; M], Field) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { +) -> ([u8; M], Field) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { compute( contract_address, storage_slot, @@ -28,7 +25,7 @@ unconstrained fn compute_unconstrained( +fn compute( contract_address: AztecAddress, storage_slot: Field, ovsk_app: Field, @@ -36,7 +33,7 @@ fn compute( ivpk: IvpkM, recipient: AztecAddress, note: Note -) -> ([u8; M], Field) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { +) -> ([u8; M], Field) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { let encrypted_log: [u8; M] = compute_encrypted_note_log( contract_address, storage_slot, @@ -50,14 +47,14 @@ fn compute( (encrypted_log, log_hash) } -fn emit_with_keys( +fn emit_with_keys( context: &mut PrivateContext, note: Note, ovpk: OvpkM, ivpk: IvpkM, recipient: AztecAddress, inner_compute: fn(AztecAddress, Field, Field, OvpkM, IvpkM, AztecAddress, Note) -> ([u8; M], Field) -) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { +) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { let note_header = note.get_header(); let note_hash_counter = note_header.note_hash_counter; let storage_slot = note_header.storage_slot; @@ -81,11 +78,11 @@ fn emit_with_keys( context.emit_raw_note_log(note_hash_counter, encrypted_log, log_hash); } -pub fn encode_and_encrypt_note( +pub fn encode_and_encrypt_note( context: &mut PrivateContext, ov: AztecAddress, iv: AztecAddress -) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](NoteEmission) -> () where Note: NoteInterface, [Field; N]: LensForEncryptedLog { +) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](NoteEmission) -> () where Note: NoteInterface, [Field; N]: LensForEncryptedLog { | e: NoteEmission | { let ovpk = get_current_public_keys(context, ov).ovpk_m; let ivpk = get_current_public_keys(context, iv).ivpk_m; @@ -93,11 +90,11 @@ pub fn encode_and_encrypt_note( } } -pub fn encode_and_encrypt_note_unconstrained( +pub fn encode_and_encrypt_note_unconstrained( context: &mut PrivateContext, ov: AztecAddress, iv: AztecAddress -) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](NoteEmission) -> () where Note: NoteInterface, [Field; N]: LensForEncryptedLog { +) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](NoteEmission) -> () where Note: NoteInterface, [Field; N]: LensForEncryptedLog { | e: NoteEmission | { let ovpk = get_current_public_keys(context, ov).ovpk_m; let ivpk = get_current_public_keys(context, iv).ivpk_m; @@ -105,23 +102,23 @@ pub fn encode_and_encrypt_note_unconstrained( +pub fn encode_and_encrypt_note_with_keys( context: &mut PrivateContext, ovpk: OvpkM, ivpk: IvpkM, recipient: AztecAddress -) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](NoteEmission) -> () where Note: NoteInterface, [Field; N]: LensForEncryptedLog { +) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](NoteEmission) -> () where Note: NoteInterface, [Field; N]: LensForEncryptedLog { | e: NoteEmission | { emit_with_keys(context, e.note, ovpk, ivpk, recipient, compute); } } -pub fn encode_and_encrypt_note_with_keys_unconstrained( +pub fn encode_and_encrypt_note_with_keys_unconstrained( context: &mut PrivateContext, ovpk: OvpkM, ivpk: IvpkM, recipient: AztecAddress -) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](NoteEmission) -> () where Note: NoteInterface, [Field; N]: LensForEncryptedLog { +) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](NoteEmission) -> () where Note: NoteInterface, [Field; N]: LensForEncryptedLog { | e: NoteEmission | { emit_with_keys(context, e.note, ovpk, ivpk, recipient, compute_unconstrained); } diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr index eaa143772bc..0b94e35b527 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr @@ -5,20 +5,17 @@ use dep::protocol_types::{scalar::Scalar, point::Point}; use std::aes128::aes128_encrypt; use crate::keys::{point_to_symmetric_key::point_to_symmetric_key, public_keys::IvpkM}; -struct EncryptedLogIncomingBody { - plaintext: [u8; M] +struct EncryptedLogIncomingBody { + plaintext: [u8; N * 32 + 64] } -impl EncryptedLogIncomingBody { - pub fn from_note(note: T, storage_slot: Field) -> Self where T: NoteInterface { +impl EncryptedLogIncomingBody { + pub fn from_note(note: T, storage_slot: Field) -> Self where T: NoteInterface { let mut plaintext = note.to_be_bytes(storage_slot); EncryptedLogIncomingBody { plaintext } } - pub fn from_event( - event: T, - randomness: Field - ) -> Self where T: EventInterface { + pub fn from_event(event: T, randomness: Field) -> Self where T: EventInterface { let mut plaintext = event.private_to_be_bytes(randomness); EncryptedLogIncomingBody { plaintext } } @@ -43,7 +40,7 @@ mod test { }; use crate::{ - note::{note_header::NoteHeader, note_interface::NoteInterface}, + note::{note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}}, encrypted_logs::incoming_body::EncryptedLogIncomingBody, event::event_interface::EventInterface, context::PrivateContext, keys::public_keys::IvpkM }; @@ -56,9 +53,22 @@ mod test { } global ADDRESS_NOTE_LEN: Field = 3; - global ADDRESS_NOTE_BYTES_LEN = 32 * 3 + 64; - impl NoteInterface for AddressNote { + impl NullifiableNote for AddressNote { + fn compute_nullifier( + _self: Self, + _context: &mut PrivateContext, + _note_hash_for_nullify: Field + ) -> Field { + 1 + } + + fn compute_nullifier_without_context(_self: Self) -> Field { + 1 + } + } + + impl NoteInterface for AddressNote { fn compute_note_hiding_point(_self: Self) -> Point { crate::generators::Ga1 } @@ -67,28 +77,31 @@ mod test { 1 } - fn get_header(self) -> NoteHeader { self.header} - - fn set_header(&mut self, header: NoteHeader) {self.header = header; } - - fn compute_nullifier(_self: Self, _context: &mut PrivateContext, _note_hash_for_nullify: Field) -> Field { - 1 + fn get_header(self) -> NoteHeader { + self.header } - fn compute_nullifier_without_context(_self: Self) -> Field { - 1 + fn set_header(&mut self, header: NoteHeader) { + self.header = header; } - fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN] { [self.address.to_field(), self.owner.to_field(), self.randomness]} + fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN] { + [self.address.to_field(), self.owner.to_field(), self.randomness] + } fn deserialize_content(fields: [Field; ADDRESS_NOTE_LEN]) -> Self { - AddressNote { address: AztecAddress::from_field(fields[0]), owner: AztecAddress::from_field(fields[1]), randomness: fields[2], header: NoteHeader::empty() } + AddressNote { + address: AztecAddress::from_field(fields[0]), + owner: AztecAddress::from_field(fields[1]), + randomness: fields[2], + header: NoteHeader::empty() + } } - fn to_be_bytes(self, storage_slot: Field) -> [u8; ADDRESS_NOTE_BYTES_LEN] { + fn to_be_bytes(self, storage_slot: Field) -> [u8; ADDRESS_NOTE_LEN * 32 + 64] { let serialized_note = self.serialize_content(); - let mut buffer: [u8; ADDRESS_NOTE_BYTES_LEN] = [0; ADDRESS_NOTE_BYTES_LEN]; + let mut buffer: [u8; ADDRESS_NOTE_LEN * 32 + 64] = [0; ADDRESS_NOTE_LEN * 32 + 64]; let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); let note_type_id_bytes: [u8; 32] = AddressNote::get_note_type_id().to_be_bytes(); @@ -175,13 +188,16 @@ mod test { global TEST_EVENT_BYTES_LEN = 32 * 3 + 64; global TEST_EVENT_BYTES_LEN_WITHOUT_RANDOMNESS = 32 * 3 + 32; - impl EventInterface for TestEvent { + impl EventInterface for TestEvent { fn get_event_type_id() -> EventSelector { - comptime { EventSelector::from_signature("TestEvent(Field,Field,Field)") } + comptime + { + EventSelector::from_signature("TestEvent(Field,Field,Field)") + } } - fn private_to_be_bytes(self, randomness: Field) -> [u8; TEST_EVENT_BYTES_LEN] { - let mut buffer: [u8; TEST_EVENT_BYTES_LEN] = [0; TEST_EVENT_BYTES_LEN]; + fn private_to_be_bytes(self, randomness: Field) -> [u8; TEST_EVENT_LEN * 32 + 64] { + let mut buffer: [u8; TEST_EVENT_LEN * 32 + 64] = [0; TEST_EVENT_LEN * 32 + 64]; let randomness_bytes: [u8; 32] = randomness.to_be_bytes(); let event_type_id_bytes: [u8; 32] = TestEvent::get_event_type_id().to_field().to_be_bytes(); @@ -203,25 +219,25 @@ mod test { buffer } - fn to_be_bytes(self) -> [u8; TEST_EVENT_BYTES_LEN_WITHOUT_RANDOMNESS] { - let mut buffer: [u8; TEST_EVENT_BYTES_LEN_WITHOUT_RANDOMNESS] = [0; TEST_EVENT_BYTES_LEN_WITHOUT_RANDOMNESS]; + fn to_be_bytes(self) -> [u8; TEST_EVENT_LEN * 32 + 32] { + let mut buffer: [u8; TEST_EVENT_LEN * 32 + 32] = [0; TEST_EVENT_LEN * 32 + 32]; - let event_type_id_bytes: [u8; 32] = TestEvent::get_event_type_id().to_field().to_be_bytes(); + let event_type_id_bytes: [u8; 32] = TestEvent::get_event_type_id().to_field().to_be_bytes(); - for i in 0..32 { - buffer[i] = event_type_id_bytes[i]; + for i in 0..32 { + buffer[i] = event_type_id_bytes[i]; } - let serialized_event = self.serialize(); + let serialized_event = self.serialize(); - for i in 0..serialized_event.len() { - let bytes: [u8; 32] = serialized_event[i].to_be_bytes(); - for j in 0..32 { - buffer[32 + i * 32 + j] = bytes[j]; + for i in 0..serialized_event.len() { + let bytes: [u8; 32] = serialized_event[i].to_be_bytes(); + for j in 0..32 { + buffer[32 + i * 32 + j] = bytes[j]; } } - buffer + buffer } fn emit(self, _emit: fn[Env](Self) -> ()) { diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr index 84c7a9eacbf..a7d0bea7c13 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr @@ -14,7 +14,7 @@ use crate::{ keys::public_keys::{OvpkM, IvpkM} }; -pub fn compute_encrypted_event_log( +pub fn compute_encrypted_event_log( contract_address: AztecAddress, randomness: Field, ovsk_app: Field, @@ -22,7 +22,7 @@ pub fn compute_encrypted_event_log ivpk: IvpkM, recipient: AztecAddress, event: Event -) -> [u8; OB] where Event: EventInterface { +) -> [u8; OB] where Event: EventInterface { let (eph_sk, eph_pk) = generate_ephemeral_key_pair(); let header = EncryptedLogHeader::new(contract_address); @@ -65,7 +65,7 @@ pub fn compute_encrypted_event_log encrypted_bytes } -pub fn compute_encrypted_note_log( +pub fn compute_encrypted_note_log( contract_address: AztecAddress, storage_slot: Field, ovsk_app: Field, @@ -73,7 +73,7 @@ pub fn compute_encrypted_note_log( ivpk: IvpkM, recipient: AztecAddress, note: Note -) -> [u8; M] where Note: NoteInterface { +) -> [u8; M] where Note: NoteInterface { let (eph_sk, eph_pk) = generate_ephemeral_key_pair(); let header = EncryptedLogHeader::new(contract_address); diff --git a/noir-projects/aztec-nr/aztec/src/event/event_interface.nr b/noir-projects/aztec-nr/aztec/src/event/event_interface.nr index 58a7ea2ba79..ee82d72d293 100644 --- a/noir-projects/aztec-nr/aztec/src/event/event_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/event/event_interface.nr @@ -1,8 +1,8 @@ use dep::protocol_types::abis::event_selector::EventSelector; -trait EventInterface { - fn private_to_be_bytes(self, randomness: Field) -> [u8; NB]; - fn to_be_bytes(self) -> [u8; MB]; +trait EventInterface { + fn private_to_be_bytes(self, randomness: Field) -> [u8; N * 32 + 64]; + fn to_be_bytes(self) -> [u8; N * 32 + 32]; fn get_event_type_id() -> EventSelector; fn emit(self, _emit: fn[Env](Self) -> ()); } diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index 6dc078e986b..a6b8dbbb0d4 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -2,16 +2,16 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use dep::protocol_types::header::Header; use crate::{ - note::{utils::compute_note_hash_for_nullify, note_interface::NoteInterface}, + note::{utils::compute_note_hash_for_nullify, note_interface::{NoteInterface, NullifiableNote}}, oracle::get_membership_witness::get_note_hash_membership_witness }; trait ProveNoteInclusion { - fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface; + fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote; } impl ProveNoteInclusion for Header { - fn prove_note_inclusion(self, note: Note) where Note: NoteInterface { + fn prove_note_inclusion(self, note: Note) where Note: NoteInterface + NullifiableNote { let note_hash = compute_note_hash_for_nullify(note); let witness = unsafe { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr index e0560ea39f8..3c8ccea46ea 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr @@ -1,13 +1,13 @@ -use crate::{context::PrivateContext, note::note_interface::NoteInterface}; +use crate::{context::PrivateContext, note::note_interface::{NoteInterface, NullifiableNote}}; use dep::protocol_types::header::Header; trait ProveNoteValidity { - fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; + fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteValidity for Header { - fn prove_note_validity(self, note: Note, context: &mut PrivateContext) where Note: NoteInterface { + fn prove_note_validity(self, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote { self.prove_note_inclusion(note); self.prove_note_not_nullified(note, context); } diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index 4c9b89788d1..6f0b5914549 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -3,7 +3,7 @@ use dep::protocol_types::header::Header; use crate::{ context::PrivateContext, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, - note::{utils::compute_siloed_nullifier, note_interface::NoteInterface} + note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote}} }; trait ProveNullifierInclusion { @@ -32,12 +32,12 @@ impl ProveNullifierInclusion for Header { } trait ProveNoteIsNullified { - fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; + fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteIsNullified for Header { // docs:start:prove_note_is_nullified - fn prove_note_is_nullified(self, note: Note, context: &mut PrivateContext) where Note: NoteInterface { + fn prove_note_is_nullified(self, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote { let nullifier = compute_siloed_nullifier(note, context); self.prove_nullifier_inclusion(nullifier); diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index 5238ca99c50..d4d378f716a 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -1,7 +1,8 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use dep::protocol_types::{header::Header, utils::field::{full_field_less_than, full_field_greater_than}}; use crate::{ - context::PrivateContext, note::{utils::compute_siloed_nullifier, note_interface::NoteInterface}, + context::PrivateContext, + note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote}}, oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness }; @@ -41,12 +42,16 @@ impl ProveNullifierNonInclusion for Header { } trait ProveNoteNotNullified { - fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; + fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteNotNullified for Header { // docs:start:prove_note_not_nullified - fn prove_note_not_nullified(self, note: Note, context: &mut PrivateContext) where Note: NoteInterface { + fn prove_note_not_nullified( + self, + note: Note, + context: &mut PrivateContext + ) where Note: NoteInterface + NullifiableNote { let nullifier = compute_siloed_nullifier(note, context); self.prove_nullifier_non_inclusion(nullifier); diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 4514e86042f..da119bdcf07 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -13,9 +13,8 @@ pub comptime fn note(s: StructDefinition) { // } let serialized_len_generic = fresh_type_variable(); - let bytes_len_generic = fresh_type_variable(); let maybe_note_interface_impl = s.as_type().get_trait_impl( - quote { crate::note::note_interface::NoteInterface<$serialized_len_generic, $bytes_len_generic> }.as_trait_constraint() + quote { crate::note::note_interface::NoteInterface<$serialized_len_generic> }.as_trait_constraint() ); assert(maybe_note_interface_impl.is_some(), "Note must implement NoteInterface"); let note_interface_impl = maybe_note_interface_impl.unwrap(); diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index 5253b37ddd2..aae74d02193 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -1,16 +1,16 @@ use crate::context::{PrivateContext, PublicContext}; use crate::note::{ - note_header::NoteHeader, note_interface::NoteInterface, + note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}, utils::{compute_note_hash_for_read_request, compute_note_hash_for_nullify_internal}, note_emission::NoteEmission }; use crate::oracle::notes::{notify_created_note, notify_nullified_note}; -pub fn create_note( +pub fn create_note( context: &mut PrivateContext, storage_slot: Field, note: &mut Note -) -> NoteEmission where Note: NoteInterface { +) -> NoteEmission where Note: NoteInterface + NullifiableNote { let contract_address = (*context).this_address(); let note_hash_counter = context.side_effect_counter; @@ -36,11 +36,11 @@ pub fn create_note( NoteEmission::new(*note) } -pub fn create_note_hash_from_public( +pub fn create_note_hash_from_public( context: &mut PublicContext, storage_slot: Field, note: &mut Note -) where Note: NoteInterface { +) where Note: NoteInterface + NullifiableNote { let contract_address = (*context).this_address(); // Public note hashes are transient, but have no side effect counters, so we just need note_hash_counter != 0 let header = NoteHeader { contract_address, storage_slot, nonce: 0, note_hash_counter: 1 }; @@ -52,20 +52,20 @@ pub fn create_note_hash_from_public( } // Note: This function is currently totally unused. -pub fn destroy_note( +pub fn destroy_note( context: &mut PrivateContext, note: Note -) where Note: NoteInterface { +) where Note: NoteInterface + NullifiableNote { let note_hash_for_read_request = compute_note_hash_for_read_request(note); destroy_note_unsafe(context, note, note_hash_for_read_request) } -pub fn destroy_note_unsafe( +pub fn destroy_note_unsafe( context: &mut PrivateContext, note: Note, note_hash_for_read_request: Field -) where Note: NoteInterface { +) where Note: NoteInterface + NullifiableNote { let note_hash_for_nullify = compute_note_hash_for_nullify_internal(note, note_hash_for_read_request); let nullifier = note.compute_nullifier(context, note_hash_for_nullify); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index 25d66fe899d..e97d8fd576f 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -3,7 +3,7 @@ use crate::context::PrivateContext; use crate::note::{ constants::{GET_NOTE_ORACLE_RETURN_LENGTH, MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH}, note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, NoteStatus, PropertySelector}, - note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_request }; use crate::oracle; @@ -36,7 +36,7 @@ fn check_note_header( context: PrivateContext, storage_slot: Field, note: Note -) where Note: NoteInterface { +) where Note: NoteInterface { let header = note.get_header(); let contract_address = context.this_address(); assert(header.contract_address.eq(contract_address), "Mismatch note header contract address."); @@ -79,7 +79,7 @@ fn check_notes_order( pub fn get_note( context: &mut PrivateContext, storage_slot: Field -) -> (Note, Field) where Note: NoteInterface { +) -> (Note, Field) where Note: NoteInterface + NullifiableNote { let note = unsafe { get_note_internal(storage_slot) }; @@ -97,8 +97,8 @@ pub fn get_note( pub fn get_notes( context: &mut PrivateContext, storage_slot: Field, - options: NoteGetterOptions -) -> (BoundedVec, BoundedVec) where Note: NoteInterface + Eq { + options: NoteGetterOptions +) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + Eq { let opt_notes = unsafe { get_notes_internal(storage_slot, options) }; @@ -120,8 +120,8 @@ fn constrain_get_notes_internal; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], - options: NoteGetterOptions -) -> (BoundedVec, BoundedVec) where Note: NoteInterface + Eq { + options: NoteGetterOptions +) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + Eq { // The filter is applied first to avoid pushing note read requests for notes we're not interested in. Note that // while the filter function can technically mutate the contents of the notes (as opposed to simply removing some), // the private kernel will later validate that these note actually exist, so transformations would cause for that @@ -161,7 +161,7 @@ fn constrain_get_notes_internal(storage_slot: Field) -> Note where Note: NoteInterface { +unconstrained fn get_note_internal(storage_slot: Field) -> Note where Note: NoteInterface { let placeholder_note = [Option::none()]; let placeholder_fields = [0; GET_NOTE_ORACLE_RETURN_LENGTH]; let placeholder_note_length = [0; N]; @@ -188,8 +188,8 @@ unconstrained fn get_note_internal(storage_slot: F unconstrained fn get_notes_internal( storage_slot: Field, - options: NoteGetterOptions -) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { + options: NoteGetterOptions +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { // This function simply performs some transformations from NoteGetterOptions into the types required by the oracle. let (num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order) = flatten_options(options.selects, options.sorts); @@ -220,10 +220,10 @@ unconstrained fn get_notes_internal( +unconstrained pub fn view_notes( storage_slot: Field, - options: NoteViewerOptions -) -> BoundedVec where Note: NoteInterface { + options: NoteViewerOptions +) -> BoundedVec where Note: NoteInterface { let (num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE]; let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH]; diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr index 2414ca7b10d..c48b2f453f4 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr @@ -61,7 +61,7 @@ fn return_all_notes( } // docs:start:NoteGetterOptions -struct NoteGetterOptions { +struct NoteGetterOptions { selects: BoundedVec, N>, sorts: BoundedVec, N>, limit: u32, @@ -82,7 +82,7 @@ struct NoteGetterOptions NoteGetterOptions { +impl NoteGetterOptions { // This method adds a `Select` criterion to the options. // It takes a property_selector indicating which field to select, // a value representing the specific value to match in that field, and @@ -136,7 +136,7 @@ impl NoteGetterOpt } } -impl NoteGetterOptions where Note: NoteInterface { +impl NoteGetterOptions where Note: NoteInterface { // This function initializes a NoteGetterOptions that simply returns the maximum number of notes allowed in a call. pub fn new() -> Self { Self { @@ -153,7 +153,7 @@ impl NoteGetterOptions w } } -impl NoteGetterOptions where Note: NoteInterface { +impl NoteGetterOptions where Note: NoteInterface { // This function initializes a NoteGetterOptions with a preprocessor, which takes the notes returned from // the database and preprocessor_args as its parameters. // `preprocessor_args` allows you to provide additional data or context to the custom preprocessor. @@ -175,7 +175,7 @@ impl NoteGetterOptions NoteGetterOptions where Note: NoteInterface { +impl NoteGetterOptions where Note: NoteInterface { // This function initializes a NoteGetterOptions with a filter, which takes // the notes returned from the database and filter_args as its parameters. // `filter_args` allows you to provide additional data or context to the custom filter. diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index 7631d30da12..9ade63d0057 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -2,8 +2,7 @@ use crate::context::PrivateContext; use crate::note::note_header::NoteHeader; use dep::protocol_types::point::Point; -// docs:start:note_interface -trait NoteInterface { +trait NullifiableNote { // This function MUST be called with the correct note hash for consumption! It will otherwise silently fail and // compute an incorrect value. // The reason why we receive this as an argument instead of computing it ourselves directly is because the @@ -14,7 +13,10 @@ trait NoteInterface { // Unlike compute_nullifier, this function does not take a note hash since it'll only be invoked in unconstrained // contexts, where there is no gate count. fn compute_nullifier_without_context(self) -> Field; - +} + +// docs:start:note_interface +trait NoteInterface { // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn serialize_content(self) -> [Field; N]; @@ -34,7 +36,7 @@ trait NoteInterface { fn get_note_type_id() -> Field; // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation - fn to_be_bytes(self, storage_slot: Field) -> [u8; M]; + fn to_be_bytes(self, storage_slot: Field) -> [u8; N*32 + 64]; } // docs:end:note_interface diff --git a/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr index 8c1a106ff53..6fb0ad85d8c 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr @@ -5,7 +5,7 @@ use crate::note::note_interface::NoteInterface; use crate::note::constants::MAX_NOTES_PER_PAGE; // docs:start:NoteViewerOptions -struct NoteViewerOptions { +struct NoteViewerOptions { selects: BoundedVec, N>, sorts: BoundedVec, N>, limit: u32, @@ -14,8 +14,8 @@ struct NoteViewerOptions { } // docs:end:NoteViewerOptions -impl NoteViewerOptions { - pub fn new() -> NoteViewerOptions where Note: NoteInterface { +impl NoteViewerOptions { + pub fn new() -> NoteViewerOptions where Note: NoteInterface { NoteViewerOptions { selects: BoundedVec::new(), sorts: BoundedVec::new(), diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 75cb366afe7..618c4e75f34 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -1,4 +1,7 @@ -use crate::{context::PrivateContext, note::{note_header::NoteHeader, note_interface::NoteInterface}}; +use crate::{ + context::PrivateContext, + note::{note_header::NoteHeader, note_interface::{NullifiableNote, NoteInterface}} +}; use dep::protocol_types::{ hash::{ @@ -8,10 +11,10 @@ use dep::protocol_types::{ utils::arr_copy_slice }; -pub fn compute_siloed_nullifier( +pub fn compute_siloed_nullifier( note_with_header: Note, context: &mut PrivateContext -) -> Field where Note: NoteInterface { +) -> Field where Note: NoteInterface + NullifiableNote { let header = note_with_header.get_header(); let note_hash_for_nullify = compute_note_hash_for_nullify(note_with_header); let inner_nullifier = note_with_header.compute_nullifier(context, note_hash_for_nullify); @@ -20,7 +23,7 @@ pub fn compute_siloed_nullifier( } // TODO(#7775): make this not impossible to understand -pub fn compute_note_hash_for_read_request(note: Note) -> Field where Note: NoteInterface { +pub fn compute_note_hash_for_read_request(note: Note) -> Field where Note: NoteInterface + NullifiableNote { // TODO(#7771): inject compute_note_hash(...) func to notes with macros. let note_hash = note.compute_note_hiding_point().x; let nonce = note.get_header().nonce; @@ -34,10 +37,10 @@ pub fn compute_note_hash_for_read_request(note: No } // TODO(#7775): make this not impossible to understand -pub fn compute_note_hash_for_nullify_internal( +pub fn compute_note_hash_for_nullify_internal( note: Note, note_hash_for_read_request: Field -) -> Field where Note: NoteInterface { +) -> Field where Note: NoteInterface + NullifiableNote { let header = note.get_header(); if header.note_hash_counter != 0 { @@ -57,12 +60,12 @@ pub fn compute_note_hash_for_nullify_internal( } // TODO(#7775): nuke this commented out code - kept it around as it contains comments which might be helpful when tackling #7775 -// pub fn compute_note_hash_for_nullify(note: Note) -> Field where Note: NoteInterface { +// pub fn compute_note_hash_for_nullify(note: Note) -> Field where Note: NoteInterface { // let header = note.get_header(); // // There are 3 cases for reading a note intended for consumption: -// // 1. The note was inserted in this transaction, is revertible, or is not nullified by a revertible nullifier in +// // 1. The note was inserted in this transaction, is revertible, or is not nullified by a revertible nullifier in // // the same transaction: (note_hash_counter != 0) & (nonce == 0) -// // 2. The note was inserted in this transaction, is non-revertible, and is nullified by a revertible nullifier in +// // 2. The note was inserted in this transaction, is non-revertible, and is nullified by a revertible nullifier in // // the same transaction: (note_hash_counter != 0) & (nonce != 0) // // 3. The note was inserted in a previous transaction: (note_hash_counter == 0) & (nonce != 0) @@ -74,15 +77,15 @@ pub fn compute_note_hash_for_nullify_internal( // // If a note is transient, we just read the note_hash (kernel will hash it with nonce and silo by contract address). // note_hash // } else { -// // Case 2: If a note is non-revertible, and is nullified by a revertible nullifier, we cannot squash them in the -// // private reset circuit. Because if the tx reverts, we will have to keep the note hash and throw away the +// // Case 2: If a note is non-revertible, and is nullified by a revertible nullifier, we cannot squash them in the +// // private reset circuit. Because if the tx reverts, we will have to keep the note hash and throw away the // // nullifier. // // And if the tx does not revert, both will be emitted. In which case, the nullifier must be created in the app // // from the siloed note hash. // // The kernel circuit will check that a nullifier with non-zero note_nonce is linked to a note hash, whose // // siloed note hash matches the note hash specified in the nullifier. -// // Case 3: If a note is not from the current transaction, that means we are reading a settled note (from +// // Case 3: If a note is not from the current transaction, that means we are reading a settled note (from // // tree) created in a previous TX. So we need the siloed_note_hash which has already been hashed with // // nonce and then contract address. This hash will match the existing leaf in the note hash // // tree, so the kernel can just perform a membership check directly on this hash/leaf. @@ -99,17 +102,17 @@ pub fn compute_note_hash_for_nullify_internal( // } // } -pub fn compute_note_hash_for_nullify(note: Note) -> Field where Note: NoteInterface { +pub fn compute_note_hash_for_nullify(note: Note) -> Field where Note: NoteInterface + NullifiableNote { let note_hash_for_read_request = compute_note_hash_for_read_request(note); compute_note_hash_for_nullify_internal(note, note_hash_for_read_request) } -pub fn compute_note_hash_and_optionally_a_nullifier( +pub fn compute_note_hash_and_optionally_a_nullifier( deserialize_content: fn([Field; N]) -> T, note_header: NoteHeader, compute_nullifier: bool, serialized_note: [Field; S] -) -> [Field; 4] where T: NoteInterface { +) -> [Field; 4] where T: NoteInterface + NullifiableNote { let mut note = deserialize_content(arr_copy_slice(serialized_note, [0; N], 0)); note.set_header(note_header); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index b384ff82488..b3f95b57a4a 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -86,7 +86,7 @@ unconstrained fn get_notes_oracle_wrapper( ) } -unconstrained pub fn get_notes( +unconstrained pub fn get_notes( storage_slot: Field, num_selects: u8, select_by_indexes: [u8; M], @@ -104,7 +104,7 @@ unconstrained pub fn get_notes; S], // TODO: Remove it and use `limit` to initialize the note array. placeholder_fields: [Field; NS], // TODO: Remove it and use `limit` to initialize the note array. _placeholder_note_length: [Field; N] // Turbofish hack? Compiler breaks calculating read_offset unless we add this parameter -) -> [Option; S] where Note: NoteInterface { +) -> [Option; S] where Note: NoteInterface { let fields = get_notes_oracle_wrapper( storage_slot, num_selects, diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 5510253e228..9f463483f03 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -2,8 +2,9 @@ use dep::protocol_types::{constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, use crate::context::{PrivateContext, UnconstrainedContext}; use crate::note::{ - lifecycle::create_note, note_getter::{get_note, view_notes}, note_interface::NoteInterface, - note_viewer_options::NoteViewerOptions, note_emission::NoteEmission + lifecycle::create_note, note_getter::{get_note, view_notes}, + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, + note_emission::NoteEmission }; use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; @@ -44,7 +45,7 @@ impl PrivateImmutable { pub fn initialize( self, note: &mut Note - ) -> NoteEmission where Note: NoteInterface { + ) -> NoteEmission where Note: NoteInterface + NullifiableNote { // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); self.context.push_nullifier(nullifier); @@ -54,7 +55,7 @@ impl PrivateImmutable { // docs:end:initialize // docs:start:get_note - pub fn get_note(self) -> Note where Note: NoteInterface { + pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote { let storage_slot = self.storage_slot; get_note(self.context, storage_slot).0 } @@ -71,7 +72,7 @@ impl PrivateImmutable { // view_note does not actually use the context, but it calls oracles that are only available in private // docs:start:view_note - unconstrained pub fn view_note(self) -> Note where Note: NoteInterface { + unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(0) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index dcd219d9ad2..4a1540118d4 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -1,12 +1,10 @@ -use dep::protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, - hash::poseidon2_hash_with_separator -}; +use dep::protocol_types::{constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, hash::poseidon2_hash_with_separator}; use crate::context::{PrivateContext, UnconstrainedContext}; use crate::note::{ lifecycle::{create_note, destroy_note_unsafe}, note_getter::{get_note, view_notes}, - note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, note_emission::NoteEmission + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, + note_emission::NoteEmission }; use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; @@ -46,7 +44,7 @@ impl PrivateMutable { } } -impl PrivateMutable where Note: NoteInterface { +impl PrivateMutable where Note: NoteInterface + NullifiableNote { // docs:start:initialize pub fn initialize(self, note: &mut Note) -> NoteEmission { // Nullify the storage slot. @@ -105,7 +103,7 @@ impl PrivateMutable where Note: NoteInter // docs:end:get_note } -impl PrivateMutable where Note: NoteInterface { +impl PrivateMutable where Note: NoteInterface + NullifiableNote { unconstrained pub fn is_initialized(self) -> bool { let nullifier = self.compute_initialization_nullifier(); check_nullifier_exists(nullifier) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index b115b8c3adc..0eb7822218f 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -4,7 +4,7 @@ use crate::note::{ constants::MAX_NOTES_PER_PAGE, lifecycle::{create_note, create_note_hash_from_public, destroy_note_unsafe}, note_getter::{get_notes, view_notes}, note_getter_options::NoteGetterOptions, - note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_request, note_emission::NoteEmission }; use crate::state_vars::storage::Storage; @@ -27,7 +27,7 @@ impl PrivateSet { // docs:end:new } -impl PrivateSet where Note: NoteInterface { +impl PrivateSet where Note: NoteInterface + NullifiableNote { // docs:start:insert_from_public pub fn insert_from_public(self, note: &mut Note) { create_note_hash_from_public(self.context, self.storage_slot, note); @@ -35,7 +35,7 @@ impl PrivateSet where No // docs:end:insert_from_public } -impl PrivateSet where Note: NoteInterface + Eq { +impl PrivateSet where Note: NoteInterface + NullifiableNote + Eq { // docs:start:insert pub fn insert(self, note: &mut Note) -> NoteEmission { create_note(self.context, self.storage_slot, note) @@ -44,7 +44,7 @@ impl PrivateSet where N pub fn pop_notes( self, - options: NoteGetterOptions + options: NoteGetterOptions ) -> BoundedVec { let (notes, note_hashes) = get_notes(self.context, self.storage_slot, options); // We iterate in a range 0..options.limit instead of 0..notes.len() because options.limit is known at compile @@ -77,17 +77,17 @@ impl PrivateSet where N /// in significantly less constrains due to avoiding 1 read request check. pub fn get_notes( self, - options: NoteGetterOptions + options: NoteGetterOptions ) -> BoundedVec { get_notes(self.context, self.storage_slot, options).0 } } -impl PrivateSet where Note: NoteInterface { +impl PrivateSet where Note: NoteInterface + NullifiableNote { // docs:start:view_notes unconstrained pub fn view_notes( self, - options: NoteViewerOptions + options: NoteViewerOptions ) -> BoundedVec { view_notes(self.storage_slot, options) } diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index b5b6c20a554..a752bf6d7b6 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -213,7 +213,7 @@ impl TestEnvironment { note: &mut Note, storage_slot: Field, contract_address: AztecAddress - ) where Note: NoteInterface { + ) where Note: NoteInterface { let original_contract_address = get_contract_address(); cheatcodes::set_contract_address(contract_address); let note_hash_counter = cheatcodes::get_side_effects_counter(); diff --git a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr index fda3cc1be45..933b0c01b02 100644 --- a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr +++ b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr @@ -5,17 +5,31 @@ use crate::{ use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, point::Point, traits::Eq}; use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; +use crate::note::note_interface::NullifiableNote; global MOCK_NOTE_LENGTH = 1; -// MOCK_NOTE_LENGTH * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global MOCK_NOTE_BYTES_LENGTH: Field = 1 * 32 + 64; struct MockNote { header: NoteHeader, value: Field, } -impl NoteInterface for MockNote { +impl NullifiableNote for MockNote { + fn compute_nullifier(_self: Self, _context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { + // We don't use any kind of secret here since this is only a mock note and having it here would make tests + // more cumbersome + poseidon2_hash_with_separator([note_hash_for_nullify], GENERATOR_INDEX__NOTE_NULLIFIER as Field) + } + + fn compute_nullifier_without_context(self) -> Field { + // We don't use any kind of secret here since this is only a mock note and having it here would make tests + // more cumbersome + let note_hash_for_nullify = compute_note_hash_for_nullify(self); + poseidon2_hash_with_separator([note_hash_for_nullify], GENERATOR_INDEX__NOTE_NULLIFIER as Field) + } +} + +impl NoteInterface for MockNote { fn serialize_content(self) -> [Field; MOCK_NOTE_LENGTH] { [self.value] } @@ -47,23 +61,10 @@ impl NoteInterface for MockNote { 4135 } - fn compute_nullifier(_self: Self, _context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { - // We don't use any kind of secret here since this is only a mock note and having it here would make tests - // more cumbersome - poseidon2_hash_with_separator([note_hash_for_nullify], GENERATOR_INDEX__NOTE_NULLIFIER as Field) - } - - fn compute_nullifier_without_context(self) -> Field { - // We don't use any kind of secret here since this is only a mock note and having it here would make tests - // more cumbersome - let note_hash_for_nullify = compute_note_hash_for_nullify(self); - poseidon2_hash_with_separator([note_hash_for_nullify], GENERATOR_INDEX__NOTE_NULLIFIER as Field) - } - - fn to_be_bytes(self, storage_slot: Field) -> [u8; MOCK_NOTE_BYTES_LENGTH] { + fn to_be_bytes(self, storage_slot: Field) -> [u8; MOCK_NOTE_LENGTH * 32 + 64] { let serialized_note = self.serialize_content(); - let mut buffer: [u8; MOCK_NOTE_BYTES_LENGTH] = [0; MOCK_NOTE_BYTES_LENGTH]; + let mut buffer: [u8; MOCK_NOTE_LENGTH * 32 + 64] = [0; MOCK_NOTE_LENGTH * 32 + 64]; let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); let note_type_id_bytes: [u8; 32] = MockNote::get_note_type_id().to_be_bytes(); diff --git a/noir-projects/aztec-nr/aztec/src/unencrypted_logs/unencrypted_event_emission.nr b/noir-projects/aztec-nr/aztec/src/unencrypted_logs/unencrypted_event_emission.nr index 8f977dc71ed..f8126cf8990 100644 --- a/noir-projects/aztec-nr/aztec/src/unencrypted_logs/unencrypted_event_emission.nr +++ b/noir-projects/aztec-nr/aztec/src/unencrypted_logs/unencrypted_event_emission.nr @@ -4,10 +4,10 @@ use crate::{ }; use dep::protocol_types::{address::AztecAddress, traits::Serialize}; -fn emit( +fn emit( context: &mut PublicContext, event: Event -) where Event: EventInterface, Event: Serialize, [Field; N]: LensForEventSelector { +) where Event: EventInterface, Event: Serialize, [Field; N]: LensForEventSelector { let selector = Event::get_event_type_id(); let serialized_event = event.serialize(); @@ -23,7 +23,7 @@ fn emit( context.emit_unencrypted_log(emitted_log); } -pub fn encode_event(context: &mut PublicContext) -> fn[(&mut PublicContext,)](Event) -> () where Event: EventInterface, Event: Serialize, [Field; N]: LensForEventSelector { +pub fn encode_event(context: &mut PublicContext) -> fn[(&mut PublicContext,)](Event) -> () where Event: EventInterface, Event: Serialize, [Field; N]: LensForEventSelector { | e: Event | { emit( context, @@ -39,20 +39,32 @@ trait LensForEventSelector { } impl LensForEventSelector<1, 2> for [Field; 1] { - fn output(self) -> [Field; 2] {[self[0] as Field; 2]} + fn output(self) -> [Field; 2] { + [self[0] as Field; 2] + } } impl LensForEventSelector<2, 3> for [Field; 2] { - fn output(self) -> [Field; 3] {[self[0] as Field; 3]} + fn output(self) -> [Field; 3] { + [self[0] as Field; 3] + } } impl LensForEventSelector<3, 4> for [Field; 3] { - fn output(self) -> [Field; 4] {[self[0] as Field; 4]} + fn output(self) -> [Field; 4] { + [self[0] as Field; 4] + } } impl LensForEventSelector<4, 5> for [Field; 4] { - fn output(self) -> [Field; 5] {[self[0] as Field; 5]} + fn output(self) -> [Field; 5] { + [self[0] as Field; 5] + } } impl LensForEventSelector<5, 6> for [Field; 5] { - fn output(self) -> [Field; 6] {[self[0] as Field; 6]} + fn output(self) -> [Field; 6] { + [self[0] as Field; 6] + } } impl LensForEventSelector<6, 7> for [Field; 6] { - fn output(self) -> [Field; 7] {[self[0] as Field; 7]} + fn output(self) -> [Field; 7] { + [self[0] as Field; 7] + } } diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index f4919981818..72592a41b8b 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -2,11 +2,11 @@ use dep::aztec::prelude::{AztecAddress, PrivateContext, PrivateSet, NoteGetterOp use dep::aztec::note::note_getter_options::SortOrder; use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys; use dep::aztec::keys::getters::get_current_public_keys; -use crate::{filter::filter_notes_min_sum, value_note::{ValueNote, VALUE_NOTE_LEN, VALUE_NOTE_BYTES_LEN}}; +use crate::{filter::filter_notes_min_sum, value_note::{ValueNote, VALUE_NOTE_LEN}}; // Sort the note values (0th field) in descending order. // Pick the fewest notes whose sum is equal to or greater than `amount`. -pub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteGetterOptions { +pub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteGetterOptions { NoteGetterOptions::with_filter(filter_notes_min_sum, amount).sort(ValueNote::properties().value, SortOrder.DESC) } diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index bceb6230ee5..ba9e6953cea 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -5,36 +5,54 @@ use dep::aztec::{ point::{Point, POINT_LENGTH} }, macros::notes::note, - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_nullify}, + note::{ + note_header::NoteHeader, note_interface::{NullifiableNote, NoteInterface}, + note_getter_options::PropertySelector, utils::compute_note_hash_for_nullify +}, oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext }; use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; -global VALUE_NOTE_LEN: Field = 3; // 3 plus a header. -// VALUE_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global VALUE_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global VALUE_NOTE_LEN: u64 = 3; // 3 plus a header. // docs:start:value-note-def -#[aztec(note)] #[note] struct ValueNote { value: Field, // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. npk_m_hash: Field, randomness: Field, + header: NoteHeader } // docs:end:value-note-def -impl NoteInterface for ValueNote { +struct ValueNoteProperties { + value: PropertySelector, + npk_m_hash: PropertySelector, + randomness: PropertySelector, +} + +impl ValueNote { + fn properties() -> ValueNoteProperties { + ValueNoteProperties { + value: PropertySelector { index: 0, offset: 0, length: 32 }, + npk_m_hash: PropertySelector { index: 1, offset: 0, length: 32 }, + randomness: PropertySelector { index: 2, offset: 0, length: 32 } + } + } +} + +impl NullifiableNote for ValueNote { // docs:start:nullifier fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash_with_separator([ + poseidon2_hash_with_separator( + [ note_hash_for_nullify, secret ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, + GENERATOR_INDEX__NOTE_NULLIFIER as Field ) } @@ -43,13 +61,65 @@ impl NoteInterface for ValueNote { fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_nullify(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash_with_separator([ + poseidon2_hash_with_separator( + [ note_hash_for_nullify, - secret, + secret ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, + GENERATOR_INDEX__NOTE_NULLIFIER as Field ) } +} + +impl NoteInterface for ValueNote { + + fn to_be_bytes(self, storage_slot: Field) -> [u8; VALUE_NOTE_LEN * 32 + 64] { + let serialized_note = self.serialize_content(); + + let mut buffer: [u8; VALUE_NOTE_LEN * 32 + 64] = [0; VALUE_NOTE_LEN * 32 + 64]; + + let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); + let note_type_id_bytes: [u8; 32] = ValueNote::get_note_type_id().to_be_bytes(); + + for i in 0..32 { + { + buffer[i] = storage_slot_bytes[i]; + buffer[32 + i] = note_type_id_bytes[i]; + } + } + + for i in 0..serialized_note.len() { + { + let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); + for j in 0..32 { + { + buffer[64 + i * 32 + j] = bytes[j]; + } + } + } + } + buffer + } + + fn deserialize_content(fields: [Field; VALUE_NOTE_LEN]) -> Self { + ValueNote { value: fields[0], npk_m_hash: fields[1], randomness: fields[2], header: NoteHeader::empty() } + } + + fn serialize_content(self) -> [Field; VALUE_NOTE_LEN] { + [self.value, self.npk_m_hash, self.randomness] + } + + fn get_note_type_id() -> Field { + 1 + } + + fn set_header(&mut self, header: NoteHeader) { + self.header = header; + } + + fn get_header(self) -> NoteHeader { + self.header + } fn compute_note_hiding_point(self) -> Point { // We use the unsafe version because the multi_scalar_mul will constrain the scalars. @@ -96,9 +166,9 @@ impl Serialize<7> for ValueNote { impl Eq for ValueNote { fn eq(self, other: Self) -> bool { - (self.value == other.value) & - (self.npk_m_hash == other.npk_m_hash) & - (self.randomness == other.randomness) + (self.value == other.value) + & (self.npk_m_hash == other.npk_m_hash) + & (self.randomness == other.randomness) } } From 09ff34e972d0e939ff2490e8d39018e246032314 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 13 Sep 2024 12:16:15 +0000 Subject: [PATCH 08/79] the witch is dead --- .../aztec/src/encrypted_logs/incoming_body.nr | 11 +- .../aztec/src/history/note_inclusion.nr | 9 +- .../aztec/src/history/note_validity.nr | 10 +- .../aztec/src/history/nullifier_inclusion.nr | 10 +- .../src/history/nullifier_non_inclusion.nr | 6 +- .../aztec/src/macros/functions/mod.nr | 49 ++- .../aztec-nr/aztec/src/macros/mod.nr | 24 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 304 ++++++++++++++++-- .../aztec-nr/aztec/src/macros/storage/mod.nr | 2 +- .../aztec-nr/aztec/src/macros/utils.nr | 20 +- .../aztec-nr/aztec/src/note/lifecycle.nr | 16 +- .../aztec/src/note/note_getter/mod.nr | 10 +- .../aztec-nr/aztec/src/note/note_interface.nr | 15 +- .../aztec-nr/aztec/src/note/utils.nr | 17 +- .../aztec/src/state_vars/private_immutable.nr | 10 +- .../aztec/src/state_vars/private_mutable.nr | 8 +- .../aztec/src/state_vars/private_set.nr | 11 +- .../src/test/helpers/test_environment.nr | 16 +- .../aztec/src/test/mocks/mock_note.nr | 50 +-- .../aztec-nr/value-note/src/value_note.nr | 151 +-------- .../contracts/counter_contract/src/main.nr | 4 +- .../contracts/router_contract/src/main.nr | 4 +- .../src/types/transparent_note.nr | 4 +- .../crates/types/src/meta/mod.nr | 88 ++--- .../crates/types/src/traits.nr | 96 +++++- 25 files changed, 602 insertions(+), 343 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr index 0b94e35b527..41adaca8480 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr @@ -40,7 +40,7 @@ mod test { }; use crate::{ - note::{note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}}, + note::{note_header::NoteHeader, note_interface::{NoteInterface, PartialNote, NullifiableNote}}, encrypted_logs::incoming_body::EncryptedLogIncomingBody, event::event_interface::EventInterface, context::PrivateContext, keys::public_keys::IvpkM }; @@ -68,10 +68,17 @@ mod test { } } - impl NoteInterface for AddressNote { + struct AddressNoteHidingPoint { + inner: Point + } + + impl PartialNote for AddressNote { fn compute_note_hiding_point(_self: Self) -> Point { crate::generators::Ga1 } + } + + impl NoteInterface for AddressNote { fn get_note_type_id() -> Field { 1 diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index a6b8dbbb0d4..b144c4910be 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -2,16 +2,19 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use dep::protocol_types::header::Header; use crate::{ - note::{utils::compute_note_hash_for_nullify, note_interface::{NoteInterface, NullifiableNote}}, + note::{utils::compute_note_hash_for_nullify, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}}, oracle::get_membership_witness::get_note_hash_membership_witness }; trait ProveNoteInclusion { - fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote; + fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote + FinalizedNote; } impl ProveNoteInclusion for Header { - fn prove_note_inclusion(self, note: Note) where Note: NoteInterface + NullifiableNote { + fn prove_note_inclusion( + self, + note: Note + ) where Note: NoteInterface + NullifiableNote + FinalizedNote { let note_hash = compute_note_hash_for_nullify(note); let witness = unsafe { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr index 3c8ccea46ea..4f38f37a22c 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr @@ -1,13 +1,17 @@ -use crate::{context::PrivateContext, note::note_interface::{NoteInterface, NullifiableNote}}; +use crate::{context::PrivateContext, note::note_interface::{NoteInterface, NullifiableNote, FinalizedNote}}; use dep::protocol_types::header::Header; trait ProveNoteValidity { - fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; + fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote + FinalizedNote; } impl ProveNoteValidity for Header { - fn prove_note_validity(self, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote { + fn prove_note_validity( + self, + note: Note, + context: &mut PrivateContext + ) where Note: NoteInterface + NullifiableNote + FinalizedNote { self.prove_note_inclusion(note); self.prove_note_not_nullified(note, context); } diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index 6f0b5914549..bd6b285f8ea 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -3,7 +3,7 @@ use dep::protocol_types::header::Header; use crate::{ context::PrivateContext, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, - note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote}} + note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}} }; trait ProveNullifierInclusion { @@ -32,12 +32,16 @@ impl ProveNullifierInclusion for Header { } trait ProveNoteIsNullified { - fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; + fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote + FinalizedNote; } impl ProveNoteIsNullified for Header { // docs:start:prove_note_is_nullified - fn prove_note_is_nullified(self, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote { + fn prove_note_is_nullified( + self, + note: Note, + context: &mut PrivateContext + ) where Note: NoteInterface + NullifiableNote + FinalizedNote { let nullifier = compute_siloed_nullifier(note, context); self.prove_nullifier_inclusion(nullifier); diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index d4d378f716a..d3545a5d672 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -2,7 +2,7 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use dep::protocol_types::{header::Header, utils::field::{full_field_less_than, full_field_greater_than}}; use crate::{ context::PrivateContext, - note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote}}, + note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}}, oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness }; @@ -42,7 +42,7 @@ impl ProveNullifierNonInclusion for Header { } trait ProveNoteNotNullified { - fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; + fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote + FinalizedNote; } impl ProveNoteNotNullified for Header { @@ -51,7 +51,7 @@ impl ProveNoteNotNullified for Header { self, note: Note, context: &mut PrivateContext - ) where Note: NoteInterface + NullifiableNote { + ) where Note: NoteInterface + NullifiableNote + FinalizedNote { let nullifier = compute_siloed_nullifier(note, context); self.prove_nullifier_non_inclusion(nullifier); diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 565ef8530de..e7da8422ea4 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -1,10 +1,9 @@ use std::meta::{unquote, type_of}; use super::utils::{ - modify_fn_body, is_fn_private, get_fn_visibility, is_fn_view, compute_fn_selector, - add_to_field_slice, add_to_hasher + modify_fn_body, is_fn_private, get_fn_visibility, is_fn_view, is_fn_initializer, is_fn_internal, + fn_has_noinitcheck, compute_fn_selector, add_to_field_slice, add_to_hasher }; -use super::storage::STORAGE_LAYOUT_NAME; use super::utils::is_fn_public; comptime mut global STUBS: [Quoted] = &[]; @@ -92,8 +91,8 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { let fn_stub = stub_fn(f); STUBS = STUBS.push_back(fn_stub); - let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| f.has_named_attribute(quote { initializer })); - let module_has_storage = STORAGE_LAYOUT_NAME != quote { }; + let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| is_fn_initializer(f)); + let module_has_storage = f.module().structs().any(|s: StructDefinition| s.has_named_attribute("storage")); let current_params = f.parameters(); f.set_parameters( @@ -119,17 +118,17 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { } ); let context_creation = quote { let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); }; - let internal_check = if f.has_named_attribute(quote { internal }) { + let internal_check = if is_fn_internal(f) { create_internal_check(f) } else { quote {} }; - let view_check = if f.has_named_attribute(quote { view }) { + let view_check = if is_fn_view(f) { create_view_check(f) } else { quote {} }; - let (assert_initializer, mark_as_initialized) = if f.has_named_attribute(quote { initializer }) { + let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) { (create_assert_initializer(f), create_mark_as_initialized(f)) } else { (quote {}, quote {}) @@ -139,7 +138,7 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { } else { quote {} }; - let init_check = if module_has_initializer & !f.has_named_attribute(quote { no_init_check }) { + let init_check = if module_has_initializer & !fn_has_noinitcheck(f) { create_init_check(f) } else { quote {} @@ -196,8 +195,8 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { let fn_stub = stub_fn(f); STUBS = STUBS.push_back(fn_stub); - let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| f.has_named_attribute(quote { initializer })); - let module_has_storage = STORAGE_LAYOUT_NAME != quote { }; + let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| is_fn_initializer(f)); + let module_has_storage = f.module().structs().any(|s: StructDefinition| s.has_named_attribute("storage")); let current_params = f.parameters(); f.set_parameters( @@ -208,12 +207,27 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { ].append(current_params) ); let context_creation = quote { let mut context = dep::aztec::context::public_context::PublicContext::new(inputs); }; + let internal_check = if is_fn_internal(f) { + create_internal_check(f) + } else { + quote {} + }; + let view_check = if is_fn_view(f) { + create_view_check(f) + } else { + quote {} + }; + let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) { + (create_assert_initializer(f), create_mark_as_initialized(f)) + } else { + (quote {}, quote {}) + }; let storage_init = if module_has_storage { quote { let storage = Storage::init(&mut context); } } else { quote {} }; - let init_check = if module_has_initializer & !f.has_named_attribute(quote { no_init_check }) { + let init_check = if module_has_initializer & !fn_has_noinitcheck(f) { create_init_check(f) } else { quote {} @@ -221,11 +235,16 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { let to_prepend = quote { $context_creation - $storage_init + $assert_initializer $init_check + $internal_check + $view_check + $storage_init }; - let to_append = quote {}; + let to_append = quote { + $mark_as_initialized + }; modify_fn_body(f, to_prepend, to_append); f.set_unconstrained(true); @@ -235,7 +254,7 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { pub comptime fn transform_unconstrained(f: FunctionDefinition) { let context_creation = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); }; - let module_has_storage = STORAGE_LAYOUT_NAME != quote { }; + let module_has_storage = f.module().structs().any(|s: StructDefinition| s.has_named_attribute("storage")); let storage_init = if module_has_storage { quote { let storage = Storage::init(context); } diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index e39910a5c14..9ba5b12b1c7 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -5,7 +5,7 @@ mod storage; use functions::STUBS; use storage::STORAGE_LAYOUT_NAME; -use notes::NOTES; +use notes::{NOTES, generate_note_export}; use functions::transform_unconstrained; @@ -79,11 +79,11 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quote [0, 0, 0, 0] } } else { - max_note_length = NOTES.fold(0, | acc, (_, len): (StructDefinition, u32) | { + max_note_length = NOTES.fold(0, | acc, (_, len, _): (StructDefinition, u32, Field) | { acc + len }); let if_statements = NOTES.map( - | (note, _): (StructDefinition, u32) | { + | (note, _, _): (StructDefinition, u32, Field) | { let note_name = note.name(); quote { if note_type_id == $note_name::get_note_type_id() { @@ -117,15 +117,29 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quote } } -pub comptime fn aztec_contract(m: Module) -> Quoted { +pub comptime fn generate_note_exports() -> Quoted { + let note_exports = NOTES.map( + | (s, _, note_type_id): (StructDefinition, u32, Field) | { + generate_note_export(s, note_type_id) + } + ).join(quote {}); + + quote { + $note_exports + } +} + +pub comptime fn aztec(m: Module) -> Quoted { let interface = generate_contract_interface(m); - let unconstrained_functions = m.functions().filter(| f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute(quote { test })); + let unconstrained_functions = m.functions().filter(| f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute("test")); let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); + let note_exports = generate_note_exports(); for f in unconstrained_functions { transform_unconstrained(f); } quote { $interface $compute_note_hash_and_optionally_a_nullifier + $note_exports } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index da119bdcf07..da1562ac6d9 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -1,25 +1,291 @@ -use std::meta::typ::fresh_type_variable; +use std::meta::{type_of, unquote}; +use protocol_types::{meta::flatten_to_fields, utils::field::field_from_bytes}; +use crate::note::{note_header::NoteHeader, note_getter_options::PropertySelector}; comptime mut global NOTES = &[]; -pub comptime fn note(s: StructDefinition) { - // Automatically inject header if not present - // let filtered_header = s.fields().filter( - // | (_, typ): (Quoted, Type) | typ.eq(quote { dep::aztec::note::note_header::NoteHeader}.as_type()) - // ); - // if (filtered_header.len() == 0) { - // let new_fields = s.fields().push_back((quote { header }, quote { dep::aztec::note::note_header::NoteHeader}.as_type())); - // s.set_fields(new_fields); - // } - - let serialized_len_generic = fresh_type_variable(); - let maybe_note_interface_impl = s.as_type().get_trait_impl( - quote { crate::note::note_interface::NoteInterface<$serialized_len_generic> }.as_trait_constraint() +comptime fn compute_note_type_id(name: Quoted) -> Field { + let name_as_str_quote = name.as_str_quote(); + + let hash: [u8; 32] = unquote!( + quote { + let bytes = $name_as_str_quote.as_bytes(); + std::hash::keccak256(bytes, bytes.len() as u32) + } + ); + + let mut selector_be_bytes = [0; 4]; + for i in 0..4 { + selector_be_bytes[i] = hash[i]; + } + + field_from_bytes(selector_be_bytes, true) +} + +comptime fn generate_note_interface(s: StructDefinition) -> (Quoted, u32, Field) { + let name = s.name(); + let typ = s.as_type(); + let (fields, aux_vars) = flatten_to_fields(quote { self }, typ, &[quote {self.header}]); + let aux_vars_for_serialization = if aux_vars.len() > 0 { + let joint = aux_vars.join(quote {;}); + quote { $joint; } + } else { + quote {} + }; + let serialized_fields = fields.join(quote {,}); + let content_len = fields.len(); + + let mut deserialized_fields = &[]; + + let note_header_type = quote { crate::note::note_header::NoteHeader}.as_type(); + let mut field_counter: u64 = 0; + for field in s.fields() { + let (name, typ) = field; + if typ != note_header_type { + deserialized_fields = deserialized_fields.push_back(quote { $name: fields[$field_counter] }); + } + field_counter+= 1; + } + + let deserialized_content = deserialized_fields.join(quote {,}); + + let note_type_id = compute_note_type_id(name); + + (quote { + impl aztec::note::note_interface::NoteInterface<$content_len> for ValueNote { + fn to_be_bytes(self, storage_slot: Field) -> [u8; $content_len * 32 + 64] { + let serialized_note = self.serialize_content(); + + let mut buffer: [u8; $content_len * 32 + 64] = [0; $content_len * 32 + 64]; + + let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); + let note_type_id_bytes: [u8; 32] = $name::get_note_type_id().to_be_bytes(); + + for i in 0..32 { + buffer[i] = storage_slot_bytes[i]; + buffer[32 + i] = note_type_id_bytes[i]; + } + + for i in 0..serialized_note.len() { + let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); + for j in 0..32 { + buffer[64 + i * 32 + j] = bytes[j]; + } + } + buffer + } + + fn deserialize_content(fields: [Field; $content_len]) -> Self { + $name { + $deserialized_content, + header: NoteHeader::empty() + } + } + + fn serialize_content(self) -> [Field; $content_len] { + $aux_vars_for_serialization + [$serialized_fields] + } + + fn get_note_type_id() -> Field { + $note_type_id + } + + fn set_header(&mut self, header: $note_header_type) { + self.header = header; + } + + fn get_header(self) -> $note_header_type { + self.header + } + + } + }, content_len, note_type_id) +} + +comptime fn generate_note_properties(s: StructDefinition) -> Quoted { + let name = s.name(); + + let struct_name = f"{name}Properties".quoted_contents(); + + let property_selector_type = type_of(PropertySelector { index: 0, offset: 0, length: 0 }); + let note_header_type: Type = type_of(NoteHeader::empty()); + + let non_header_fields = s.fields().filter(| (_, typ): (Quoted, Type) | typ != note_header_type); + + let properties_types = non_header_fields.map( + | (name, _): (Quoted, Type) | { + quote { $name: $property_selector_type } + } + ).join(quote {,}); + + // TODO: Properly handle non-field types + let mut properties_list = &[]; + for i in 0..non_header_fields.len() { + let (name, _) = non_header_fields[i]; + properties_list = properties_list.push_back(quote { $name: aztec::note::note_getter_options::PropertySelector { index: $i, offset: 0, length: 32 } }); + } + + let properties = properties_list.join(quote {,}); + + quote { + struct $struct_name { + $properties_types + } + + impl aztec::note::note_interface::NoteProperties<$struct_name> for $name { + fn properties() -> $struct_name { + $struct_name { + $properties + } + } + } + } +} + +pub(crate) comptime fn generate_note_export(s: StructDefinition, note_type_id: Field) -> Quoted { + let name = s.name(); + let global_export_name = f"{name}_EXPORTS".quoted_contents(); + let note_name_as_str = name.as_str_quote(); + let note_name_str_len = unquote!(quote { $note_name_as_str.as_bytes().len() }); + let note_type_id_hex = f"0x{note_type_id}".quoted_contents(); + quote { + #[abi(notes)] + global $global_export_name: (Field, str<$note_name_str_len>) = ($note_type_id_hex,$note_name_as_str); + } +} + +comptime fn generate_note_hiding_point(s: StructDefinition, nullable_fields: [Quoted]) -> (Quoted, Quoted) { + let name = s.name(); + let hiding_point_name = f"{name}HidingPoint".quoted_contents(); + let note_header_type: Type = type_of(NoteHeader::empty()); + + let fixed_fields = s.fields().filter( + | (name, typ): (Quoted, Type) | (typ != note_header_type) & nullable_fields.all(| field | field != name) ); - assert(maybe_note_interface_impl.is_some(), "Note must implement NoteInterface"); - let note_interface_impl = maybe_note_interface_impl.unwrap(); - let note_serialized_len = note_interface_impl.trait_generic_args()[0].as_constant().unwrap(); + + let mut new_generators_list = &[]; + let mut new_scalars_list = &[]; + for i in 0..fixed_fields.len() { + let (field_name, _) = fixed_fields[i]; + let generator_index = i + 1; + new_generators_list = new_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); + new_scalars_list = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(note.$field_name.to_field()) }); + } + let new_generators = new_generators_list.push_back(quote { aztec::generators::G_slot }).join(quote {,}); + let new_scalars = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(note.get_header().storage_slot) }).join(quote {,}); + + let mut finalize_generators_list = &[]; + let mut finalize_scalars_list = &[]; + let mut finalize_args_list = &[]; + let mut finalize_generics_list = &[]; + let mut finalize_trait_bounds_list = &[]; + + for i in 0..nullable_fields.len() { + let field_name = nullable_fields[i]; + let arg_type = f"N{i}".quoted_contents(); + finalize_args_list = finalize_args_list.push_back(quote { $field_name: $arg_type }); + let generator_index = i + 1; + finalize_generators_list = finalize_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); + finalize_scalars_list = finalize_scalars_list.push_back(quote { std::hash::from_field_unsafe($field_name.to_field()) }); + finalize_generics_list = finalize_generics_list.push_back(quote { $arg_type }); + finalize_trait_bounds_list = finalize_trait_bounds_list.push_back(quote { $arg_type: aztec::protocol_types::traits::ToField }); + } + + let finalize_args = if finalize_args_list.len() > 0 { + &[quote {self}].append(finalize_args_list).join(quote {,}) + } else { + quote {self} + }; + + let finalize_body = if nullable_fields.len() > 0 { + let finalize_generators = finalize_generators_list.join(quote {,}); + let finalize_scalars = finalize_scalars_list.join(quote {,}); + quote { + let point = std::embedded_curve_ops::multi_scalar_mul( + [$finalize_generators], + [$finalize_scalars] + ) + self.inner.x; + point.x + } + } else { + quote { self.inner.x } + }; + + let finalize_name = if finalize_generics_list.len() > 0 { + let generics = finalize_generics_list.join(quote {,}); + quote {finalize<$generics>} + } else { + quote {finalize} + }; + + let finalize_trait_bounds = if finalize_trait_bounds_list.len() > 0 { + let bounds = finalize_trait_bounds_list.join(quote {,}); + quote {where $bounds} + } else { + quote {} + }; + + (quote { + struct $hiding_point_name { + inner: aztec::protocol_types::point::Point + } + + impl $hiding_point_name { + fn new(note: $name) -> $hiding_point_name { + let generators = [$new_generators]; + let point = std::embedded_curve_ops::multi_scalar_mul( + [$new_generators], + [$new_scalars] + ); + $hiding_point_name { inner: point } + } + + fn $finalize_name($finalize_args) -> Field $finalize_trait_bounds { + $finalize_body + } + } + + impl aztec::protocol_types::traits::Serialize for $hiding_point_name { + fn serialize(self) -> [Field; aztec::protocol_types::point::POINT_LENGTH] { + self.inner.serialize() + } + } + }, hiding_point_name) +} + +pub comptime fn generate_finalized_note_for_complete_note(s: StructDefinition, hiding_point_name: Quoted) -> Quoted { + let name = s.name(); + quote { + impl aztec::note::note_interface::FinalizedNote for $name { + fn compute_note_hash(self) -> Field { + $hiding_point_name::new(self).finalize() + } + } + } +} + +pub comptime fn note(s: StructDefinition) -> Quoted { + // Automatically inject header if not present + let note_header_type = type_of(NoteHeader::empty()); + let filtered_header = s.fields().filter(| (_, typ): (Quoted, Type) | typ == note_header_type); + if (filtered_header.len() == 0) { + let new_fields = s.fields().push_back((quote { header }, note_header_type)); + s.set_fields(new_fields); + } + + let (note_interface_impl, note_serialized_len, note_type_id) = generate_note_interface(s); + let note_properties = generate_note_properties(s); + let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, &[]); + let finalized_note = generate_finalized_note_for_complete_note(s, hiding_point_name); + // Register note here - NOTES = NOTES.push_back((s, note_serialized_len)); - //note_interface_impl. + NOTES = NOTES.push_back((s, note_serialized_len, note_type_id)); + + quote { + $note_interface_impl + $note_properties + $note_hiding_point + $finalized_note + } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index 5fd4b705fc4..d651e289d8c 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -31,7 +31,7 @@ pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, pare (quote { $struct_name::new(context, $slot, | context, slot | { $value_constructor }) }, 1) } else { let (container_struct, _) = typ.as_struct().unwrap(); - let serialized_size = if parent_is_map | container_struct.has_named_attribute(quote { note }) { + let serialized_size = if parent_is_map | container_struct.has_named_attribute("note") { 1 } else { assert( diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 8ff99522aed..c3de1299186 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -1,7 +1,7 @@ use std::meta::{typ::fresh_type_variable, unquote}; pub(crate) comptime fn get_fn_visibility(f: FunctionDefinition) -> Quoted { - if f.has_named_attribute(quote { private }) { + if f.has_named_attribute("private") { quote { private } } else { quote { public } @@ -9,15 +9,27 @@ pub(crate) comptime fn get_fn_visibility(f: FunctionDefinition) -> Quoted { } pub(crate) comptime fn is_fn_private(f: FunctionDefinition) -> bool { - f.has_named_attribute(quote { private }) + f.has_named_attribute("private") } pub(crate) comptime fn is_fn_public(f: FunctionDefinition) -> bool { - f.has_named_attribute(quote { public }) + f.has_named_attribute("public") } pub(crate) comptime fn is_fn_view(f: FunctionDefinition) -> bool { - f.has_named_attribute(quote { view }) + f.has_named_attribute("view") +} + +pub(crate) comptime fn is_fn_internal(f: FunctionDefinition) -> bool { + f.has_named_attribute("internal") +} + +pub(crate) comptime fn is_fn_initializer(f: FunctionDefinition) -> bool { + f.has_named_attribute("initializer") +} + +pub(crate) comptime fn fn_has_noinitcheck(f: FunctionDefinition) -> bool { + f.has_named_attribute("noinitcheck") } pub(crate) comptime fn fn_body_as_quoted(f: FunctionDefinition) -> Quoted { diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index aae74d02193..6cfddaeed90 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -1,6 +1,6 @@ use crate::context::{PrivateContext, PublicContext}; use crate::note::{ - note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}, + note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, utils::{compute_note_hash_for_read_request, compute_note_hash_for_nullify_internal}, note_emission::NoteEmission }; @@ -10,14 +10,13 @@ pub fn create_note( context: &mut PrivateContext, storage_slot: Field, note: &mut Note -) -> NoteEmission where Note: NoteInterface + NullifiableNote { +) -> NoteEmission where Note: NoteInterface + NullifiableNote + FinalizedNote { let contract_address = (*context).this_address(); let note_hash_counter = context.side_effect_counter; let header = NoteHeader { contract_address, storage_slot, nonce: 0, note_hash_counter }; note.set_header(header); - // TODO(#7771): inject compute_note_hash(...) func to notes with macros. - let note_hash = note.compute_note_hiding_point().x; + let note_hash = note.compute_note_hash(); let serialized_note = Note::serialize_content(*note); assert( @@ -40,13 +39,12 @@ pub fn create_note_hash_from_public( context: &mut PublicContext, storage_slot: Field, note: &mut Note -) where Note: NoteInterface + NullifiableNote { +) where Note: NoteInterface + NullifiableNote + FinalizedNote { let contract_address = (*context).this_address(); // Public note hashes are transient, but have no side effect counters, so we just need note_hash_counter != 0 let header = NoteHeader { contract_address, storage_slot, nonce: 0, note_hash_counter: 1 }; note.set_header(header); - // TODO(#7771): inject compute_note_hash(...) func to notes with macros. - let note_hash = note.compute_note_hiding_point().x; + let note_hash = note.compute_note_hash(); context.push_note_hash(note_hash); } @@ -55,7 +53,7 @@ pub fn create_note_hash_from_public( pub fn destroy_note( context: &mut PrivateContext, note: Note -) where Note: NoteInterface + NullifiableNote { +) where Note: NoteInterface + NullifiableNote + FinalizedNote { let note_hash_for_read_request = compute_note_hash_for_read_request(note); destroy_note_unsafe(context, note, note_hash_for_read_request) @@ -65,7 +63,7 @@ pub fn destroy_note_unsafe( context: &mut PrivateContext, note: Note, note_hash_for_read_request: Field -) where Note: NoteInterface + NullifiableNote { +) where Note: NoteInterface + NullifiableNote + FinalizedNote { let note_hash_for_nullify = compute_note_hash_for_nullify_internal(note, note_hash_for_read_request); let nullifier = note.compute_nullifier(context, note_hash_for_nullify); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index e97d8fd576f..651ead3d438 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -3,8 +3,8 @@ use crate::context::PrivateContext; use crate::note::{ constants::{GET_NOTE_ORACLE_RETURN_LENGTH, MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH}, note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, NoteStatus, PropertySelector}, - note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_for_read_request + note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, + note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_request }; use crate::oracle; use crate::utils::comparison::compare; @@ -79,7 +79,7 @@ fn check_notes_order( pub fn get_note( context: &mut PrivateContext, storage_slot: Field -) -> (Note, Field) where Note: NoteInterface + NullifiableNote { +) -> (Note, Field) where Note: NoteInterface + NullifiableNote + FinalizedNote { let note = unsafe { get_note_internal(storage_slot) }; @@ -98,7 +98,7 @@ pub fn get_notes( context: &mut PrivateContext, storage_slot: Field, options: NoteGetterOptions -) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + Eq { +) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + FinalizedNote + Eq { let opt_notes = unsafe { get_notes_internal(storage_slot, options) }; @@ -121,7 +121,7 @@ fn constrain_get_notes_internal; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], options: NoteGetterOptions -) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + Eq { +) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + FinalizedNote + Eq { // The filter is applied first to avoid pushing note read requests for notes we're not interested in. Note that // while the filter function can technically mutate the contents of the notes (as opposed to simply removing some), // the private kernel will later validate that these note actually exist, so transformations would cause for that diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index 9ade63d0057..221f6015145 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -2,6 +2,18 @@ use crate::context::PrivateContext; use crate::note::note_header::NoteHeader; use dep::protocol_types::point::Point; +trait NoteProperties { + fn properties() -> T; +} + +trait PartialNote { + fn compute_note_hiding_point(self) -> Point; +} + +trait FinalizedNote { + fn compute_note_hash(self) -> Field; +} + trait NullifiableNote { // This function MUST be called with the correct note hash for consumption! It will otherwise silently fail and // compute an incorrect value. @@ -23,9 +35,6 @@ trait NoteInterface { // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn deserialize_content(fields: [Field; N]) -> Self; - // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation - fn compute_note_hiding_point(self) -> Point; - // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn get_header(self) -> NoteHeader; diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 618c4e75f34..1c7888a28a4 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -1,6 +1,6 @@ use crate::{ context::PrivateContext, - note::{note_header::NoteHeader, note_interface::{NullifiableNote, NoteInterface}} + note::{note_header::NoteHeader, note_interface::{NullifiableNote, NoteInterface, FinalizedNote}} }; use dep::protocol_types::{ @@ -14,7 +14,7 @@ use dep::protocol_types::{ pub fn compute_siloed_nullifier( note_with_header: Note, context: &mut PrivateContext -) -> Field where Note: NoteInterface + NullifiableNote { +) -> Field where Note: NoteInterface + NullifiableNote + FinalizedNote { let header = note_with_header.get_header(); let note_hash_for_nullify = compute_note_hash_for_nullify(note_with_header); let inner_nullifier = note_with_header.compute_nullifier(context, note_hash_for_nullify); @@ -23,9 +23,8 @@ pub fn compute_siloed_nullifier( } // TODO(#7775): make this not impossible to understand -pub fn compute_note_hash_for_read_request(note: Note) -> Field where Note: NoteInterface + NullifiableNote { - // TODO(#7771): inject compute_note_hash(...) func to notes with macros. - let note_hash = note.compute_note_hiding_point().x; +pub fn compute_note_hash_for_read_request(note: Note) -> Field where Note: NoteInterface + NullifiableNote + FinalizedNote { + let note_hash = note.compute_note_hash(); let nonce = note.get_header().nonce; let counter = note.get_header().note_hash_counter; @@ -69,7 +68,6 @@ pub fn compute_note_hash_for_nullify_internal( // // the same transaction: (note_hash_counter != 0) & (nonce != 0) // // 3. The note was inserted in a previous transaction: (note_hash_counter == 0) & (nonce != 0) -// // TODO(#7771): inject compute_note_hash(...) func to notes with macros. // let note_hash = note.compute_note_hiding_point().x; // if header.nonce == 0 { @@ -102,7 +100,7 @@ pub fn compute_note_hash_for_nullify_internal( // } // } -pub fn compute_note_hash_for_nullify(note: Note) -> Field where Note: NoteInterface + NullifiableNote { +pub fn compute_note_hash_for_nullify(note: Note) -> Field where Note: NoteInterface + NullifiableNote + FinalizedNote { let note_hash_for_read_request = compute_note_hash_for_read_request(note); compute_note_hash_for_nullify_internal(note, note_hash_for_read_request) } @@ -112,12 +110,11 @@ pub fn compute_note_hash_and_optionally_a_nullifier( note_header: NoteHeader, compute_nullifier: bool, serialized_note: [Field; S] -) -> [Field; 4] where T: NoteInterface + NullifiableNote { +) -> [Field; 4] where T: NoteInterface + NullifiableNote + FinalizedNote { let mut note = deserialize_content(arr_copy_slice(serialized_note, [0; N], 0)); note.set_header(note_header); - // TODO(#7771): inject compute_note_hash(...) func to notes with macros. - let note_hash = note.compute_note_hiding_point().x; + let note_hash = note.compute_note_hash(); let unique_note_hash = compute_unique_note_hash(note_header.nonce, note_hash); let siloed_note_hash = compute_siloed_note_hash(note_header.contract_address, unique_note_hash); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 9f463483f03..3c6d6c77de8 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -3,8 +3,8 @@ use dep::protocol_types::{constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, use crate::context::{PrivateContext, UnconstrainedContext}; use crate::note::{ lifecycle::create_note, note_getter::{get_note, view_notes}, - note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, - note_emission::NoteEmission + note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, + note_viewer_options::NoteViewerOptions, note_emission::NoteEmission }; use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; @@ -45,7 +45,7 @@ impl PrivateImmutable { pub fn initialize( self, note: &mut Note - ) -> NoteEmission where Note: NoteInterface + NullifiableNote { + ) -> NoteEmission where Note: NoteInterface + NullifiableNote + FinalizedNote { // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); self.context.push_nullifier(nullifier); @@ -55,7 +55,7 @@ impl PrivateImmutable { // docs:end:initialize // docs:start:get_note - pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote { + pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote + FinalizedNote { let storage_slot = self.storage_slot; get_note(self.context, storage_slot).0 } @@ -72,7 +72,7 @@ impl PrivateImmutable { // view_note does not actually use the context, but it calls oracles that are only available in private // docs:start:view_note - unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote { + unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote + FinalizedNote { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(0) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index 4a1540118d4..4eec6ab22ee 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -3,8 +3,8 @@ use dep::protocol_types::{constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, use crate::context::{PrivateContext, UnconstrainedContext}; use crate::note::{ lifecycle::{create_note, destroy_note_unsafe}, note_getter::{get_note, view_notes}, - note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, - note_emission::NoteEmission + note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, + note_viewer_options::NoteViewerOptions, note_emission::NoteEmission }; use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; @@ -44,7 +44,7 @@ impl PrivateMutable { } } -impl PrivateMutable where Note: NoteInterface + NullifiableNote { +impl PrivateMutable where Note: NoteInterface + NullifiableNote + FinalizedNote { // docs:start:initialize pub fn initialize(self, note: &mut Note) -> NoteEmission { // Nullify the storage slot. @@ -103,7 +103,7 @@ impl PrivateMutable where Note: NoteInter // docs:end:get_note } -impl PrivateMutable where Note: NoteInterface + NullifiableNote { +impl PrivateMutable where Note: NoteInterface + NullifiableNote + FinalizedNote { unconstrained pub fn is_initialized(self) -> bool { let nullifier = self.compute_initialization_nullifier(); check_nullifier_exists(nullifier) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index 0eb7822218f..d8a1a6d70ea 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -4,8 +4,9 @@ use crate::note::{ constants::MAX_NOTES_PER_PAGE, lifecycle::{create_note, create_note_hash_from_public, destroy_note_unsafe}, note_getter::{get_notes, view_notes}, note_getter_options::NoteGetterOptions, - note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_for_read_request, note_emission::NoteEmission + note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, + note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_request, + note_emission::NoteEmission }; use crate::state_vars::storage::Storage; @@ -27,7 +28,7 @@ impl PrivateSet { // docs:end:new } -impl PrivateSet where Note: NoteInterface + NullifiableNote { +impl PrivateSet where Note: NoteInterface + NullifiableNote + FinalizedNote { // docs:start:insert_from_public pub fn insert_from_public(self, note: &mut Note) { create_note_hash_from_public(self.context, self.storage_slot, note); @@ -35,7 +36,7 @@ impl PrivateSet where Note: NoteInte // docs:end:insert_from_public } -impl PrivateSet where Note: NoteInterface + NullifiableNote + Eq { +impl PrivateSet where Note: NoteInterface + NullifiableNote + FinalizedNote + Eq { // docs:start:insert pub fn insert(self, note: &mut Note) -> NoteEmission { create_note(self.context, self.storage_slot, note) @@ -83,7 +84,7 @@ impl PrivateSet where Note: NoteInt } } -impl PrivateSet where Note: NoteInterface + NullifiableNote { +impl PrivateSet where Note: NoteInterface + NullifiableNote + FinalizedNote { // docs:start:view_notes unconstrained pub fn view_notes( self, diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index a752bf6d7b6..88a43625f03 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -1,18 +1,17 @@ use dep::protocol_types::{ abis::{function_selector::FunctionSelector, private_circuit_public_inputs::PrivateCircuitPublicInputs}, - address::{AztecAddress, PartialAddress}, storage::map::derive_storage_slot_in_map, - constants::CANONICAL_KEY_REGISTRY_ADDRESS, traits::Deserialize + address::AztecAddress, traits::Deserialize }; use crate::context::inputs::{PublicContextInputs, PrivateContextInputs}; use crate::context::{packed_returns::PackedReturns, call_interfaces::CallInterface}; -use crate::context::{PrivateContext, PublicContext, UnconstrainedContext, PrivateVoidCallInterface}; -use crate::test::helpers::{cheatcodes, utils::{apply_side_effects_private, Deployer, TestAccount}, keys}; +use crate::context::{PrivateContext, PublicContext, UnconstrainedContext}; +use crate::test::helpers::{cheatcodes, utils::{apply_side_effects_private, Deployer}, keys}; use crate::keys::constants::{NULLIFIER_INDEX, INCOMING_INDEX, OUTGOING_INDEX, TAGGING_INDEX}; -use crate::hash::{hash_args, hash_args_array}; +use crate::hash::hash_args; -use crate::note::{note_header::NoteHeader, note_interface::NoteInterface}; +use crate::note::{note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}}; use crate::oracle::{execution::{get_block_number, get_contract_address}, notes::notify_created_note}; struct TestEnvironment {} @@ -213,15 +212,14 @@ impl TestEnvironment { note: &mut Note, storage_slot: Field, contract_address: AztecAddress - ) where Note: NoteInterface { + ) where Note: NoteInterface + NullifiableNote + FinalizedNote { let original_contract_address = get_contract_address(); cheatcodes::set_contract_address(contract_address); let note_hash_counter = cheatcodes::get_side_effects_counter(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, note_hash_counter }; note.set_header(header); - // TODO(#7771): inject compute_note_hash(...) func to notes with macros. - let note_hash = note.compute_note_hiding_point().x; + let note_hash = note.compute_note_hash(); let serialized_note = Note::serialize_content(*note); assert( notify_created_note( diff --git a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr index 933b0c01b02..a01bde28a5d 100644 --- a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr +++ b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr @@ -3,9 +3,9 @@ use crate::{ note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_nullify} }; -use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, point::Point, traits::Eq}; +use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, traits::Eq}; use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; -use crate::note::note_interface::NullifiableNote; +use crate::note::note_interface::{NullifiableNote, FinalizedNote}; global MOCK_NOTE_LENGTH = 1; @@ -18,51 +18,56 @@ impl NullifiableNote for MockNote { fn compute_nullifier(_self: Self, _context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { // We don't use any kind of secret here since this is only a mock note and having it here would make tests // more cumbersome - poseidon2_hash_with_separator([note_hash_for_nullify], GENERATOR_INDEX__NOTE_NULLIFIER as Field) + poseidon2_hash_with_separator( + [note_hash_for_nullify], + GENERATOR_INDEX__NOTE_NULLIFIER as Field + ) } fn compute_nullifier_without_context(self) -> Field { // We don't use any kind of secret here since this is only a mock note and having it here would make tests // more cumbersome let note_hash_for_nullify = compute_note_hash_for_nullify(self); - poseidon2_hash_with_separator([note_hash_for_nullify], GENERATOR_INDEX__NOTE_NULLIFIER as Field) + poseidon2_hash_with_separator( + [note_hash_for_nullify], + GENERATOR_INDEX__NOTE_NULLIFIER as Field + ) + } +} + +impl FinalizedNote for MockNote { + fn compute_note_hash(self: Self) -> Field { + assert(self.header.storage_slot != 0, "Storage slot must be set before computing note hash"); + // We use the unsafe version because the multi_scalar_mul will constrain the scalars. + let value_scalar = from_field_unsafe(self.value); + multi_scalar_mul([G_val], [value_scalar]).x } } impl NoteInterface for MockNote { fn serialize_content(self) -> [Field; MOCK_NOTE_LENGTH] { - [self.value] + [self.value] } fn deserialize_content(fields: [Field; MOCK_NOTE_LENGTH]) -> Self { - Self { - value: fields[0], - header: NoteHeader::empty(), - } - } - - fn compute_note_hiding_point(self: Self) -> Point { - assert(self.header.storage_slot != 0, "Storage slot must be set before computing note hiding point"); - // We use the unsafe version because the multi_scalar_mul will constrain the scalars. - let value_scalar = from_field_unsafe(self.value); - multi_scalar_mul([G_val], [value_scalar]) + Self { value: fields[0], header: NoteHeader::empty() } } fn get_header(self) -> NoteHeader { - self.header + self.header } fn set_header(&mut self, header: NoteHeader) -> () { - self.header = header; + self.header = header; } fn get_note_type_id() -> Field { - // randomly chose note type id - 4135 + // randomly chose note type id + 4135 } fn to_be_bytes(self, storage_slot: Field) -> [u8; MOCK_NOTE_LENGTH * 32 + 64] { - let serialized_note = self.serialize_content(); + let serialized_note = self.serialize_content(); let mut buffer: [u8; MOCK_NOTE_LENGTH * 32 + 64] = [0; MOCK_NOTE_LENGTH * 32 + 64]; @@ -86,8 +91,7 @@ impl NoteInterface for MockNote { impl Eq for MockNote { fn eq(self, other: Self) -> bool { - (self.header == other.header) & - (self.value == other.value) + (self.header == other.header) & (self.value == other.value) } } diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index ba9e6953cea..42001cc6a4e 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -1,47 +1,23 @@ use dep::aztec::{ - generators::{Ga1 as G_amt, Ga2 as G_npk, Ga3 as G_rnd, G_slot}, - protocol_types::{ - traits::Serialize, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator, - point::{Point, POINT_LENGTH} -}, + protocol_types::{traits::Serialize, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, macros::notes::note, - note::{ - note_header::NoteHeader, note_interface::{NullifiableNote, NoteInterface}, - note_getter_options::PropertySelector, utils::compute_note_hash_for_nullify -}, + note::{note_header::NoteHeader, note_interface::NullifiableNote, utils::compute_note_hash_for_nullify}, oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext }; -use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; global VALUE_NOTE_LEN: u64 = 3; // 3 plus a header. // docs:start:value-note-def +#[derive(Serialize)] #[note] struct ValueNote { value: Field, // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. npk_m_hash: Field, randomness: Field, - header: NoteHeader } // docs:end:value-note-def -struct ValueNoteProperties { - value: PropertySelector, - npk_m_hash: PropertySelector, - randomness: PropertySelector, -} - -impl ValueNote { - fn properties() -> ValueNoteProperties { - ValueNoteProperties { - value: PropertySelector { index: 0, offset: 0, length: 32 }, - npk_m_hash: PropertySelector { index: 1, offset: 0, length: 32 }, - randomness: PropertySelector { index: 2, offset: 0, length: 32 } - } - } -} - impl NullifiableNote for ValueNote { // docs:start:nullifier @@ -71,97 +47,12 @@ impl NullifiableNote for ValueNote { } } -impl NoteInterface for ValueNote { - - fn to_be_bytes(self, storage_slot: Field) -> [u8; VALUE_NOTE_LEN * 32 + 64] { - let serialized_note = self.serialize_content(); - - let mut buffer: [u8; VALUE_NOTE_LEN * 32 + 64] = [0; VALUE_NOTE_LEN * 32 + 64]; - - let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); - let note_type_id_bytes: [u8; 32] = ValueNote::get_note_type_id().to_be_bytes(); - - for i in 0..32 { - { - buffer[i] = storage_slot_bytes[i]; - buffer[32 + i] = note_type_id_bytes[i]; - } - } - - for i in 0..serialized_note.len() { - { - let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); - for j in 0..32 { - { - buffer[64 + i * 32 + j] = bytes[j]; - } - } - } - } - buffer - } - - fn deserialize_content(fields: [Field; VALUE_NOTE_LEN]) -> Self { - ValueNote { value: fields[0], npk_m_hash: fields[1], randomness: fields[2], header: NoteHeader::empty() } - } - - fn serialize_content(self) -> [Field; VALUE_NOTE_LEN] { - [self.value, self.npk_m_hash, self.randomness] - } - - fn get_note_type_id() -> Field { - 1 - } - - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - - fn compute_note_hiding_point(self) -> Point { - // We use the unsafe version because the multi_scalar_mul will constrain the scalars. - let amount_scalar = from_field_unsafe(self.value); - let npk_m_hash_scalar = from_field_unsafe(self.npk_m_hash); - let randomness_scalar = from_field_unsafe(self.randomness); - let slot_scalar = from_field_unsafe(self.header.storage_slot); - // We compute the note hiding point as: - // `G_amt * amount + G_npk * npk_m_hash + G_rnd * randomness + G_slot * slot` - // instead of using pedersen or poseidon2 because it allows us to privately add and subtract from amount - // in public by leveraging homomorphism. - multi_scalar_mul( - [G_amt, G_npk, G_rnd, G_slot], - [amount_scalar, npk_m_hash_scalar, randomness_scalar, slot_scalar] - ) - } -} - impl ValueNote { pub fn new(value: Field, npk_m_hash: Field) -> Self { let randomness = unsafe_rand(); let header = NoteHeader::empty(); ValueNote { value, npk_m_hash, randomness, header } } - - // TODO: Merge this func with `compute_note_hiding_point`. I (benesjan) didn't do it in the initial PR to not have - // to modify macros and all the related funcs in it. - fn to_note_hiding_point(self) -> ValueNoteHidingPoint { - ValueNoteHidingPoint::new(self.compute_note_hiding_point()) - } -} - -impl Serialize<7> for ValueNote { - /// The following method needed to be implemented because the note is passed as an argument to a contract function - /// --> the serialize method is called by aztec-nr when computing an arguments hash. - /// Note that when the note is about to be encrypted and emitted as a log the to_be_bytes function auto-implemented - /// by aztec macros is called instead. - fn serialize(self) -> [Field; 7] { - let header = self.header.serialize(); - - [self.value, self.npk_m_hash, self.randomness, header[0], header[1], header[2], header[3]] - } } impl Eq for ValueNote { @@ -171,39 +62,3 @@ impl Eq for ValueNote { & (self.randomness == other.randomness) } } - -struct ValueNoteHidingPoint { - inner: Point -} - -impl ValueNoteHidingPoint { - fn new(point: Point) -> Self { - Self { inner: point } - } - - fn add_value(&mut self, value: U128) { - self.inner = multi_scalar_mul([G_amt], [from_field_unsafe(value.to_integer())]) + self.inner; - } - - fn add_npk_m_hash(&mut self, npk_m_hash: Field) { - self.inner = multi_scalar_mul([G_npk], [from_field_unsafe(npk_m_hash)]) + self.inner; - } - - fn add_randomness(&mut self, randomness: Field) { - self.inner = multi_scalar_mul([G_rnd], [from_field_unsafe(randomness)]) + self.inner; - } - - fn add_slot(&mut self, slot: Field) { - self.inner = multi_scalar_mul([G_slot], [from_field_unsafe(slot)]) + self.inner; - } - - fn finalize(self) -> Field { - self.inner.x - } -} - -impl Serialize for ValueNoteHidingPoint { - fn serialize(self) -> [Field; POINT_LENGTH] { - self.inner.serialize() - } -} diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index f001ddfe652..9a012573d71 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -1,6 +1,6 @@ -use dep::aztec::macros::aztec_contract; +use dep::aztec::macros::aztec; -#[aztec_contract] +#[aztec] contract Counter { // docs:start:imports use aztec::prelude::{AztecAddress, Map}; diff --git a/noir-projects/noir-contracts/contracts/router_contract/src/main.nr b/noir-projects/noir-contracts/contracts/router_contract/src/main.nr index 0b229474e8f..1ea96c506ae 100644 --- a/noir-projects/noir-contracts/contracts/router_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/router_contract/src/main.nr @@ -1,12 +1,12 @@ mod test; mod utils; -use aztec::macros::aztec_contract; +use dep::aztec::macros::aztec; /// The purpose of this contract is to perform a check in public without revealing what contract enqued the public /// call. This is achieved by having a private function on this contract that enques the public call and hence /// the `msg_sender` in the public call is the address of this contract. -#[aztec_contract] +#[aztec] contract Router { use aztec::{macros::functions::{private, public}, utils::comparison::compare}; diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index 1e543e3d4ad..fb04609edc0 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -1,6 +1,6 @@ // docs:start:token_types_all use dep::aztec::{ - note::{note_getter_options::PropertySelector, utils::compute_note_hash_for_nullify}, + utils::compute_note_hash_for_nullify}, prelude::{NoteHeader, NoteInterface, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; @@ -50,7 +50,7 @@ impl NoteInterface for Transpa // 1) We pass the secret as an argument to the function and use it to compute a secret hash, // 2) we fetch a note via the "get_notes" oracle which accepts the secret hash as an argument, // 3) the "get_notes" oracle constrains that the secret hash in the returned note matches the one computed in - // circuit. + // circuit. // This achieves that the note can only be spent by the party that knows the secret. fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_nullify(self); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 7b08330c36f..a4428215c8e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -1,55 +1,59 @@ use super::traits::Serialize; +use std::meta::type_of; -pub(crate) comptime fn flatten_to_fields(name: Quoted, typ: Type) -> ([Quoted], [Quoted]) { +pub comptime fn flatten_to_fields(name: Quoted, typ: Type, omit: [Quoted]) -> ([Quoted], [Quoted]) { let mut fields = &[]; let mut aux_vars = &[]; - if typ.is_field() | typ.as_integer().is_some() { - fields = fields.push_back(quote { $name as Field }); - } else if typ.as_struct().is_some() { - let nested_struct = typ.as_struct().unwrap(); - let params = nested_struct.0.fields(); - let struct_flattened = params.map( - | (param_name, param_type): (Quoted, Type) | flatten_to_fields(quote {$name.$param_name}, param_type) - ); - let struct_flattened_fields = struct_flattened.fold( - &[], - | acc: [Quoted], (fields, _): (_, [Quoted]) | acc.append(fields) - ); - let struct_flattened_aux_vars = struct_flattened.fold( - &[], - |acc: [Quoted], (_, aux_vars): ([Quoted], _) | acc.append(aux_vars) - ); - fields = fields.append(struct_flattened_fields); - aux_vars = aux_vars.append(struct_flattened_aux_vars); - } else if typ.as_array().is_some() { - let (element_type, array_len) = typ.as_array().unwrap(); - let array_len = array_len.as_constant().unwrap(); - for i in 0..array_len { - let (element_fields, element_aux_vars) = flatten_to_fields(quote { $name[$i] }, element_type); - fields = fields.append(element_fields); - aux_vars = aux_vars.append(element_aux_vars); - } - } else if typ.as_str().is_some() { - let length_type = typ.as_str().unwrap(); - let str_len = length_type.as_constant().unwrap(); - let var_name = name.as_expr().unwrap().as_member_access().unwrap().1; - let as_bytes_name = f"{var_name}_as_bytes".quoted_contents(); - let as_bytes = quote { let $as_bytes_name = $name.as_bytes() }; - for i in 0..str_len { - fields = fields.push_back(quote { $as_bytes_name[$i] as Field } ); + + if omit.all(| to_omit | to_omit != name) { + if typ.is_field() | typ.as_integer().is_some() { + fields = fields.push_back(quote { $name as Field }); + } else if typ.as_struct().is_some() { + let nested_struct = typ.as_struct().unwrap(); + let params = nested_struct.0.fields(); + let struct_flattened = params.map( + | (param_name, param_type): (Quoted, Type) | flatten_to_fields(quote {$name.$param_name}, param_type, omit) + ); + let struct_flattened_fields = struct_flattened.fold( + &[], + | acc: [Quoted], (fields, _): (_, [Quoted]) | acc.append(fields) + ); + let struct_flattened_aux_vars = struct_flattened.fold( + &[], + |acc: [Quoted], (_, aux_vars): ([Quoted], _) | acc.append(aux_vars) + ); + fields = fields.append(struct_flattened_fields); + aux_vars = aux_vars.append(struct_flattened_aux_vars); + } else if typ.as_array().is_some() { + let (element_type, array_len) = typ.as_array().unwrap(); + let array_len = array_len.as_constant().unwrap(); + for i in 0..array_len { + let (element_fields, element_aux_vars) = flatten_to_fields(quote { $name[$i] }, element_type, omit); + fields = fields.append(element_fields); + aux_vars = aux_vars.append(element_aux_vars); + } + } else if typ.as_str().is_some() { + let length_type = typ.as_str().unwrap(); + let str_len = length_type.as_constant().unwrap(); + let var_name = name.as_expr().unwrap().as_member_access().unwrap().1; + let as_bytes_name = f"{var_name}_as_bytes".quoted_contents(); + let as_bytes = quote { let $as_bytes_name = $name.as_bytes() }; + for i in 0..str_len { + fields = fields.push_back(quote { $as_bytes_name[$i] as Field } ); + } + aux_vars = aux_vars.push_back(as_bytes); + } else { + assert(false, f"Unsupported type for serialization of argument {name} and type {typ}"); + std::mem::zeroed() } - aux_vars = aux_vars.push_back(as_bytes); - } else { - assert(false, f"Unsupported type for serialization of argument {name} and type {typ}"); - std::mem::zeroed() } (fields, aux_vars) } pub(crate) comptime fn derive_serialize(s: StructDefinition) -> Quoted { let typ = s.as_type(); - let (fields, aux_vars) = flatten_to_fields(quote { self }, typ); - let aux_vars_quote = if aux_vars.len() > 0 { + let (fields, aux_vars) = flatten_to_fields(quote { self }, typ, &[]); + let aux_vars_for_serialization = if aux_vars.len() > 0 { let joint = aux_vars.join(quote {;}); quote { $joint; } } else { @@ -61,7 +65,7 @@ pub(crate) comptime fn derive_serialize(s: StructDefinition) -> Quoted { quote { impl Serialize<$serialized_len> for $typ { fn serialize(self) -> [Field; $serialized_len] { - $aux_vars_quote + $aux_vars_for_serialization [ $field_serializations ] } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr index fe54c0e750b..b428d7795e0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr @@ -16,13 +16,37 @@ trait Empty { fn empty() -> Self; } -impl Empty for Field { fn empty() -> Self {0} } +impl Empty for Field { + fn empty() -> Self { + 0 + } +} -impl Empty for u1 { fn empty() -> Self {0} } -impl Empty for u8 { fn empty() -> Self {0} } -impl Empty for u32 { fn empty() -> Self {0} } -impl Empty for u64 { fn empty() -> Self {0} } -impl Empty for U128 { fn empty() -> Self {U128::from_integer(0)} } +impl Empty for u1 { + fn empty() -> Self { + 0 + } +} +impl Empty for u8 { + fn empty() -> Self { + 0 + } +} +impl Empty for u32 { + fn empty() -> Self { + 0 + } +} +impl Empty for u64 { + fn empty() -> Self { + 0 + } +} +impl Empty for U128 { + fn empty() -> Self { + U128::from_integer(0) + } +} pub fn is_empty(item: T) -> bool where T: Empty + Eq { item.eq(T::empty()) @@ -46,11 +70,31 @@ impl ToField for Field { } } -impl ToField for bool { fn to_field(self) -> Field { self as Field } } -impl ToField for u1 { fn to_field(self) -> Field { self as Field } } -impl ToField for u8 { fn to_field(self) -> Field { self as Field } } -impl ToField for u32 { fn to_field(self) -> Field { self as Field } } -impl ToField for u64 { fn to_field(self) -> Field { self as Field } } +impl ToField for bool { + fn to_field(self) -> Field { + self as Field + } +} +impl ToField for u1 { + fn to_field(self) -> Field { + self as Field + } +} +impl ToField for u8 { + fn to_field(self) -> Field { + self as Field + } +} +impl ToField for u32 { + fn to_field(self) -> Field { + self as Field + } +} +impl ToField for u64 { + fn to_field(self) -> Field { + self as Field + } +} impl ToField for U128 { fn to_field(self) -> Field { self.to_integer() @@ -73,11 +117,31 @@ impl FromField for Field { } } -impl FromField for bool { fn from_field(value: Field) -> Self { value as bool } } -impl FromField for u1 { fn from_field(value: Field) -> Self { value as u1 } } -impl FromField for u8 { fn from_field(value: Field) -> Self { value as u8 } } -impl FromField for u32 { fn from_field(value: Field) -> Self { value as u32 } } -impl FromField for u64 { fn from_field(value: Field) -> Self { value as u64 } } +impl FromField for bool { + fn from_field(value: Field) -> Self { + value as bool + } +} +impl FromField for u1 { + fn from_field(value: Field) -> Self { + value as u1 + } +} +impl FromField for u8 { + fn from_field(value: Field) -> Self { + value as u8 + } +} +impl FromField for u32 { + fn from_field(value: Field) -> Self { + value as u32 + } +} +impl FromField for u64 { + fn from_field(value: Field) -> Self { + value as u64 + } +} impl FromField for U128 { fn from_field(value: Field) -> Self { U128::from_integer(value) From 4e81f4d856b37baa295f1e8b721076152cf24a95 Mon Sep 17 00:00:00 2001 From: thunkar Date: Fri, 13 Sep 2024 20:03:42 +0000 Subject: [PATCH 09/79] towards token_contract --- .../aztec/src/macros/functions/mod.nr | 27 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 28 +- .../aztec-nr/aztec/src/macros/storage/mod.nr | 28 +- .../aztec-nr/aztec/src/macros/utils.nr | 31 +- noir-projects/aztec-nr/aztec/src/prelude.nr | 4 +- .../contracts/counter_contract/src/main.nr | 15 +- .../contracts/token_contract/src/main.nr | 1104 ++++++++--------- .../token_contract/src/types/balance_set.nr | 26 +- .../token_contract/src/types/token_note.nr | 101 +- .../src/types/transparent_note.nr | 50 +- .../crates/types/src/meta/mod.nr | 93 +- .../crates/types/src/traits.nr | 3 +- .../crates/types/src/type_serialization.nr | 1 - 13 files changed, 723 insertions(+), 788 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index e7da8422ea4..7e2149d5999 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -51,7 +51,7 @@ comptime fn create_mark_as_initialized(f: FunctionDefinition) -> Quoted { comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { let name = f.name(); // Remove first arg (inputs) - let mut parameters = f.parameters().pop_front().1.map( + let mut parameters = f.parameters().map( | (name, typ): (Quoted, Type) | { quote { $name: $typ } } @@ -90,7 +90,6 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { let fn_abi = create_fn_abi_export(f); let fn_stub = stub_fn(f); STUBS = STUBS.push_back(fn_stub); - let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| is_fn_initializer(f)); let module_has_storage = f.module().structs().any(|s: StructDefinition| s.has_named_attribute("storage")); @@ -149,13 +148,16 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { let return_value = if return_value_type != type_of(()) { let (body_without_return, return_value) = body.pop_back(); let return_value = return_value.quoted(); + let return_value_var_name = quote { macro__returned__values }; + let return_value_assignment = quote { let $return_value_var_name = $return_value; }; let return_hasher_name = quote { return_hasher }; - let return_value_into_hasher = add_to_hasher(return_hasher_name, return_value, return_value_type); + let return_value_into_hasher = add_to_hasher(return_hasher_name, return_value_var_name, return_value_type); body = body_without_return; quote { - let $return_hasher_name = dep::aztec::hash::ArgsHasher::new(); + let mut $return_hasher_name = dep::aztec::hash::ArgsHasher::new(); + $return_value_assignment $return_value_into_hasher context.set_return_hash($return_hasher_name); } @@ -180,13 +182,14 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { $mark_as_initialized $context_finish }; - - modify_fn_body(f, to_prepend, to_append); + let modified_body = modify_fn_body(body, to_prepend, to_append); + f.set_body(modified_body); f.add_attribute("recursive"); f.set_return_public(true); f.set_return_type( quote { dep::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs }.as_type() ); + fn_abi } @@ -194,7 +197,6 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { let fn_abi = create_fn_abi_export(f); let fn_stub = stub_fn(f); STUBS = STUBS.push_back(fn_stub); - let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| is_fn_initializer(f)); let module_has_storage = f.module().structs().any(|s: StructDefinition| s.has_named_attribute("storage")); @@ -246,9 +248,13 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { $mark_as_initialized }; - modify_fn_body(f, to_prepend, to_append); + let body = f.body().as_block().unwrap(); + let modified_body = modify_fn_body(body, to_prepend, to_append); + f.set_body(modified_body); + f.set_unconstrained(true); f.set_return_public(true); + fn_abi } @@ -265,8 +271,9 @@ pub comptime fn transform_unconstrained(f: FunctionDefinition) { $context_creation $storage_init }; - - modify_fn_body(f, to_prepend, quote {}); + let body = f.body().as_block().unwrap(); + let modified_body = modify_fn_body(body, to_prepend, quote {}); + f.set_body(modified_body); } pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index da1562ac6d9..21eb11bdea9 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -1,6 +1,7 @@ use std::meta::{type_of, unquote}; use protocol_types::{meta::flatten_to_fields, utils::field::field_from_bytes}; use crate::note::{note_header::NoteHeader, note_getter_options::PropertySelector}; +use protocol_types::meta::pack_from_fields; comptime mut global NOTES = &[]; @@ -35,24 +36,20 @@ comptime fn generate_note_interface(s: StructDefinition) -> (Quoted, u32, Field) let serialized_fields = fields.join(quote {,}); let content_len = fields.len(); - let mut deserialized_fields = &[]; - let note_header_type = quote { crate::note::note_header::NoteHeader}.as_type(); - let mut field_counter: u64 = 0; - for field in s.fields() { - let (name, typ) = field; - if typ != note_header_type { - deserialized_fields = deserialized_fields.push_back(quote { $name: fields[$field_counter] }); - } - field_counter+= 1; - } - let deserialized_content = deserialized_fields.join(quote {,}); + let (deserialized_content, _) = pack_from_fields( + quote { self }, + typ, + quote { value }, + 0, + &[(quote {header}, quote { NoteHeader::empty() })] + ); let note_type_id = compute_note_type_id(name); (quote { - impl aztec::note::note_interface::NoteInterface<$content_len> for ValueNote { + impl aztec::note::note_interface::NoteInterface<$content_len> for $name { fn to_be_bytes(self, storage_slot: Field) -> [u8; $content_len * 32 + 64] { let serialized_note = self.serialize_content(); @@ -75,11 +72,8 @@ comptime fn generate_note_interface(s: StructDefinition) -> (Quoted, u32, Field) buffer } - fn deserialize_content(fields: [Field; $content_len]) -> Self { - $name { - $deserialized_content, - header: NoteHeader::empty() - } + fn deserialize_content(value: [Field; $content_len]) -> Self { + $deserialized_content } fn serialize_content(self) -> [Field; $content_len] { diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index d651e289d8c..fd0683c1e58 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -21,7 +21,7 @@ pub comptime fn is_storage_map(typ: Type) -> bool { pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map: bool) -> (Quoted, u32) { assert( - typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container`, or Map" + typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container<_, Context>`, or Map" ); let (container_struct, generics) = typ.as_struct().unwrap(); let struct_name = container_struct.name(); @@ -30,16 +30,28 @@ pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, pare let (value_constructor, _) = generate_storage_field_constructor(generics[1], quote { slot }, true); (quote { $struct_name::new(context, $slot, | context, slot | { $value_constructor }) }, 1) } else { - let (container_struct, _) = typ.as_struct().unwrap(); - let serialized_size = if parent_is_map | container_struct.has_named_attribute("note") { + let (container_struct, container_struct_generics) = typ.as_struct().unwrap(); + let container_struct_name = container_struct.name(); + // Whatever's stored in a map occupies "a single slot" + let serialized_size = if parent_is_map { 1 } else { assert( - container_struct.generics().len() != 2, "Storable containers must be generic over a serializable type and Context" + container_struct_generics.len() == 2, f"Failed to process {container_struct_name}: Storable containers must be generic over a serializable type and Context" ); - let stored_struct = container_struct.generics()[0]; - assert(stored_struct.as_struct().is_some(), "Storable items must be Serializable structs"); - get_serialized_size(stored_struct) + let stored_struct = container_struct_generics[0]; + let is_note = if stored_struct.as_struct().is_some() { + let (def, _) = stored_struct.as_struct().unwrap(); + def.has_named_attribute("note") + } else { + false + }; + // Private notes always occupy a single slot. Someone could store a Note in PublicMutable for whatever reason though. + if is_note & (container_struct_name != quote { PublicMutable }) { + 1 + } else { + get_serialized_size(stored_struct) + } }; (quote { $struct_name::new(context, $slot)}, serialized_size) } @@ -80,7 +92,7 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { storage_layout_constructors = storage_layout_constructors.push_back(quote { $name: dep::aztec::prelude::Storable { slot: $slot } }); //let with_context_generic = add_context_generic(typ, context_generic); //println(with_context_generic); - //new_storage_fields = new_storage_fields.push_back((name, with_context_generic )); + //new_storage_fields = new_storage_fields.push_back((name, with_context_generic ));ç slot += serialized_size; } diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index c3de1299186..955043d1618 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -32,10 +32,8 @@ pub(crate) comptime fn fn_has_noinitcheck(f: FunctionDefinition) -> bool { f.has_named_attribute("noinitcheck") } -pub(crate) comptime fn fn_body_as_quoted(f: FunctionDefinition) -> Quoted { - let body = f.body().as_block(); - assert(body.is_some(), "Function body must be a block"); - body.unwrap().fold( +pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quoted) -> Expr { + let mut body_quote = body.fold( quote {}, |body_quote, expr: Expr| { let expr_quote = expr.quoted(); @@ -44,11 +42,7 @@ pub(crate) comptime fn fn_body_as_quoted(f: FunctionDefinition) -> Quoted { $expr_quote } } - ) -} - -pub(crate) comptime fn modify_fn_body(f: FunctionDefinition, prepend: Quoted, append: Quoted) { - let mut body_quote = fn_body_as_quoted(f); + ); body_quote = quote { { $prepend @@ -57,8 +51,11 @@ pub(crate) comptime fn modify_fn_body(f: FunctionDefinition, prepend: Quoted, ap } }; let body_expr = body_quote.as_expr(); + if !body_expr.is_some() { + println(body_quote); + } assert(body_expr.is_some(), "Body is not an expression"); - f.set_body(body_expr.unwrap()); + body_expr.unwrap() } pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: Type) -> Quoted { @@ -77,7 +74,7 @@ pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: } } else if typ.as_str().is_some() { quote { - $slice_name = $slice_name.append($name.to_bytes()); + $slice_name = $slice_name.append($name.as_bytes().map(| byte: u8 | byte as Field).as_slice()); } } else { assert(false, f"Cannot add to slice: unsupported type {typ} variable {name}"); @@ -96,12 +93,12 @@ pub(crate) comptime fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Typ quote { let $serialized_name = $name.map(|x: $element_type | x.serialize()); for i in 0..$name.len() { - args_acc = args_acc.append($serialized_name[i].as_slice()); + $hasher_name.add_multiple($serialized_name[i]); } } } else if typ.as_str().is_some() { quote { - $hasher_name.add_multiple($name.to_bytes()); + $hasher_name.add_multiple($name.as_bytes().map(| byte: u8 | byte as Field)); } } else { assert(false, f"Cannot add to hasher: unsupported type {typ} of variable {name}"); @@ -144,6 +141,8 @@ comptime fn signature_of_type(typ: Type) -> Quoted { } ).join(quote {,}); f"({field_signatures})".quoted_contents() + } else if typ.is_bool() { + quote {bool} } else { assert(false, f"Unsupported type {typ}"); std::mem::zeroed() @@ -196,8 +195,10 @@ pub(crate) comptime fn compute_fn_selector(f: FunctionDefinition) -> Field { pub(crate) comptime fn get_serialized_size(typ: Type) -> u32 { let any = fresh_type_variable(); - let maybe_serialize_impl = typ.get_trait_impl(quote { Serialize<$any> }.as_trait_constraint()); - assert(maybe_serialize_impl.is_some(), "Storable items must implement Serialize"); + let maybe_serialize_impl = typ.get_trait_impl(quote { protocol_types::traits::Serialize<$any> }.as_trait_constraint()); + assert( + maybe_serialize_impl.is_some(), f"Storable items must implement Serialize. Trait impl not found for {typ}" + ); let serialize_impl = maybe_serialize_impl.unwrap(); serialize_impl.trait_generic_args()[0].as_constant().unwrap() } diff --git a/noir-projects/aztec-nr/aztec/src/prelude.nr b/noir-projects/aztec-nr/aztec/src/prelude.nr index 21bac4ea1b4..793550c5668 100644 --- a/noir-projects/aztec-nr/aztec/src/prelude.nr +++ b/noir-projects/aztec-nr/aztec/src/prelude.nr @@ -11,8 +11,8 @@ pub use crate::{ }, context::{PrivateContext, PackedReturns, FunctionReturns}, note::{ - note_header::NoteHeader, note_interface::NoteInterface, note_getter_options::NoteGetterOptions, - note_viewer_options::NoteViewerOptions, + note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}, + note_getter_options::NoteGetterOptions, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_and_optionally_a_nullifier as utils_compute_note_hash_and_optionally_a_nullifier } }; diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 9a012573d71..5156ab14d94 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -28,12 +28,23 @@ contract Counter { // docs:start:increment #[private] - fn increment(owner: AztecAddress, outgoing_viewer: AztecAddress) { + fn increment(owner: AztecAddress, outgoing_viewer: AztecAddress) -> Field { + let mut args_hasher = dep::aztec::hash::ArgsHasher::new(); + args_hasher.add_multiple(owner.serialize()); + args_hasher.add_multiple(outgoing_viewer.serialize()); + let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); + dep::aztec::initializer::assert_is_initialized_private(&mut context); + let storage = Storage::init(&mut context); unsafe { dep::aztec::oracle::debug_log::debug_log_format("Incrementing counter for owner {0}", [owner.to_field()]); } - let counters = storage.counters; + let counters: unspecified = (storage.counters); counters.at(owner).add(1, owner, outgoing_viewer); + let mut return_hasher = dep::aztec::hash::ArgsHasher::new(); + let macro__returned__values = 1; + return_hasher.add(macro__returned__values as Field); + context.set_return_hash(return_hasher); + context.finish() } // docs:end:increment diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 1bcba8c0d32..acb0690fed5 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -1,7 +1,9 @@ // docs:start:token_all // docs:start:imports mod types; -mod test; +//mod test; + +use dep::aztec::macros::aztec; // Minimal token implementation that supports `AuthWit` accounts. // The auth message follows a similar pattern to the cross-chain message and includes a designated caller. @@ -9,7 +11,7 @@ mod test; // message hash = H([caller, contract, selector, ...args]) // To be read as `caller` calls function at `contract` defined by `selector` with `args` // Including a nonce in the message hash ensures that the message can only be used once. - +#[aztec] contract Token { // Libs @@ -25,17 +27,15 @@ contract Token { encrypted_note_emission::{encode_and_encrypt_note_with_keys, encode_and_encrypt_note_with_keys_unconstrained}, encrypted_event_emission::encode_and_encrypt_event_with_keys_unconstrained }, - keys::getters::get_current_public_keys + keys::getters::get_current_public_keys, + macros::{storage::storage, functions::{initializer, private, view, public}} }; // docs:start:import_authwit use dep::authwit::auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public, compute_authwit_nullifier}; // docs:end:import_authwit - use crate::types::{ - transparent_note::TransparentNote, token_note::{TokenNote, TokenNoteHidingPoint}, - balance_set::BalanceSet - }; + use crate::types::{transparent_note::TransparentNote, token_note::TokenNote, balance_set::BalanceSet}; // docs:end::imports // In the first transfer iteration we are computing a lot of additional information (validating inputs, retrieving @@ -55,604 +55,532 @@ contract Token { } // docs:start:storage_struct - #[aztec(storage)] - struct Storage { + #[storage] + struct Storage { // docs:start:storage_admin - admin: PublicMutable, + admin: PublicMutable, // docs:end:storage_admin // docs:start:storage_minters - minters: Map>, + minters: Map, Context>, // docs:end:storage_minters // docs:start:storage_balances - balances: Map>, + balances: Map, Context>, // docs:end:storage_balances - total_supply: PublicMutable, + total_supply: PublicMutable, // docs:start:storage_pending_shields - pending_shields: PrivateSet, + pending_shields: PrivateSet, // docs:end:storage_pending_shields - public_balances: Map>, - symbol: SharedImmutable, - name: SharedImmutable, + public_balances: Map, Context>, + symbol: SharedImmutable, + name: SharedImmutable, // docs:start:storage_decimals - decimals: SharedImmutable, + decimals: SharedImmutable, // docs:end:storage_decimals } // docs:end:storage_struct // docs:start:constructor - #[aztec(public)] - #[aztec(initializer)] - fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { - assert(!admin.is_zero(), "invalid admin"); - storage.admin.write(admin); - storage.minters.at(admin).write(true); - storage.name.initialize(FieldCompressedString::from_string(name)); - storage.symbol.initialize(FieldCompressedString::from_string(symbol)); - // docs:start:initialize_decimals - storage.decimals.initialize(decimals); - // docs:end:initialize_decimals - } - // docs:end:constructor - - // docs:start:set_admin - #[aztec(public)] - fn set_admin(new_admin: AztecAddress) { - assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin"); - // docs:start:write_admin - storage.admin.write(new_admin); - // docs:end:write_admin - } + // #[public] + // #[initializer] + // fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { + // assert(!admin.is_zero(), "invalid admin"); + // storage.admin.write(admin); + // storage.minters.at(admin).write(true); + // storage.name.initialize(FieldCompressedString::from_string(name)); + // storage.symbol.initialize(FieldCompressedString::from_string(symbol)); + // // docs:start:initialize_decimals + // storage.decimals.initialize(decimals); + // // docs:end:initialize_decimals + // } + // // docs:end:constructor + // // docs:start:set_admin + // #[public] + // fn set_admin(new_admin: AztecAddress) { + // assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin"); + // // docs:start:write_admin + // storage.admin.write(new_admin); + // // docs:end:write_admin + // } // docs:end:set_admin - - #[aztec(public)] - #[aztec(view)] - fn public_get_name() -> pub FieldCompressedString { - storage.name.read_public() - } - - #[aztec(private)] - #[aztec(view)] - fn private_get_name() -> pub FieldCompressedString { + // #[public] + // #[view] + // fn public_get_name() -> FieldCompressedString { + // storage.name.read_public() + // } + + #[private] + #[view] + fn private_get_name() -> FieldCompressedString { storage.name.read_private() } - - #[aztec(public)] - #[aztec(view)] - fn public_get_symbol() -> pub FieldCompressedString { - storage.symbol.read_public() - } - - #[aztec(private)] - #[aztec(view)] - fn private_get_symbol() -> pub FieldCompressedString { - storage.symbol.read_private() - } - - #[aztec(public)] - #[aztec(view)] - fn public_get_decimals() -> pub u8 { - // docs:start:read_decimals_public - storage.decimals.read_public() - // docs:end:read_decimals_public - } - - #[aztec(private)] - #[aztec(view)] - fn private_get_decimals() -> pub u8 { - // docs:start:read_decimals_private - storage.decimals.read_private() - // docs:end:read_decimals_private - } - - // docs:start:admin - #[aztec(public)] - #[aztec(view)] - fn admin() -> Field { - storage.admin.read().to_field() - } - // docs:end:admin - - // docs:start:is_minter - #[aztec(public)] - #[aztec(view)] - fn is_minter(minter: AztecAddress) -> bool { - storage.minters.at(minter).read() - } - // docs:end:is_minter - - // docs:start:total_supply - #[aztec(public)] - #[aztec(view)] - fn total_supply() -> Field { - storage.total_supply.read().to_integer() - } - // docs:end:total_supply - - // docs:start:balance_of_public - #[aztec(public)] - #[aztec(view)] - fn balance_of_public(owner: AztecAddress) -> Field { - storage.public_balances.at(owner).read().to_integer() - } - // docs:end:balance_of_public - - // docs:start:set_minter - #[aztec(public)] - fn set_minter(minter: AztecAddress, approve: bool) { - // docs:start:read_admin - assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin"); - // docs:end:read_admin - // docs:start:write_minter - storage.minters.at(minter).write(approve); - // docs:end:write_minter - } - // docs:end:set_minter - - // docs:start:mint_public - #[aztec(public)] - fn mint_public(to: AztecAddress, amount: Field) { - // docs:start:read_minter - assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); - // docs:end:read_minter - let amount = U128::from_integer(amount); - let new_balance = storage.public_balances.at(to).read().add(amount); - let supply = storage.total_supply.read().add(amount); - - storage.public_balances.at(to).write(new_balance); - storage.total_supply.write(supply); - } - // docs:end:mint_public - - // docs:start:mint_private - #[aztec(public)] - fn mint_private(amount: Field, secret_hash: Field) { - assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); - let pending_shields = storage.pending_shields; - let mut note = TransparentNote::new(amount, secret_hash); - let supply = storage.total_supply.read().add(U128::from_integer(amount)); - - storage.total_supply.write(supply); - // docs:start:insert_from_public - pending_shields.insert_from_public(&mut note); - // docs:end:insert_from_public - } - // docs:end:mint_private - - // TODO: Nuke this - test functions do not belong to token contract! - #[aztec(private)] - fn privately_mint_private_note(amount: Field) { - let caller = context.msg_sender(); - let caller_keys = get_current_public_keys(&mut context, caller); - storage.balances.at(caller).add(caller_keys.npk_m, U128::from_integer(amount)).emit( - encode_and_encrypt_note_with_keys(&mut context, caller_keys.ovpk_m, caller_keys.ivpk_m, caller) - ); - - Token::at(context.this_address()).assert_minter_and_mint(context.msg_sender(), amount).enqueue(&mut context); - } - - #[aztec(public)] - #[aztec(internal)] - fn assert_minter_and_mint(minter: AztecAddress, amount: Field) { - assert(storage.minters.at(minter).read(), "caller is not minter"); - let supply = storage.total_supply.read() + U128::from_integer(amount); - storage.total_supply.write(supply); - } - - // docs:start:shield - #[aztec(public)] - fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) { - if (!from.eq(context.msg_sender())) { - // The redeem is only spendable once, so we need to ensure that you cannot insert multiple shields from the same message. - assert_current_call_valid_authwit_public(&mut context, from); - } else { - assert(nonce == 0, "invalid nonce"); - } - - let amount = U128::from_integer(amount); - let from_balance = storage.public_balances.at(from).read().sub(amount); - - let pending_shields = storage.pending_shields; - let mut note = TransparentNote::new(amount.to_field(), secret_hash); - - storage.public_balances.at(from).write(from_balance); - pending_shields.insert_from_public(&mut note); - } - // docs:end:shield - - // docs:start:transfer_public - #[aztec(public)] - fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { - if (!from.eq(context.msg_sender())) { - assert_current_call_valid_authwit_public(&mut context, from); - } else { - assert(nonce == 0, "invalid nonce"); - } - - let amount = U128::from_integer(amount); - let from_balance = storage.public_balances.at(from).read().sub(amount); - storage.public_balances.at(from).write(from_balance); - - let to_balance = storage.public_balances.at(to).read().add(amount); - storage.public_balances.at(to).write(to_balance); - } - // docs:end:transfer_public - - // docs:start:burn_public - #[aztec(public)] - fn burn_public(from: AztecAddress, amount: Field, nonce: Field) { - // docs:start:assert_current_call_valid_authwit_public - if (!from.eq(context.msg_sender())) { - assert_current_call_valid_authwit_public(&mut context, from); - } else { - assert(nonce == 0, "invalid nonce"); - } - // docs:end:assert_current_call_valid_authwit_public - - let amount = U128::from_integer(amount); - let from_balance = storage.public_balances.at(from).read().sub(amount); - storage.public_balances.at(from).write(from_balance); - - let new_supply = storage.total_supply.read().sub(amount); - storage.total_supply.write(new_supply); - } - // docs:end:burn_public - - // docs:start:redeem_shield - #[aztec(private)] - fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) { - let secret_hash = compute_secret_hash(secret); - - // Pop 1 note (set_limit(1)) which has an amount stored in a field with index 0 (select(0, amount)) and - // a secret_hash stored in a field with index 1 (select(1, secret_hash)). - let mut options = NoteGetterOptions::new(); - options = options.select(TransparentNote::properties().amount, amount, Option::none()).select( - TransparentNote::properties().secret_hash, - secret_hash, - Option::none() - ).set_limit(1); - - let notes = storage.pending_shields.pop_notes(options); - assert(notes.len() == 1, "note not popped"); - - // Add the token note to user's balances set - // Note: Using context.msg_sender() as a sender below makes this incompatible with escrows because we send - // outgoing logs to that address and to send outgoing logs you need to get a hold of ovsk_m. - let from = context.msg_sender(); - let from_keys = get_current_public_keys(&mut context, from); - let to_keys = get_current_public_keys(&mut context, to); - storage.balances.at(to).add(to_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to)); - } - // docs:end:redeem_shield - - // docs:start:unshield - #[aztec(private)] - fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { - if (!from.eq(context.msg_sender())) { - assert_current_call_valid_authwit(&mut context, from); - } else { - assert(nonce == 0, "invalid nonce"); - } - - let from_keys = get_current_public_keys(&mut context, from); - storage.balances.at(from).sub(from_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); - - Token::at(context.this_address())._increase_public_balance(to, amount).enqueue(&mut context); - } - // docs:end:unshield - - // docs:start:transfer - #[aztec(private)] - fn transfer(to: AztecAddress, amount: Field) { - let from = context.msg_sender(); - - let from_keys = get_current_public_keys(&mut context, from); - let to_keys = get_current_public_keys(&mut context, to); - - let amount = U128::from_integer(amount); - - // We reduce `from`'s balance by amount by recursively removing notes over potentially multiple calls. This - // method keeps the gate count for each individual call low - reading too many notes at once could result in - // circuits in which proving is not feasible. - // Since the sum of the amounts in the notes we nullified was potentially larger than amount, we create a new - // note for `from` with the change amount, e.g. if `amount` is 10 and two notes are nullified with amounts 8 and - // 5, then the change will be 3 (since 8 + 5 - 10 = 3). - let change = subtract_balance( - &mut context, - storage, - from, - amount, - INITIAL_TRANSFER_CALL_MAX_NOTES - ); - - storage.balances.at(from).add(from_keys.npk_m, change).emit( - encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from) - ); - - storage.balances.at(to).add(to_keys.npk_m, amount).emit( - encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to) - ); - - // We don't constrain encryption of the note log in `transfer` (unlike in `transfer_from`) because the transfer - // function is only designed to be used in situations where the event is not strictly necessary (e.g. payment to - // another person where the payment is considered to be successful when the other party successfully decrypts a - // note). - Transfer { from, to, amount: amount.to_field() }.emit( - encode_and_encrypt_event_with_keys_unconstrained(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to) - ); - } - // docs:end:transfer - - #[contract_library_method] - fn subtract_balance( - context: &mut PrivateContext, - storage: Storage<&mut PrivateContext>, - account: AztecAddress, - amount: U128, - max_notes: u32 - ) -> U128 { - let subtracted = storage.balances.at(account).try_sub(amount, max_notes); - - // Failing to subtract any amount means that the owner was unable to produce more notes that could be nullified. - // We could in some cases fail early inside try_sub if we detected that fewer notes than the maximum were - // returned and we were still unable to reach the target amount, but that'd make the code more complicated, and - // optimizing for the failure scenario is not as important. - assert(subtracted > U128::from_integer(0), "Balance too low"); - - if subtracted >= amount { - // We have achieved our goal of nullifying notes that add up to more than amount, so we return the change - subtracted - amount - } else { - // try_sub failed to nullify enough notes to reach the target amount, so we compute the amount remaining - // and try again. - let remaining = amount - subtracted; - compute_recurse_subtract_balance_call(*context, account, remaining).call(context) - } - } - - // TODO(#7729): apply no_predicates to the contract interface method directly instead of having to use a wrapper - // like we do here. - #[no_predicates] - #[contract_library_method] - fn compute_recurse_subtract_balance_call( - context: PrivateContext, - account: AztecAddress, - remaining: U128 - ) -> PrivateCallInterface<25, U128, (AztecAddress, Field)> { - Token::at(context.this_address())._recurse_subtract_balance(account, remaining.to_field()) - } - - // TODO(#7728): even though the amount should be a U128, we can't have that type in a contract interface due to - // serialization issues. - #[aztec(internal)] - #[aztec(private)] - fn _recurse_subtract_balance(account: AztecAddress, amount: Field) -> U128 { - subtract_balance( - &mut context, - storage, - account, - U128::from_integer(amount), - RECURSIVE_TRANSFER_CALL_MAX_NOTES - ) - } - - /** - * Cancel a private authentication witness. - * @param inner_hash The inner hash of the authwit to cancel. - */ - // docs:start:cancel_authwit - #[aztec(private)] - fn cancel_authwit(inner_hash: Field) { - let on_behalf_of = context.msg_sender(); - let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash); - context.push_nullifier(nullifier); - } - // docs:end:cancel_authwit - - // docs:start:transfer_from - #[aztec(private)] - fn transfer_from(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { - // docs:start:assert_current_call_valid_authwit - if (!from.eq(context.msg_sender())) { - assert_current_call_valid_authwit(&mut context, from); - } else { - assert(nonce == 0, "invalid nonce"); - } - // docs:end:assert_current_call_valid_authwit - - let from_keys = get_current_public_keys(&mut context, from); - let to_keys = get_current_public_keys(&mut context, to); - - let amount = U128::from_integer(amount); - // docs:start:increase_private_balance - // docs:start:encrypted - storage.balances.at(from).sub(from_keys.npk_m, amount).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); - // docs:end:encrypted - // docs:end:increase_private_balance - storage.balances.at(to).add(to_keys.npk_m, amount).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to)); - } - // docs:end:transfer_from - - // docs:start:burn - #[aztec(private)] - fn burn(from: AztecAddress, amount: Field, nonce: Field) { - if (!from.eq(context.msg_sender())) { - assert_current_call_valid_authwit(&mut context, from); - } else { - assert(nonce == 0, "invalid nonce"); - } - - let from_keys = get_current_public_keys(&mut context, from); - storage.balances.at(from).sub(from_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); - - Token::at(context.this_address())._reduce_total_supply(amount).enqueue(&mut context); - } - // docs:end:burn - - /// We need to use different randomness for the user and for the fee payer notes because if the randomness values - /// were the same we could fingerprint the user by doing the following: - /// 1) randomness_influence = fee_payer_point - G_npk * fee_payer_npk = - /// = (G_npk * fee_payer_npk + G_rnd * randomness + G_slot * fee_payer_slot) - /// - G_npk * fee_payer_npk - G_slot * fee_payer_slot = - /// = G_rnd * randomness - /// 2) user_fingerprint = user_point - randomness_influence = - /// = (G_npk * user_npk + G_rnd * randomness + G_slot * user_slot) - G_rnd * randomness = - /// = G_npk * user_npk + G_slot * user_slot - /// 3) Then the second time the user would use this fee paying contract we would recover the same fingerprint - /// and link that the 2 transactions were made by the same user. Given that it's expected that only - /// a limited set of fee paying contracts will be used and they will be known, searching for fingerprints - /// by trying different fee payers is a feasible attack. - /// - /// Note 1: fee_payer_npk is publicly available in a key registry contract under a fee_payer address. So if we have - /// a known set of fee payer contract addresses getting fee_payer_npk and fee_payer_slot is trivial (slot - /// is derived in a `Map<...>` as a hash of balances map slot and a fee payer address). - /// Note 2: fee_payer_point and user_point above are public information because they are passed as args to - /// the public `complete_refund(...)` function. - // docs:start:setup_refund - #[aztec(private)] - fn setup_refund( - fee_payer: AztecAddress, // Address of the entity which will receive the fee note. - user: AztecAddress, // A user for which we are setting up the fee refund. - funded_amount: Field, // The amount the user funded the fee payer with (represents fee limit). - user_randomness: Field, // A randomness to mix in with the generated refund note for the sponsored user. - fee_payer_randomness: Field // A randomness to mix in with the generated fee note for the fee payer. - ) { - // 1. This function is called by fee paying contract (fee_payer) when setting up a refund so we need to support - // the authwit flow here and check that the user really permitted fee_payer to set up a refund on their behalf. - assert_current_call_valid_authwit(&mut context, user); - - // 2. Get all the relevant keys - let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); - let user_keys = get_current_public_keys(&mut context, user); - let user_npk_m_hash = user_keys.npk_m.hash(); - - // 3. Deduct the funded amount from the user's balance - this is a maximum fee a user is willing to pay - // (called fee limit in aztec spec). The difference between fee limit and the actual tx fee will be refunded - // to the user in the `complete_refund(...)` function. - let change = subtract_balance( - &mut context, - storage, - user, - U128::from_integer(funded_amount), - INITIAL_TRANSFER_CALL_MAX_NOTES - ); - storage.balances.at(user).add(user_keys.npk_m, change).emit( - encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) - ); - - // 4. We create the partial notes for the fee payer and the user. - // --> Called "partial" because they don't have the amount set yet (that will be done in `complete_refund(...)`). - let fee_payer_partial_note = TokenNote { - header: NoteHeader { - contract_address: AztecAddress::zero(), - nonce: 0, - storage_slot: storage.balances.at(fee_payer).set.storage_slot, - note_hash_counter: 0 - }, - amount: U128::zero(), - npk_m_hash: fee_payer_npk_m_hash, - randomness: fee_payer_randomness - }; - let user_partial_note = TokenNote { - header: NoteHeader { - contract_address: AztecAddress::zero(), - nonce: 0, - storage_slot: storage.balances.at(user).set.storage_slot, - note_hash_counter: 0 - }, - amount: U128::zero(), - npk_m_hash: user_npk_m_hash, - randomness: user_randomness - }; - - // 5. Now we get the note hiding points. - let mut fee_payer_point = fee_payer_partial_note.to_note_hiding_point(); - let mut user_point = user_partial_note.to_note_hiding_point(); - - // 6. Set the public teardown function to `complete_refund(...)`. Public teardown is the only time when a public - // function has access to the final transaction fee, which is needed to compute the actual refund amount. - context.set_public_teardown_function( - context.this_address(), - comptime { - FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") - }, - [ - fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount - ] - ); - } - // docs:end:setup_refund - - // TODO(#7728): even though the funded_amount should be a U128, we can't have that type in a contract interface due - // to serialization issues. - // docs:start:complete_refund - #[aztec(public)] - #[aztec(internal)] - fn complete_refund( - // TODO(#7771): the following makes macros crash --> try getting it work once we migrate to metaprogramming - // mut fee_payer_point: TokenNoteHidingPoint, - // mut user_point: TokenNoteHidingPoint, - fee_payer_point_immutable: TokenNoteHidingPoint, - user_point_immutable: TokenNoteHidingPoint, - funded_amount: Field - ) { - // TODO(#7771): nuke the following 2 lines once we have mutable args - let mut fee_payer_point = fee_payer_point_immutable; - let mut user_point = user_point_immutable; - - // TODO(#7728): Remove the next line - let funded_amount = U128::from_integer(funded_amount); - let tx_fee = U128::from_integer(context.transaction_fee()); - - // 1. We check that user funded the fee payer contract with at least the transaction fee. - // TODO(#7796): we should try to prevent reverts here - assert(funded_amount >= tx_fee, "funded amount not enough to cover tx fee"); - - // 2. We compute the refund amount as the difference between funded amount and tx fee. - let refund_amount = funded_amount - tx_fee; - - // 3. We add fee to the fee payer point and refund amount to the user point. - fee_payer_point.add_amount(tx_fee); - user_point.add_amount(refund_amount); - - // 4. We finalize the hiding points to get the note hashes. - let fee_payer_note_hash = fee_payer_point.finalize(); - let user_note_hash = user_point.finalize(); - - // 5. At last we emit the note hashes. - context.push_note_hash(fee_payer_note_hash); - context.push_note_hash(user_note_hash); - // --> Once the tx is settled user and fee recipient can add the notes to their pixies. - } - // docs:end:complete_refund - - /// Internal /// - - // docs:start:increase_public_balance - #[aztec(public)] - #[aztec(internal)] - fn _increase_public_balance(to: AztecAddress, amount: Field) { - let new_balance = storage.public_balances.at(to).read().add(U128::from_integer(amount)); - storage.public_balances.at(to).write(new_balance); - } - // docs:end:increase_public_balance - - // docs:start:reduce_total_supply - #[aztec(public)] - #[aztec(internal)] - fn _reduce_total_supply(amount: Field) { - // Only to be called from burn. - let new_supply = storage.total_supply.read().sub(U128::from_integer(amount)); - storage.total_supply.write(new_supply); - } - // docs:end:reduce_total_supply - - /// Unconstrained /// - - // docs:start:balance_of_private - unconstrained fn balance_of_private(owner: AztecAddress) -> pub Field { - storage.balances.at(owner).balance_of().to_field() - } - // docs:end:balance_of_private + // #[public] + // #[view] + // fn public_get_symbol() -> pub FieldCompressedString { + // storage.symbol.read_public() + // } + // #[private] + // #[view] + // fn private_get_symbol() -> pub FieldCompressedString { + // storage.symbol.read_private() + // } + // #[public] + // #[view] + // fn public_get_decimals() -> pub u8 { + // // docs:start:read_decimals_public + // storage.decimals.read_public() + // // docs:end:read_decimals_public + // } + // #[private] + // #[view] + // fn private_get_decimals() -> pub u8 { + // // docs:start:read_decimals_private + // storage.decimals.read_private() + // // docs:end:read_decimals_private + // } + // // docs:start:admin + // #[public] + // #[view] + // fn admin() -> Field { + // storage.admin.read().to_field() + // } + // // docs:end:admin + // // docs:start:is_minter + // #[public] + // #[view] + // fn is_minter(minter: AztecAddress) -> bool { + // storage.minters.at(minter).read() + // } + // // docs:end:is_minter + // // docs:start:total_supply + // #[public] + // #[view] + // fn total_supply() -> Field { + // storage.total_supply.read().to_integer() + // } + // // docs:end:total_supply + // // docs:start:balance_of_public + // #[public] + // #[view] + // fn balance_of_public(owner: AztecAddress) -> Field { + // storage.public_balances.at(owner).read().to_integer() + // } + // // docs:end:balance_of_public + // // docs:start:set_minter + // #[public] + // fn set_minter(minter: AztecAddress, approve: bool) { + // // docs:start:read_admin + // assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin"); + // // docs:end:read_admin + // // docs:start:write_minter + // storage.minters.at(minter).write(approve); + // // docs:end:write_minter + // } + // // docs:end:set_minter + // // docs:start:mint_public + // #[public] + // fn mint_public(to: AztecAddress, amount: Field) { + // // docs:start:read_minter + // assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); + // // docs:end:read_minter + // let amount = U128::from_integer(amount); + // let new_balance = storage.public_balances.at(to).read().add(amount); + // let supply = storage.total_supply.read().add(amount); + // storage.public_balances.at(to).write(new_balance); + // storage.total_supply.write(supply); + // } + // // docs:end:mint_public + // // docs:start:mint_private + // #[public] + // fn mint_private(amount: Field, secret_hash: Field) { + // assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); + // let pending_shields = storage.pending_shields; + // let mut note = TransparentNote::new(amount, secret_hash); + // let supply = storage.total_supply.read().add(U128::from_integer(amount)); + // storage.total_supply.write(supply); + // // docs:start:insert_from_public + // pending_shields.insert_from_public(&mut note); + // // docs:end:insert_from_public + // } + // // docs:end:mint_private + // // TODO: Nuke this - test functions do not belong to token contract! + // #[private] + // fn privately_mint_private_note(amount: Field) { + // let caller = context.msg_sender(); + // let caller_keys = get_current_public_keys(&mut context, caller); + // storage.balances.at(caller).add(caller_keys.npk_m, U128::from_integer(amount)).emit( + // encode_and_encrypt_note_with_keys(&mut context, caller_keys.ovpk_m, caller_keys.ivpk_m, caller) + // ); + // Token::at(context.this_address()).assert_minter_and_mint(context.msg_sender(), amount).enqueue(&mut context); + // } + // #[public] + // #[internal] + // fn assert_minter_and_mint(minter: AztecAddress, amount: Field) { + // assert(storage.minters.at(minter).read(), "caller is not minter"); + // let supply = storage.total_supply.read() + U128::from_integer(amount); + // storage.total_supply.write(supply); + // } + // // docs:start:shield + // #[public] + // fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) { + // if (!from.eq(context.msg_sender())) { + // // The redeem is only spendable once, so we need to ensure that you cannot insert multiple shields from the same message. + // assert_current_call_valid_authwit_public(&mut context, from); + // } else { + // assert(nonce == 0, "invalid nonce"); + // } + // let amount = U128::from_integer(amount); + // let from_balance = storage.public_balances.at(from).read().sub(amount); + // let pending_shields = storage.pending_shields; + // let mut note = TransparentNote::new(amount.to_field(), secret_hash); + // storage.public_balances.at(from).write(from_balance); + // pending_shields.insert_from_public(&mut note); + // } + // // docs:end:shield + // // docs:start:transfer_public + // #[public] + // fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { + // if (!from.eq(context.msg_sender())) { + // assert_current_call_valid_authwit_public(&mut context, from); + // } else { + // assert(nonce == 0, "invalid nonce"); + // } + // let amount = U128::from_integer(amount); + // let from_balance = storage.public_balances.at(from).read().sub(amount); + // storage.public_balances.at(from).write(from_balance); + // let to_balance = storage.public_balances.at(to).read().add(amount); + // storage.public_balances.at(to).write(to_balance); + // } + // // docs:end:transfer_public + // // docs:start:burn_public + // #[public] + // fn burn_public(from: AztecAddress, amount: Field, nonce: Field) { + // // docs:start:assert_current_call_valid_authwit_public + // if (!from.eq(context.msg_sender())) { + // assert_current_call_valid_authwit_public(&mut context, from); + // } else { + // assert(nonce == 0, "invalid nonce"); + // } + // // docs:end:assert_current_call_valid_authwit_public + // let amount = U128::from_integer(amount); + // let from_balance = storage.public_balances.at(from).read().sub(amount); + // storage.public_balances.at(from).write(from_balance); + // let new_supply = storage.total_supply.read().sub(amount); + // storage.total_supply.write(new_supply); + // } + // // docs:end:burn_public + // // docs:start:redeem_shield + // #[private] + // fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) { + // let secret_hash = compute_secret_hash(secret); + // // Pop 1 note (set_limit(1)) which has an amount stored in a field with index 0 (select(0, amount)) and + // // a secret_hash stored in a field with index 1 (select(1, secret_hash)). + // let mut options = NoteGetterOptions::new(); + // options = options.select(TransparentNote::properties().amount, amount, Option::none()).select( + // TransparentNote::properties().secret_hash, + // secret_hash, + // Option::none() + // ).set_limit(1); + // let notes = storage.pending_shields.pop_notes(options); + // assert(notes.len() == 1, "note not popped"); + // // Add the token note to user's balances set + // // Note: Using context.msg_sender() as a sender below makes this incompatible with escrows because we send + // // outgoing logs to that address and to send outgoing logs you need to get a hold of ovsk_m. + // let from = context.msg_sender(); + // let from_keys = get_current_public_keys(&mut context, from); + // let to_keys = get_current_public_keys(&mut context, to); + // storage.balances.at(to).add(to_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to)); + // } + // // docs:end:redeem_shield + // // docs:start:unshield + // #[private] + // fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { + // if (!from.eq(context.msg_sender())) { + // assert_current_call_valid_authwit(&mut context, from); + // } else { + // assert(nonce == 0, "invalid nonce"); + // } + // let from_keys = get_current_public_keys(&mut context, from); + // storage.balances.at(from).sub(from_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); + // Token::at(context.this_address())._increase_public_balance(to, amount).enqueue(&mut context); + // } + // // docs:end:unshield + // // docs:start:transfer + // #[private] + // fn transfer(to: AztecAddress, amount: Field) { + // let from = context.msg_sender(); + // let from_keys = get_current_public_keys(&mut context, from); + // let to_keys = get_current_public_keys(&mut context, to); + // let amount = U128::from_integer(amount); + // // We reduce `from`'s balance by amount by recursively removing notes over potentially multiple calls. This + // // method keeps the gate count for each individual call low - reading too many notes at once could result in + // // circuits in which proving is not feasible. + // // Since the sum of the amounts in the notes we nullified was potentially larger than amount, we create a new + // // note for `from` with the change amount, e.g. if `amount` is 10 and two notes are nullified with amounts 8 and + // // 5, then the change will be 3 (since 8 + 5 - 10 = 3). + // let change = subtract_balance( + // &mut context, + // storage, + // from, + // amount, + // INITIAL_TRANSFER_CALL_MAX_NOTES + // ); + // storage.balances.at(from).add(from_keys.npk_m, change).emit( + // encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from) + // ); + // storage.balances.at(to).add(to_keys.npk_m, amount).emit( + // encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to) + // ); + // // We don't constrain encryption of the note log in `transfer` (unlike in `transfer_from`) because the transfer + // // function is only designed to be used in situations where the event is not strictly necessary (e.g. payment to + // // another person where the payment is considered to be successful when the other party successfully decrypts a + // // note). + // Transfer { from, to, amount: amount.to_field() }.emit( + // encode_and_encrypt_event_with_keys_unconstrained(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to) + // ); + // } + // // docs:end:transfer + // #[contract_library_method] + // fn subtract_balance( + // context: &mut PrivateContext, + // storage: Storage<&mut PrivateContext>, + // account: AztecAddress, + // amount: U128, + // max_notes: u32 + // ) -> U128 { + // let subtracted = storage.balances.at(account).try_sub(amount, max_notes); + // // Failing to subtract any amount means that the owner was unable to produce more notes that could be nullified. + // // We could in some cases fail early inside try_sub if we detected that fewer notes than the maximum were + // // returned and we were still unable to reach the target amount, but that'd make the code more complicated, and + // // optimizing for the failure scenario is not as important. + // assert(subtracted > U128::from_integer(0), "Balance too low"); + // if subtracted >= amount { + // // We have achieved our goal of nullifying notes that add up to more than amount, so we return the change + // subtracted - amount + // } else { + // // try_sub failed to nullify enough notes to reach the target amount, so we compute the amount remaining + // // and try again. + // let remaining = amount - subtracted; + // compute_recurse_subtract_balance_call(*context, account, remaining).call(context) + // } + // } + // // TODO(#7729): apply no_predicates to the contract interface method directly instead of having to use a wrapper + // // like we do here. + // #[no_predicates] + // #[contract_library_method] + // fn compute_recurse_subtract_balance_call( + // context: PrivateContext, + // account: AztecAddress, + // remaining: U128 + // ) -> PrivateCallInterface<25, U128, (AztecAddress, Field)> { + // Token::at(context.this_address())._recurse_subtract_balance(account, remaining.to_field()) + // } + // // TODO(#7728): even though the amount should be a U128, we can't have that type in a contract interface due to + // // serialization issues. + // #[internal] + // #[private] + // fn _recurse_subtract_balance(account: AztecAddress, amount: Field) -> U128 { + // subtract_balance( + // &mut context, + // storage, + // account, + // U128::from_integer(amount), + // RECURSIVE_TRANSFER_CALL_MAX_NOTES + // ) + // } + // /** + // * Cancel a private authentication witness. + // * @param inner_hash The inner hash of the authwit to cancel. + // */ + // // docs:start:cancel_authwit + // #[private] + // fn cancel_authwit(inner_hash: Field) { + // let on_behalf_of = context.msg_sender(); + // let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash); + // context.push_nullifier(nullifier); + // } + // // docs:end:cancel_authwit + // // docs:start:transfer_from + // #[private] + // fn transfer_from(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { + // // docs:start:assert_current_call_valid_authwit + // if (!from.eq(context.msg_sender())) { + // assert_current_call_valid_authwit(&mut context, from); + // } else { + // assert(nonce == 0, "invalid nonce"); + // } + // // docs:end:assert_current_call_valid_authwit + // let from_keys = get_current_public_keys(&mut context, from); + // let to_keys = get_current_public_keys(&mut context, to); + // let amount = U128::from_integer(amount); + // // docs:start:increase_private_balance + // // docs:start:encrypted + // storage.balances.at(from).sub(from_keys.npk_m, amount).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); + // // docs:end:encrypted + // // docs:end:increase_private_balance + // storage.balances.at(to).add(to_keys.npk_m, amount).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to)); + // } + // // docs:end:transfer_from + // // docs:start:burn + // #[private] + // fn burn(from: AztecAddress, amount: Field, nonce: Field) { + // if (!from.eq(context.msg_sender())) { + // assert_current_call_valid_authwit(&mut context, from); + // } else { + // assert(nonce == 0, "invalid nonce"); + // } + // let from_keys = get_current_public_keys(&mut context, from); + // storage.balances.at(from).sub(from_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); + // Token::at(context.this_address())._reduce_total_supply(amount).enqueue(&mut context); + // } + // // docs:end:burn + // /// We need to use different randomness for the user and for the fee payer notes because if the randomness values + // /// were the same we could fingerprint the user by doing the following: + // /// 1) randomness_influence = fee_payer_point - G_npk * fee_payer_npk = + // /// = (G_npk * fee_payer_npk + G_rnd * randomness + G_slot * fee_payer_slot) + // /// - G_npk * fee_payer_npk - G_slot * fee_payer_slot = + // /// = G_rnd * randomness + // /// 2) user_fingerprint = user_point - randomness_influence = + // /// = (G_npk * user_npk + G_rnd * randomness + G_slot * user_slot) - G_rnd * randomness = + // /// = G_npk * user_npk + G_slot * user_slot + // /// 3) Then the second time the user would use this fee paying contract we would recover the same fingerprint + // /// and link that the 2 transactions were made by the same user. Given that it's expected that only + // /// a limited set of fee paying contracts will be used and they will be known, searching for fingerprints + // /// by trying different fee payers is a feasible attack. + // /// + // /// Note 1: fee_payer_npk is publicly available in a key registry contract under a fee_payer address. So if we have + // /// a known set of fee payer contract addresses getting fee_payer_npk and fee_payer_slot is trivial (slot + // /// is derived in a `Map<...>` as a hash of balances map slot and a fee payer address). + // /// Note 2: fee_payer_point and user_point above are public information because they are passed as args to + // /// the public `complete_refund(...)` function. + // // docs:start:setup_refund + // #[private] + // fn setup_refund( + // fee_payer: AztecAddress, // Address of the entity which will receive the fee note. + // user: AztecAddress, // A user for which we are setting up the fee refund. + // funded_amount: Field, // The amount the user funded the fee payer with (represents fee limit). + // user_randomness: Field, // A randomness to mix in with the generated refund note for the sponsored user. + // fee_payer_randomness: Field // A randomness to mix in with the generated fee note for the fee payer. + // ) { + // // 1. This function is called by fee paying contract (fee_payer) when setting up a refund so we need to support + // // the authwit flow here and check that the user really permitted fee_payer to set up a refund on their behalf. + // assert_current_call_valid_authwit(&mut context, user); + // // 2. Get all the relevant keys + // let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); + // let user_keys = get_current_public_keys(&mut context, user); + // let user_npk_m_hash = user_keys.npk_m.hash(); + // // 3. Deduct the funded amount from the user's balance - this is a maximum fee a user is willing to pay + // // (called fee limit in aztec spec). The difference between fee limit and the actual tx fee will be refunded + // // to the user in the `complete_refund(...)` function. + // let change = subtract_balance( + // &mut context, + // storage, + // user, + // U128::from_integer(funded_amount), + // INITIAL_TRANSFER_CALL_MAX_NOTES + // ); + // storage.balances.at(user).add(user_keys.npk_m, change).emit( + // encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) + // ); + // // 4. We create the partial notes for the fee payer and the user. + // // --> Called "partial" because they don't have the amount set yet (that will be done in `complete_refund(...)`). + // let fee_payer_partial_note = TokenNote { + // header: NoteHeader { + // contract_address: AztecAddress::zero(), + // nonce: 0, + // storage_slot: storage.balances.at(fee_payer).set.storage_slot, + // note_hash_counter: 0 + // }, + // amount: U128::zero(), + // npk_m_hash: fee_payer_npk_m_hash, + // randomness: fee_payer_randomness + // }; + // let user_partial_note = TokenNote { + // header: NoteHeader { + // contract_address: AztecAddress::zero(), + // nonce: 0, + // storage_slot: storage.balances.at(user).set.storage_slot, + // note_hash_counter: 0 + // }, + // amount: U128::zero(), + // npk_m_hash: user_npk_m_hash, + // randomness: user_randomness + // }; + // // 5. Now we get the note hiding points. + // let mut fee_payer_point = fee_payer_partial_note.to_note_hiding_point(); + // let mut user_point = user_partial_note.to_note_hiding_point(); + // // 6. Set the public teardown function to `complete_refund(...)`. Public teardown is the only time when a public + // // function has access to the final transaction fee, which is needed to compute the actual refund amount. + // context.set_public_teardown_function( + // context.this_address(), + // comptime { + // FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") + // }, + // [ + // fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount + // ] + // ); + // } + // // docs:end:setup_refund + // // TODO(#7728): even though the funded_amount should be a U128, we can't have that type in a contract interface due + // // to serialization issues. + // // docs:start:complete_refund + // #[public] + // #[internal] + // fn complete_refund( + // // TODO(#7771): the following makes macros crash --> try getting it work once we migrate to metaprogramming + // // mut fee_payer_point: TokenNoteHidingPoint, + // // mut user_point: TokenNoteHidingPoint, + // fee_payer_point_immutable: TokenNoteHidingPoint, + // user_point_immutable: TokenNoteHidingPoint, + // funded_amount: Field + // ) { + // // TODO(#7771): nuke the following 2 lines once we have mutable args + // let mut fee_payer_point = fee_payer_point_immutable; + // let mut user_point = user_point_immutable; + // // TODO(#7728): Remove the next line + // let funded_amount = U128::from_integer(funded_amount); + // let tx_fee = U128::from_integer(context.transaction_fee()); + // // 1. We check that user funded the fee payer contract with at least the transaction fee. + // // TODO(#7796): we should try to prevent reverts here + // assert(funded_amount >= tx_fee, "funded amount not enough to cover tx fee"); + // // 2. We compute the refund amount as the difference between funded amount and tx fee. + // let refund_amount = funded_amount - tx_fee; + // // 3. We add fee to the fee payer point and refund amount to the user point. + // fee_payer_point.add_amount(tx_fee); + // user_point.add_amount(refund_amount); + // // 4. We finalize the hiding points to get the note hashes. + // let fee_payer_note_hash = fee_payer_point.finalize(); + // let user_note_hash = user_point.finalize(); + // // 5. At last we emit the note hashes. + // context.push_note_hash(fee_payer_note_hash); + // context.push_note_hash(user_note_hash); + // // --> Once the tx is settled user and fee recipient can add the notes to their pixies. + // } + // // docs:end:complete_refund + // /// Internal /// + // // docs:start:increase_public_balance + // #[public] + // #[internal] + // fn _increase_public_balance(to: AztecAddress, amount: Field) { + // let new_balance = storage.public_balances.at(to).read().add(U128::from_integer(amount)); + // storage.public_balances.at(to).write(new_balance); + // } + // // docs:end:increase_public_balance + // // docs:start:reduce_total_supply + // #[public] + // #[internal] + // fn _reduce_total_supply(amount: Field) { + // // Only to be called from burn. + // let new_supply = storage.total_supply.read().sub(U128::from_integer(amount)); + // storage.total_supply.write(new_supply); + // } + // // docs:end:reduce_total_supply + // /// Unconstrained /// + // // docs:start:balance_of_private + // unconstrained fn balance_of_private(owner: AztecAddress) -> pub Field { + // storage.balances.at(owner).balance_of().to_field() + // } + // // docs:end:balance_of_private } // docs:end:token_all diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr index 25d0407c6bb..dda5f9d8f80 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr @@ -1,8 +1,8 @@ -use dep::aztec::prelude::{NoteGetterOptions, NoteViewerOptions, NoteInterface, PrivateSet, Point}; +use dep::aztec::prelude::{NoteGetterOptions, NoteViewerOptions, NoteInterface, PrivateSet}; use dep::aztec::{ context::{PrivateContext, UnconstrainedContext}, protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, - note::{note_getter::view_notes, note_emission::{NoteEmission, OuterNoteEmission}}, + note::{note_interface::{FinalizedNote, NullifiableNote}, note_getter::view_notes, note_emission::OuterNoteEmission}, keys::{getters::get_current_public_keys, public_keys::NpkM} }; use crate::types::token_note::OwnedNote; @@ -19,14 +19,14 @@ impl BalanceSet { } impl BalanceSet { - unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote { self.balance_of_with_offset(0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, offset: u32 - ) -> U128 where T: NoteInterface + OwnedNote { + ) -> U128 where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote { let mut balance = U128::from_integer(0); // docs:start:view_notes let mut options = NoteViewerOptions::new(); @@ -46,11 +46,11 @@ impl BalanceSet { } impl BalanceSet { - pub fn add( + pub fn add( self: Self, owner_npk_m: NpkM, addend: U128 - ) -> OuterNoteEmission where T: NoteInterface + OwnedNote + Eq { + ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote + Eq { if addend == U128::from_integer(0) { OuterNoteEmission::new(Option::none()) } else { @@ -63,11 +63,11 @@ impl BalanceSet { } } - pub fn sub( + pub fn sub( self: Self, owner_npk_m: NpkM, amount: U128 - ) -> OuterNoteEmission where T: NoteInterface + OwnedNote + Eq { + ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote + Eq { let subtracted = self.try_sub(amount, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL); // try_sub may have substracted more or less than amount. We must ensure that we subtracted at least as much as @@ -85,11 +85,11 @@ impl BalanceSet { // The `max_notes` parameter is used to fine-tune the number of constraints created by this function. The gate count // scales relatively linearly with `max_notes`, but a lower `max_notes` parameter increases the likelihood of // `try_sub` subtracting an amount smaller than `target_amount`. - pub fn try_sub( + pub fn try_sub( self: Self, target_amount: U128, max_notes: u32 - ) -> U128 where T: NoteInterface + OwnedNote + Eq { + ) -> U128 where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote + Eq { // We are using a preprocessor here (filter applied in an unconstrained context) instead of a filter because // we do not need to prove correct execution of the preprocessor. // Because the `min_sum` notes is not constrained, users could choose to e.g. not call it. However, all this @@ -115,10 +115,10 @@ impl BalanceSet { // The preprocessor (a filter applied in an unconstrained context) does not check if total sum is larger or equal to // 'min_sum' - all it does is remove extra notes if it does reach that value. // Note that proper usage of this preprocessor requires for notes to be sorted in descending order. -pub fn preprocess_notes_min_sum( +pub fn preprocess_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 -) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote { let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(0); for i in 0..notes.len() { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 2d678006e7f..4f8eaf39370 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -1,25 +1,17 @@ use dep::aztec::{ - generators::{Ga1 as G_amt, Ga2 as G_npk, Ga3 as G_rnd, G_slot}, - prelude::{NoteHeader, NoteInterface, PrivateContext}, - protocol_types::{ - constants::GENERATOR_INDEX__NOTE_NULLIFIER, point::{Point, POINT_LENGTH}, scalar::Scalar, - hash::poseidon2_hash_with_separator, traits::Serialize -}, + prelude::{NoteHeader, NullifiableNote, PrivateContext}, + protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, note::utils::compute_note_hash_for_nullify, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app + keys::getters::get_nsk_app, macros::notes::note }; -use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; trait OwnedNote { fn new(amount: U128, owner_npk_m_hash: Field) -> Self; fn get_amount(self) -> U128; } -global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. -global TOKEN_NOTE_BYTES_LEN: Field = 3 * 32 + 64; - // docs:start:TokenNote -#[aztec(note)] +#[note] struct TokenNote { // The amount of tokens in the note amount: U128, @@ -30,15 +22,16 @@ struct TokenNote { } // docs:end:TokenNote -impl NoteInterface for TokenNote { +impl NullifiableNote for TokenNote { // docs:start:nullifier fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash_with_separator([ + poseidon2_hash_with_separator( + [ note_hash_for_nullify, secret ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, + GENERATOR_INDEX__NOTE_NULLIFIER as Field ) } // docs:end:nullifier @@ -46,88 +39,24 @@ impl NoteInterface for TokenNote { fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_nullify(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash_with_separator([note_hash_for_nullify, secret],GENERATOR_INDEX__NOTE_NULLIFIER) - } - - // docs:start:compute_note_hiding_point - fn compute_note_hiding_point(self) -> Point { - // We use the unsafe version because the multi_scalar_mul will constrain the scalars. - let amount_scalar = from_field_unsafe(self.amount.to_integer()); - let npk_m_hash_scalar = from_field_unsafe(self.npk_m_hash); - let randomness_scalar = from_field_unsafe(self.randomness); - let slot_scalar = from_field_unsafe(self.header.storage_slot); - // We compute the note hiding point as: - // `G_amt * amount + G_npk * npk_m_hash + G_rnd * randomness + G_slot * slot` - // instead of using pedersen or poseidon2 because it allows us to privately add and subtract from amount - // in public by leveraging homomorphism. - multi_scalar_mul( - [G_amt, G_npk, G_rnd, G_slot], - [amount_scalar, npk_m_hash_scalar, randomness_scalar, slot_scalar] + poseidon2_hash_with_separator( + [note_hash_for_nullify, secret], + GENERATOR_INDEX__NOTE_NULLIFIER ) } - // docs:end:compute_note_hiding_point -} - -impl TokenNote { - // TODO: Merge this func with `compute_note_hiding_point`. I (benesjan) didn't do it in the initial PR to not have - // to modify macros and all the related funcs in it. - fn to_note_hiding_point(self) -> TokenNoteHidingPoint { - TokenNoteHidingPoint::new(self.compute_note_hiding_point()) - } -} - -struct TokenNoteHidingPoint { - inner: Point -} - -impl TokenNoteHidingPoint { - fn new(point: Point) -> Self { - Self { inner: point } - } - - fn add_amount(&mut self, amount: U128) { - self.inner = multi_scalar_mul([G_amt], [from_field_unsafe(amount.to_integer())]) + self.inner; - } - - fn add_npk_m_hash(&mut self, npk_m_hash: Field) { - self.inner = multi_scalar_mul([G_npk], [from_field_unsafe(npk_m_hash)]) + self.inner; - } - - fn add_randomness(&mut self, randomness: Field) { - self.inner = multi_scalar_mul([G_rnd], [from_field_unsafe(randomness)]) + self.inner; - } - - fn add_slot(&mut self, slot: Field) { - self.inner = multi_scalar_mul([G_slot], [from_field_unsafe(slot)]) + self.inner; - } - - fn finalize(self) -> Field { - self.inner.x - } -} - -impl Serialize for TokenNoteHidingPoint { - fn serialize(self) -> [Field; POINT_LENGTH] { - self.inner.serialize() - } } impl Eq for TokenNote { fn eq(self, other: Self) -> bool { - (self.amount == other.amount) & - (self.npk_m_hash == other.npk_m_hash) & - (self.randomness == other.randomness) + (self.amount == other.amount) + & (self.npk_m_hash == other.npk_m_hash) + & (self.randomness == other.randomness) } } impl OwnedNote for TokenNote { fn new(amount: U128, owner_npk_m_hash: Field) -> Self { - Self { - amount, - npk_m_hash: owner_npk_m_hash, - randomness: unsafe_rand(), - header: NoteHeader::empty(), - } + Self { amount, npk_m_hash: owner_npk_m_hash, randomness: unsafe_rand(), header: NoteHeader::empty() } } fn get_amount(self) -> U128 { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index fb04609edc0..826fbca2a2d 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -1,45 +1,21 @@ // docs:start:token_types_all use dep::aztec::{ - utils::compute_note_hash_for_nullify}, - prelude::{NoteHeader, NoteInterface, PrivateContext}, - protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} + note::utils::compute_note_hash_for_nullify, prelude::{NoteHeader, NullifiableNote, PrivateContext}, + protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, + macros::notes::note }; -global TRANSPARENT_NOTE_LEN: Field = 2; -// TRANSPARENT_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global TRANSPARENT_NOTE_BYTES_LEN: Field = 2 * 32 + 64; - // Transparent note represents a note that is created in the clear (public execution), but can only be spent by those // that know the preimage of the "secret_hash" (the secret). This is typically used when shielding a token balance. // Owner of the tokens provides a "secret_hash" as an argument to the public "shield" function and then the tokens // can be redeemed in private by presenting the preimage of the "secret_hash" (the secret). -#[aztec(note)] +#[note] struct TransparentNote { amount: Field, secret_hash: Field, } -struct TransparentNoteProperties { - amount: PropertySelector, - secret_hash: PropertySelector, -} - -impl NoteInterface for TransparentNote { - - // Custom serialization to avoid disclosing the secret field - fn serialize_content(self) -> [Field; TRANSPARENT_NOTE_LEN] { - [self.amount, self.secret_hash] - } - - // Custom deserialization since we don't have access to the secret plaintext - fn deserialize_content(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> Self { - TransparentNote { - amount: serialized_note[0], - secret_hash: serialized_note[1], - header: NoteHeader::empty(), - } - } - +impl NullifiableNote for TransparentNote { fn compute_nullifier(self, _context: &mut PrivateContext, _note_hash_for_nullify: Field) -> Field { self.compute_nullifier_without_context() } @@ -54,10 +30,9 @@ impl NoteInterface for Transpa // This achieves that the note can only be spent by the party that knows the secret. fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_nullify(self); - poseidon2_hash_with_separator([ - note_hash_for_nullify, - ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, + poseidon2_hash_with_separator( + [note_hash_for_nullify], + GENERATOR_INDEX__NOTE_NULLIFIER as Field ) } } @@ -67,15 +42,6 @@ impl TransparentNote { pub fn new(amount: Field, secret_hash: Field) -> Self { TransparentNote { amount, secret_hash, header: NoteHeader::empty() } } - - // CUSTOM FUNCTIONS FOR THIS NOTE TYPE - // Custom serialization forces us to manually create the metadata struct and its getter - pub fn properties() -> TransparentNoteProperties { - TransparentNoteProperties { - amount: PropertySelector { index: 0, offset: 0, length: 32 }, - secret_hash: PropertySelector { index: 1, offset: 0, length: 32 } - } - } } impl Eq for TransparentNote { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index a4428215c8e..fd63fd0070c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -1,5 +1,76 @@ -use super::traits::Serialize; -use std::meta::type_of; +use super::traits::{Serialize, Deserialize}; + +// TODO: This is bad and incomplete. Fix it! +pub comptime fn pack_from_fields( + name: Quoted, + typ: Type, + buffer: Quoted, + already_consumed: u32, + replacements: [(Quoted, Quoted)] +) -> (Quoted, u32) { + let mut result = quote {}; + let mut consumed: u32 = already_consumed; + + let found_replacements = replacements.filter(| (to_omit, _): (Quoted, Quoted) | to_omit == name); + + let replacement = if found_replacements.len() == 1 { + replacements[0].1 + } else { + quote {} + }; + + if replacement == quote {} { + if typ.is_field() | typ.as_integer().is_some() { + result = quote { $buffer[$consumed] as Field }; + consumed = 1; + } else if typ.as_struct().is_some() { + let (nested_def, _) = typ.as_struct().unwrap(); + let nested_name = nested_def.name(); + let mut deserialized_fields_list = &[]; + for field in nested_def.fields() { + let (field_name, field_type) = field; + let (deserialized_field, consumed_by_field) = pack_from_fields( + quote { $field_name }, + field_type, + quote { $buffer }, + consumed, + replacements + ); + consumed += consumed_by_field; + deserialized_fields_list = deserialized_fields_list.push_back(quote { $field_name: $deserialized_field }); + } + let deserialized_fields = deserialized_fields_list.join(quote {,}); + result = quote { + $nested_name { + $deserialized_fields + } + }; + } else if typ.as_array().is_some() { + let (element_type, array_len) = typ.as_array().unwrap(); + let array_len = array_len.as_constant().unwrap(); + let mut array_fields_list = &[]; + for i in 0..array_len { + let (deserialized_field, consumed_by_field) = pack_from_fields( + quote { $name }, + element_type, + quote { $buffer }, + consumed, + replacements + ); + array_fields_list = array_fields_list.push_back(deserialized_field); + consumed += consumed_by_field; + } + let array_fields = array_fields_list.join(quote {,}); + result = quote { [ $array_fields ] }; + } else { + assert(false, f"Unsupported type for serialization of argument {name} and type {typ}"); + std::mem::zeroed() + } + } else { + result = replacement; + } + (result, consumed) +} pub comptime fn flatten_to_fields(name: Quoted, typ: Type, omit: [Quoted]) -> ([Quoted], [Quoted]) { let mut fields = &[]; @@ -72,7 +143,21 @@ pub(crate) comptime fn derive_serialize(s: StructDefinition) -> Quoted { } } -#[derive(Serialize)] +pub(crate) comptime fn derive_deserialize(s: StructDefinition) -> Quoted { + let typ = s.as_type(); + let (fields, _) = flatten_to_fields(quote { self }, typ, &[]); + let serialized_len = fields.len(); + let (deserialized, _) = pack_from_fields(quote { self }, typ, quote { value }, 0, &[]); + quote { + impl Deserialize<$serialized_len> for $typ { + fn deserialize(value: [Field; $serialized_len]) -> Self { + $deserialized + } + } + } +} + +#[derive(Serialize, Deserialize, Eq)] struct Smol { a: Field, b: Field, @@ -95,6 +180,8 @@ fn smol_test() { let smol = Smol { a: 1, b: 2 }; let serialized = smol.serialize(); assert(serialized == [1, 2], serialized); + let deserialized = Smol::deserialize(serialized); + assert(deserialized == smol); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr index b428d7795e0..d3e35504cb6 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr @@ -1,5 +1,5 @@ use crate::utils::field::field_from_bytes; -use crate::meta::derive_serialize; +use crate::meta::{derive_deserialize, derive_serialize}; // Trait: is_empty // @@ -173,6 +173,7 @@ impl Serialize for str { } // docs:start:deserialize +#[derive_via(derive_deserialize)] trait Deserialize { fn deserialize(fields: [Field; N]) -> Self; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr b/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr index e7aac333e59..474901eec9c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr @@ -59,7 +59,6 @@ impl Serialize for U128 { fn serialize(self) -> [Field; 1] { [self.to_integer()] } - } impl Deserialize for U128 { From b23d25c704813aac193576f29384bccc177e21a7 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 16 Sep 2024 08:01:39 +0000 Subject: [PATCH 10/79] fixes --- .../aztec-nr/aztec/src/keys/getters/test.nr | 2 +- .../aztec-nr/aztec/src/macros/utils.nr | 16 +- .../contracts/counter_contract/src/main.nr | 29 +- .../contracts/token_contract/src/main.nr | 986 +++++++++--------- 4 files changed, 515 insertions(+), 518 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/keys/getters/test.nr b/noir-projects/aztec-nr/aztec/src/keys/getters/test.nr index 41534e0de72..08c69cd6530 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/getters/test.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/getters/test.nr @@ -19,7 +19,7 @@ fn setup() -> (TestEnvironment, PrivateContext, TestAccount) { #[test(should_fail_with="Invalid public keys hint for address")] fn test_get_current_keys_unknown_unregistered() { - let (_, context, account) = setup(); + let (_, mut context, account) = setup(); let _ = OracleMock::mock("getPublicKeysAndPartialAddress").returns([0; KEY_ORACLE_RESPONSE_LENGTH]).times(1); let _ = get_current_public_keys(&mut context, account.address); diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 955043d1618..01d93bc6dc5 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -1,4 +1,4 @@ -use std::meta::{typ::fresh_type_variable, unquote}; +use std::meta::{typ::fresh_type_variable, unquote, type_of}; pub(crate) comptime fn get_fn_visibility(f: FunctionDefinition) -> Quoted { if f.has_named_attribute("private") { @@ -35,11 +35,12 @@ pub(crate) comptime fn fn_has_noinitcheck(f: FunctionDefinition) -> bool { pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quoted) -> Expr { let mut body_quote = body.fold( quote {}, - |body_quote, expr: Expr| { + |body_quote: Quoted, expr: Expr| { let expr_quote = expr.quoted(); + let semicolon = if expr_quote.as_expr().is_some() { quote {} } else { quote {;} }; quote { $body_quote - $expr_quote + $expr_quote$semicolon } } ); @@ -58,8 +59,13 @@ pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quo body_expr.unwrap() } +pub(crate) comptime fn is_bool(typ: Type) -> bool { + let a_bool = true; + typ == type_of(a_bool) +} + pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: Type) -> Quoted { - if typ.is_field() | typ.as_integer().is_some() { + if typ.is_field() | typ.as_integer().is_some() | is_bool(typ) { quote { $slice_name = $slice_name.push_back($name as Field); } } else if typ.as_struct().is_some() { quote { $slice_name = $slice_name.append($name.serialize()); } @@ -83,7 +89,7 @@ pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: } pub(crate) comptime fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted { - if typ.is_field() | typ.as_integer().is_some() { + if typ.is_field() | typ.as_integer().is_some() | is_bool(typ) { quote { $hasher_name.add($name as Field); } } else if typ.as_struct().is_some() { quote { $hasher_name.add_multiple($name.serialize()); } diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 5156ab14d94..2161f84311f 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -7,6 +7,9 @@ contract Counter { use value_note::{balance_utils, value_note::ValueNote}; use easy_private_state::EasyPrivateUint; use aztec::macros::{storage::storage, functions::{initializer, private}}; + use aztec::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs; + use aztec::context::inputs::private_context_inputs::PrivateContextInputs; + // docs:end:imports // docs:start:storage_struct @@ -28,26 +31,14 @@ contract Counter { // docs:start:increment #[private] - fn increment(owner: AztecAddress, outgoing_viewer: AztecAddress) -> Field { - let mut args_hasher = dep::aztec::hash::ArgsHasher::new(); - args_hasher.add_multiple(owner.serialize()); - args_hasher.add_multiple(outgoing_viewer.serialize()); - let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); - dep::aztec::initializer::assert_is_initialized_private(&mut context); - let storage = Storage::init(&mut context); + fn increment(owner: AztecAddress, outgoing_viewer: AztecAddress) { unsafe { dep::aztec::oracle::debug_log::debug_log_format("Incrementing counter for owner {0}", [owner.to_field()]); - } - let counters: unspecified = (storage.counters); + }; + let counters = storage.counters; counters.at(owner).add(1, owner, outgoing_viewer); - let mut return_hasher = dep::aztec::hash::ArgsHasher::new(); - let macro__returned__values = 1; - return_hasher.add(macro__returned__values as Field); - context.set_return_hash(return_hasher); - context.finish() } // docs:end:increment - // docs:start:get_counter unconstrained fn get_counter(owner: AztecAddress) -> pub Field { let counters = storage.counters; @@ -55,10 +46,10 @@ contract Counter { } // docs:end:get_counter // docs:start:test_imports - use dep::aztec::test::{helpers::{test_environment::TestEnvironment}}; - use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; - use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; - use dep::aztec::note::note_viewer_options::NoteViewerOptions; + // use dep::aztec::test::{helpers::{test_environment::TestEnvironment}}; + // use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; + // use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; + // use dep::aztec::note::note_viewer_options::NoteViewerOptions; // docs:end:test_imports // docs:start:txe_test_increment #[test] diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index acb0690fed5..77bb165d1b8 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -80,507 +80,507 @@ contract Token { // docs:end:storage_struct // docs:start:constructor - // #[public] - // #[initializer] - // fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { - // assert(!admin.is_zero(), "invalid admin"); - // storage.admin.write(admin); - // storage.minters.at(admin).write(true); - // storage.name.initialize(FieldCompressedString::from_string(name)); - // storage.symbol.initialize(FieldCompressedString::from_string(symbol)); - // // docs:start:initialize_decimals - // storage.decimals.initialize(decimals); - // // docs:end:initialize_decimals - // } - // // docs:end:constructor - // // docs:start:set_admin - // #[public] - // fn set_admin(new_admin: AztecAddress) { - // assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin"); - // // docs:start:write_admin - // storage.admin.write(new_admin); - // // docs:end:write_admin - // } + #[public] + #[initializer] + fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { + assert(!admin.is_zero(), "invalid admin"); + storage.admin.write(admin); + storage.minters.at(admin).write(true); + storage.name.initialize(FieldCompressedString::from_string(name)); + storage.symbol.initialize(FieldCompressedString::from_string(symbol)); + // docs:start:initialize_decimals + storage.decimals.initialize(decimals); + // docs:end:initialize_decimals + } + // docs:end:constructor + // docs:start:set_admin + #[public] + fn set_admin(new_admin: AztecAddress) { + assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin"); + // docs:start:write_admin + storage.admin.write(new_admin); + // docs:end:write_admin + } // docs:end:set_admin - // #[public] - // #[view] - // fn public_get_name() -> FieldCompressedString { - // storage.name.read_public() - // } + #[public] + #[view] + fn public_get_name() -> FieldCompressedString { + storage.name.read_public() + } #[private] #[view] fn private_get_name() -> FieldCompressedString { storage.name.read_private() } + #[public] + #[view] + fn public_get_symbol() -> pub FieldCompressedString { + storage.symbol.read_public() + } + #[private] + #[view] + fn private_get_symbol() -> pub FieldCompressedString { + storage.symbol.read_private() + } + #[public] + #[view] + fn public_get_decimals() -> pub u8 { + // docs:start:read_decimals_public + storage.decimals.read_public() + // docs:end:read_decimals_public + } + #[private] + #[view] + fn private_get_decimals() -> pub u8 { + // docs:start:read_decimals_private + storage.decimals.read_private() + // docs:end:read_decimals_private + } + // docs:start:admin + #[public] + #[view] + fn admin() -> Field { + storage.admin.read().to_field() + } + // docs:end:admin + // docs:start:is_minter + #[public] + #[view] + fn is_minter(minter: AztecAddress) -> bool { + storage.minters.at(minter).read() + } + // docs:end:is_minter + // docs:start:total_supply + #[public] + #[view] + fn total_supply() -> Field { + storage.total_supply.read().to_integer() + } + // docs:end:total_supply + // docs:start:balance_of_public + #[public] + #[view] + fn balance_of_public(owner: AztecAddress) -> Field { + storage.public_balances.at(owner).read().to_integer() + } + // docs:end:balance_of_public + // docs:start:set_minter + #[public] + fn set_minter(minter: AztecAddress, approve: bool) { + // docs:start:read_admin + assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin"); + // docs:end:read_admin + // docs:start:write_minter + storage.minters.at(minter).write(approve); + // docs:end:write_minter + } + // docs:end:set_minter + // docs:start:mint_public + #[public] + fn mint_public(to: AztecAddress, amount: Field) { + // docs:start:read_minter + assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); + // docs:end:read_minter + let amount = U128::from_integer(amount); + let new_balance = storage.public_balances.at(to).read().add(amount); + let supply = storage.total_supply.read().add(amount); + storage.public_balances.at(to).write(new_balance); + storage.total_supply.write(supply); + } + // docs:end:mint_public + // docs:start:mint_private + #[public] + fn mint_private(amount: Field, secret_hash: Field) { + assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); + let pending_shields = storage.pending_shields; + let mut note = TransparentNote::new(amount, secret_hash); + let supply = storage.total_supply.read().add(U128::from_integer(amount)); + storage.total_supply.write(supply); + // docs:start:insert_from_public + pending_shields.insert_from_public(&mut note); + // docs:end:insert_from_public + } + // docs:end:mint_private + // TODO: Nuke this - test functions do not belong to token contract! + #[private] + fn privately_mint_private_note(amount: Field) { + let caller = context.msg_sender(); + let caller_keys = get_current_public_keys(&mut context, caller); + storage.balances.at(caller).add(caller_keys.npk_m, U128::from_integer(amount)).emit( + encode_and_encrypt_note_with_keys(&mut context, caller_keys.ovpk_m, caller_keys.ivpk_m, caller) + ); + Token::at(context.this_address()).assert_minter_and_mint(context.msg_sender(), amount).enqueue(&mut context); + } + #[public] + #[internal] + fn assert_minter_and_mint(minter: AztecAddress, amount: Field) { + assert(storage.minters.at(minter).read(), "caller is not minter"); + let supply = storage.total_supply.read() + U128::from_integer(amount); + storage.total_supply.write(supply); + } + // docs:start:shield + #[public] + fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) { + if (!from.eq(context.msg_sender())) { + // The redeem is only spendable once, so we need to ensure that you cannot insert multiple shields from the same message. + assert_current_call_valid_authwit_public(&mut context, from); + } else { + assert(nonce == 0, "invalid nonce"); + } + let amount = U128::from_integer(amount); + let from_balance = storage.public_balances.at(from).read().sub(amount); + let pending_shields = storage.pending_shields; + let mut note = TransparentNote::new(amount.to_field(), secret_hash); + storage.public_balances.at(from).write(from_balance); + pending_shields.insert_from_public(&mut note); + } + // docs:end:shield + // docs:start:transfer_public + #[public] + fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { + if (!from.eq(context.msg_sender())) { + assert_current_call_valid_authwit_public(&mut context, from); + } else { + assert(nonce == 0, "invalid nonce"); + } + let amount = U128::from_integer(amount); + let from_balance = storage.public_balances.at(from).read().sub(amount); + storage.public_balances.at(from).write(from_balance); + let to_balance = storage.public_balances.at(to).read().add(amount); + storage.public_balances.at(to).write(to_balance); + } + // docs:end:transfer_public + // docs:start:burn_public // #[public] - // #[view] - // fn public_get_symbol() -> pub FieldCompressedString { - // storage.symbol.read_public() - // } - // #[private] - // #[view] - // fn private_get_symbol() -> pub FieldCompressedString { - // storage.symbol.read_private() - // } - // #[public] - // #[view] - // fn public_get_decimals() -> pub u8 { - // // docs:start:read_decimals_public - // storage.decimals.read_public() - // // docs:end:read_decimals_public - // } - // #[private] - // #[view] - // fn private_get_decimals() -> pub u8 { - // // docs:start:read_decimals_private - // storage.decimals.read_private() - // // docs:end:read_decimals_private - // } - // // docs:start:admin - // #[public] - // #[view] - // fn admin() -> Field { - // storage.admin.read().to_field() - // } - // // docs:end:admin - // // docs:start:is_minter - // #[public] - // #[view] - // fn is_minter(minter: AztecAddress) -> bool { - // storage.minters.at(minter).read() - // } - // // docs:end:is_minter - // // docs:start:total_supply - // #[public] - // #[view] - // fn total_supply() -> Field { - // storage.total_supply.read().to_integer() - // } - // // docs:end:total_supply - // // docs:start:balance_of_public - // #[public] - // #[view] - // fn balance_of_public(owner: AztecAddress) -> Field { - // storage.public_balances.at(owner).read().to_integer() - // } - // // docs:end:balance_of_public - // // docs:start:set_minter - // #[public] - // fn set_minter(minter: AztecAddress, approve: bool) { - // // docs:start:read_admin - // assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin"); - // // docs:end:read_admin - // // docs:start:write_minter - // storage.minters.at(minter).write(approve); - // // docs:end:write_minter - // } - // // docs:end:set_minter - // // docs:start:mint_public - // #[public] - // fn mint_public(to: AztecAddress, amount: Field) { - // // docs:start:read_minter - // assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); - // // docs:end:read_minter - // let amount = U128::from_integer(amount); - // let new_balance = storage.public_balances.at(to).read().add(amount); - // let supply = storage.total_supply.read().add(amount); - // storage.public_balances.at(to).write(new_balance); - // storage.total_supply.write(supply); - // } - // // docs:end:mint_public - // // docs:start:mint_private - // #[public] - // fn mint_private(amount: Field, secret_hash: Field) { - // assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); - // let pending_shields = storage.pending_shields; - // let mut note = TransparentNote::new(amount, secret_hash); - // let supply = storage.total_supply.read().add(U128::from_integer(amount)); - // storage.total_supply.write(supply); - // // docs:start:insert_from_public - // pending_shields.insert_from_public(&mut note); - // // docs:end:insert_from_public - // } - // // docs:end:mint_private - // // TODO: Nuke this - test functions do not belong to token contract! - // #[private] - // fn privately_mint_private_note(amount: Field) { - // let caller = context.msg_sender(); - // let caller_keys = get_current_public_keys(&mut context, caller); - // storage.balances.at(caller).add(caller_keys.npk_m, U128::from_integer(amount)).emit( - // encode_and_encrypt_note_with_keys(&mut context, caller_keys.ovpk_m, caller_keys.ivpk_m, caller) - // ); - // Token::at(context.this_address()).assert_minter_and_mint(context.msg_sender(), amount).enqueue(&mut context); - // } - // #[public] - // #[internal] - // fn assert_minter_and_mint(minter: AztecAddress, amount: Field) { - // assert(storage.minters.at(minter).read(), "caller is not minter"); - // let supply = storage.total_supply.read() + U128::from_integer(amount); - // storage.total_supply.write(supply); - // } - // // docs:start:shield - // #[public] - // fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) { - // if (!from.eq(context.msg_sender())) { - // // The redeem is only spendable once, so we need to ensure that you cannot insert multiple shields from the same message. - // assert_current_call_valid_authwit_public(&mut context, from); - // } else { - // assert(nonce == 0, "invalid nonce"); - // } - // let amount = U128::from_integer(amount); - // let from_balance = storage.public_balances.at(from).read().sub(amount); - // let pending_shields = storage.pending_shields; - // let mut note = TransparentNote::new(amount.to_field(), secret_hash); - // storage.public_balances.at(from).write(from_balance); - // pending_shields.insert_from_public(&mut note); - // } - // // docs:end:shield - // // docs:start:transfer_public - // #[public] - // fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { - // if (!from.eq(context.msg_sender())) { - // assert_current_call_valid_authwit_public(&mut context, from); - // } else { - // assert(nonce == 0, "invalid nonce"); - // } - // let amount = U128::from_integer(amount); - // let from_balance = storage.public_balances.at(from).read().sub(amount); - // storage.public_balances.at(from).write(from_balance); - // let to_balance = storage.public_balances.at(to).read().add(amount); - // storage.public_balances.at(to).write(to_balance); - // } - // // docs:end:transfer_public - // // docs:start:burn_public - // #[public] - // fn burn_public(from: AztecAddress, amount: Field, nonce: Field) { - // // docs:start:assert_current_call_valid_authwit_public - // if (!from.eq(context.msg_sender())) { - // assert_current_call_valid_authwit_public(&mut context, from); - // } else { - // assert(nonce == 0, "invalid nonce"); - // } - // // docs:end:assert_current_call_valid_authwit_public - // let amount = U128::from_integer(amount); - // let from_balance = storage.public_balances.at(from).read().sub(amount); - // storage.public_balances.at(from).write(from_balance); - // let new_supply = storage.total_supply.read().sub(amount); - // storage.total_supply.write(new_supply); - // } - // // docs:end:burn_public - // // docs:start:redeem_shield - // #[private] - // fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) { - // let secret_hash = compute_secret_hash(secret); - // // Pop 1 note (set_limit(1)) which has an amount stored in a field with index 0 (select(0, amount)) and - // // a secret_hash stored in a field with index 1 (select(1, secret_hash)). - // let mut options = NoteGetterOptions::new(); - // options = options.select(TransparentNote::properties().amount, amount, Option::none()).select( - // TransparentNote::properties().secret_hash, - // secret_hash, - // Option::none() - // ).set_limit(1); - // let notes = storage.pending_shields.pop_notes(options); - // assert(notes.len() == 1, "note not popped"); - // // Add the token note to user's balances set - // // Note: Using context.msg_sender() as a sender below makes this incompatible with escrows because we send - // // outgoing logs to that address and to send outgoing logs you need to get a hold of ovsk_m. - // let from = context.msg_sender(); - // let from_keys = get_current_public_keys(&mut context, from); - // let to_keys = get_current_public_keys(&mut context, to); - // storage.balances.at(to).add(to_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to)); - // } - // // docs:end:redeem_shield - // // docs:start:unshield - // #[private] - // fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { - // if (!from.eq(context.msg_sender())) { - // assert_current_call_valid_authwit(&mut context, from); - // } else { - // assert(nonce == 0, "invalid nonce"); - // } - // let from_keys = get_current_public_keys(&mut context, from); - // storage.balances.at(from).sub(from_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); - // Token::at(context.this_address())._increase_public_balance(to, amount).enqueue(&mut context); - // } - // // docs:end:unshield - // // docs:start:transfer - // #[private] - // fn transfer(to: AztecAddress, amount: Field) { - // let from = context.msg_sender(); - // let from_keys = get_current_public_keys(&mut context, from); - // let to_keys = get_current_public_keys(&mut context, to); - // let amount = U128::from_integer(amount); - // // We reduce `from`'s balance by amount by recursively removing notes over potentially multiple calls. This - // // method keeps the gate count for each individual call low - reading too many notes at once could result in - // // circuits in which proving is not feasible. - // // Since the sum of the amounts in the notes we nullified was potentially larger than amount, we create a new - // // note for `from` with the change amount, e.g. if `amount` is 10 and two notes are nullified with amounts 8 and - // // 5, then the change will be 3 (since 8 + 5 - 10 = 3). - // let change = subtract_balance( - // &mut context, - // storage, - // from, - // amount, - // INITIAL_TRANSFER_CALL_MAX_NOTES - // ); - // storage.balances.at(from).add(from_keys.npk_m, change).emit( - // encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from) - // ); - // storage.balances.at(to).add(to_keys.npk_m, amount).emit( - // encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to) - // ); - // // We don't constrain encryption of the note log in `transfer` (unlike in `transfer_from`) because the transfer - // // function is only designed to be used in situations where the event is not strictly necessary (e.g. payment to - // // another person where the payment is considered to be successful when the other party successfully decrypts a - // // note). - // Transfer { from, to, amount: amount.to_field() }.emit( - // encode_and_encrypt_event_with_keys_unconstrained(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to) - // ); - // } - // // docs:end:transfer - // #[contract_library_method] - // fn subtract_balance( - // context: &mut PrivateContext, - // storage: Storage<&mut PrivateContext>, - // account: AztecAddress, - // amount: U128, - // max_notes: u32 - // ) -> U128 { - // let subtracted = storage.balances.at(account).try_sub(amount, max_notes); - // // Failing to subtract any amount means that the owner was unable to produce more notes that could be nullified. - // // We could in some cases fail early inside try_sub if we detected that fewer notes than the maximum were - // // returned and we were still unable to reach the target amount, but that'd make the code more complicated, and - // // optimizing for the failure scenario is not as important. - // assert(subtracted > U128::from_integer(0), "Balance too low"); - // if subtracted >= amount { - // // We have achieved our goal of nullifying notes that add up to more than amount, so we return the change - // subtracted - amount - // } else { - // // try_sub failed to nullify enough notes to reach the target amount, so we compute the amount remaining - // // and try again. - // let remaining = amount - subtracted; - // compute_recurse_subtract_balance_call(*context, account, remaining).call(context) - // } - // } - // // TODO(#7729): apply no_predicates to the contract interface method directly instead of having to use a wrapper - // // like we do here. - // #[no_predicates] - // #[contract_library_method] - // fn compute_recurse_subtract_balance_call( - // context: PrivateContext, - // account: AztecAddress, - // remaining: U128 - // ) -> PrivateCallInterface<25, U128, (AztecAddress, Field)> { - // Token::at(context.this_address())._recurse_subtract_balance(account, remaining.to_field()) - // } - // // TODO(#7728): even though the amount should be a U128, we can't have that type in a contract interface due to - // // serialization issues. - // #[internal] - // #[private] - // fn _recurse_subtract_balance(account: AztecAddress, amount: Field) -> U128 { - // subtract_balance( - // &mut context, - // storage, - // account, - // U128::from_integer(amount), - // RECURSIVE_TRANSFER_CALL_MAX_NOTES - // ) - // } - // /** - // * Cancel a private authentication witness. - // * @param inner_hash The inner hash of the authwit to cancel. - // */ - // // docs:start:cancel_authwit - // #[private] - // fn cancel_authwit(inner_hash: Field) { - // let on_behalf_of = context.msg_sender(); - // let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash); - // context.push_nullifier(nullifier); - // } - // // docs:end:cancel_authwit - // // docs:start:transfer_from - // #[private] - // fn transfer_from(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { - // // docs:start:assert_current_call_valid_authwit - // if (!from.eq(context.msg_sender())) { - // assert_current_call_valid_authwit(&mut context, from); - // } else { - // assert(nonce == 0, "invalid nonce"); - // } - // // docs:end:assert_current_call_valid_authwit - // let from_keys = get_current_public_keys(&mut context, from); - // let to_keys = get_current_public_keys(&mut context, to); - // let amount = U128::from_integer(amount); - // // docs:start:increase_private_balance - // // docs:start:encrypted - // storage.balances.at(from).sub(from_keys.npk_m, amount).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); - // // docs:end:encrypted - // // docs:end:increase_private_balance - // storage.balances.at(to).add(to_keys.npk_m, amount).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to)); - // } - // // docs:end:transfer_from - // // docs:start:burn - // #[private] - // fn burn(from: AztecAddress, amount: Field, nonce: Field) { - // if (!from.eq(context.msg_sender())) { - // assert_current_call_valid_authwit(&mut context, from); - // } else { - // assert(nonce == 0, "invalid nonce"); - // } - // let from_keys = get_current_public_keys(&mut context, from); - // storage.balances.at(from).sub(from_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); - // Token::at(context.this_address())._reduce_total_supply(amount).enqueue(&mut context); - // } - // // docs:end:burn - // /// We need to use different randomness for the user and for the fee payer notes because if the randomness values - // /// were the same we could fingerprint the user by doing the following: - // /// 1) randomness_influence = fee_payer_point - G_npk * fee_payer_npk = - // /// = (G_npk * fee_payer_npk + G_rnd * randomness + G_slot * fee_payer_slot) - // /// - G_npk * fee_payer_npk - G_slot * fee_payer_slot = - // /// = G_rnd * randomness - // /// 2) user_fingerprint = user_point - randomness_influence = - // /// = (G_npk * user_npk + G_rnd * randomness + G_slot * user_slot) - G_rnd * randomness = - // /// = G_npk * user_npk + G_slot * user_slot - // /// 3) Then the second time the user would use this fee paying contract we would recover the same fingerprint - // /// and link that the 2 transactions were made by the same user. Given that it's expected that only - // /// a limited set of fee paying contracts will be used and they will be known, searching for fingerprints - // /// by trying different fee payers is a feasible attack. - // /// - // /// Note 1: fee_payer_npk is publicly available in a key registry contract under a fee_payer address. So if we have - // /// a known set of fee payer contract addresses getting fee_payer_npk and fee_payer_slot is trivial (slot - // /// is derived in a `Map<...>` as a hash of balances map slot and a fee payer address). - // /// Note 2: fee_payer_point and user_point above are public information because they are passed as args to - // /// the public `complete_refund(...)` function. - // // docs:start:setup_refund - // #[private] - // fn setup_refund( - // fee_payer: AztecAddress, // Address of the entity which will receive the fee note. - // user: AztecAddress, // A user for which we are setting up the fee refund. - // funded_amount: Field, // The amount the user funded the fee payer with (represents fee limit). - // user_randomness: Field, // A randomness to mix in with the generated refund note for the sponsored user. - // fee_payer_randomness: Field // A randomness to mix in with the generated fee note for the fee payer. - // ) { - // // 1. This function is called by fee paying contract (fee_payer) when setting up a refund so we need to support - // // the authwit flow here and check that the user really permitted fee_payer to set up a refund on their behalf. - // assert_current_call_valid_authwit(&mut context, user); - // // 2. Get all the relevant keys - // let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); - // let user_keys = get_current_public_keys(&mut context, user); - // let user_npk_m_hash = user_keys.npk_m.hash(); - // // 3. Deduct the funded amount from the user's balance - this is a maximum fee a user is willing to pay - // // (called fee limit in aztec spec). The difference between fee limit and the actual tx fee will be refunded - // // to the user in the `complete_refund(...)` function. - // let change = subtract_balance( - // &mut context, - // storage, - // user, - // U128::from_integer(funded_amount), - // INITIAL_TRANSFER_CALL_MAX_NOTES - // ); - // storage.balances.at(user).add(user_keys.npk_m, change).emit( - // encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) - // ); - // // 4. We create the partial notes for the fee payer and the user. - // // --> Called "partial" because they don't have the amount set yet (that will be done in `complete_refund(...)`). - // let fee_payer_partial_note = TokenNote { - // header: NoteHeader { - // contract_address: AztecAddress::zero(), - // nonce: 0, - // storage_slot: storage.balances.at(fee_payer).set.storage_slot, - // note_hash_counter: 0 - // }, - // amount: U128::zero(), - // npk_m_hash: fee_payer_npk_m_hash, - // randomness: fee_payer_randomness - // }; - // let user_partial_note = TokenNote { - // header: NoteHeader { - // contract_address: AztecAddress::zero(), - // nonce: 0, - // storage_slot: storage.balances.at(user).set.storage_slot, - // note_hash_counter: 0 - // }, - // amount: U128::zero(), - // npk_m_hash: user_npk_m_hash, - // randomness: user_randomness - // }; - // // 5. Now we get the note hiding points. - // let mut fee_payer_point = fee_payer_partial_note.to_note_hiding_point(); - // let mut user_point = user_partial_note.to_note_hiding_point(); - // // 6. Set the public teardown function to `complete_refund(...)`. Public teardown is the only time when a public - // // function has access to the final transaction fee, which is needed to compute the actual refund amount. - // context.set_public_teardown_function( - // context.this_address(), - // comptime { - // FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") - // }, - // [ - // fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount - // ] - // ); - // } - // // docs:end:setup_refund - // // TODO(#7728): even though the funded_amount should be a U128, we can't have that type in a contract interface due - // // to serialization issues. - // // docs:start:complete_refund - // #[public] - // #[internal] - // fn complete_refund( - // // TODO(#7771): the following makes macros crash --> try getting it work once we migrate to metaprogramming - // // mut fee_payer_point: TokenNoteHidingPoint, - // // mut user_point: TokenNoteHidingPoint, - // fee_payer_point_immutable: TokenNoteHidingPoint, - // user_point_immutable: TokenNoteHidingPoint, - // funded_amount: Field - // ) { - // // TODO(#7771): nuke the following 2 lines once we have mutable args - // let mut fee_payer_point = fee_payer_point_immutable; - // let mut user_point = user_point_immutable; - // // TODO(#7728): Remove the next line - // let funded_amount = U128::from_integer(funded_amount); - // let tx_fee = U128::from_integer(context.transaction_fee()); - // // 1. We check that user funded the fee payer contract with at least the transaction fee. - // // TODO(#7796): we should try to prevent reverts here - // assert(funded_amount >= tx_fee, "funded amount not enough to cover tx fee"); - // // 2. We compute the refund amount as the difference between funded amount and tx fee. - // let refund_amount = funded_amount - tx_fee; - // // 3. We add fee to the fee payer point and refund amount to the user point. - // fee_payer_point.add_amount(tx_fee); - // user_point.add_amount(refund_amount); - // // 4. We finalize the hiding points to get the note hashes. - // let fee_payer_note_hash = fee_payer_point.finalize(); - // let user_note_hash = user_point.finalize(); - // // 5. At last we emit the note hashes. - // context.push_note_hash(fee_payer_note_hash); - // context.push_note_hash(user_note_hash); - // // --> Once the tx is settled user and fee recipient can add the notes to their pixies. - // } - // // docs:end:complete_refund - // /// Internal /// - // // docs:start:increase_public_balance - // #[public] - // #[internal] - // fn _increase_public_balance(to: AztecAddress, amount: Field) { - // let new_balance = storage.public_balances.at(to).read().add(U128::from_integer(amount)); - // storage.public_balances.at(to).write(new_balance); - // } - // // docs:end:increase_public_balance - // // docs:start:reduce_total_supply - // #[public] - // #[internal] - // fn _reduce_total_supply(amount: Field) { - // // Only to be called from burn. - // let new_supply = storage.total_supply.read().sub(U128::from_integer(amount)); - // storage.total_supply.write(new_supply); - // } - // // docs:end:reduce_total_supply - // /// Unconstrained /// - // // docs:start:balance_of_private - // unconstrained fn balance_of_private(owner: AztecAddress) -> pub Field { - // storage.balances.at(owner).balance_of().to_field() - // } - // // docs:end:balance_of_private + fn burn_public(from: AztecAddress, amount: Field, nonce: Field) { + // docs:start:assert_current_call_valid_authwit_public + if (!from.eq(context.msg_sender())) { + assert_current_call_valid_authwit_public(&mut context, from); + } else { + assert(nonce == 0, "invalid nonce"); + } + // docs:end:assert_current_call_valid_authwit_public + let amount = U128::from_integer(amount); + let from_balance = storage.public_balances.at(from).read().sub(amount); + storage.public_balances.at(from).write(from_balance); + let new_supply = storage.total_supply.read().sub(amount); + storage.total_supply.write(new_supply); + } + // docs:end:burn_public + // docs:start:redeem_shield + #[private] + fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) { + let secret_hash = compute_secret_hash(secret); + // Pop 1 note (set_limit(1)) which has an amount stored in a field with index 0 (select(0, amount)) and + // a secret_hash stored in a field with index 1 (select(1, secret_hash)). + let mut options = NoteGetterOptions::new(); + options = options.select(TransparentNote::properties().amount, amount, Option::none()).select( + TransparentNote::properties().secret_hash, + secret_hash, + Option::none() + ).set_limit(1); + let notes = storage.pending_shields.pop_notes(options); + assert(notes.len() == 1, "note not popped"); + // Add the token note to user's balances set + // Note: Using context.msg_sender() as a sender below makes this incompatible with escrows because we send + // outgoing logs to that address and to send outgoing logs you need to get a hold of ovsk_m. + let from = context.msg_sender(); + let from_keys = get_current_public_keys(&mut context, from); + let to_keys = get_current_public_keys(&mut context, to); + storage.balances.at(to).add(to_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to)); + } + // docs:end:redeem_shield + // docs:start:unshield + #[private] + fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { + if (!from.eq(context.msg_sender())) { + assert_current_call_valid_authwit(&mut context, from); + } else { + assert(nonce == 0, "invalid nonce"); + } + let from_keys = get_current_public_keys(&mut context, from); + storage.balances.at(from).sub(from_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); + Token::at(context.this_address())._increase_public_balance(to, amount).enqueue(&mut context); + } + // docs:end:unshield + // docs:start:transfer + #[private] + fn transfer(to: AztecAddress, amount: Field) { + let from = context.msg_sender(); + let from_keys = get_current_public_keys(&mut context, from); + let to_keys = get_current_public_keys(&mut context, to); + let amount = U128::from_integer(amount); + // We reduce `from`'s balance by amount by recursively removing notes over potentially multiple calls. This + // method keeps the gate count for each individual call low - reading too many notes at once could result in + // circuits in which proving is not feasible. + // Since the sum of the amounts in the notes we nullified was potentially larger than amount, we create a new + // note for `from` with the change amount, e.g. if `amount` is 10 and two notes are nullified with amounts 8 and + // 5, then the change will be 3 (since 8 + 5 - 10 = 3). + let change = subtract_balance( + &mut context, + storage, + from, + amount, + INITIAL_TRANSFER_CALL_MAX_NOTES + ); + storage.balances.at(from).add(from_keys.npk_m, change).emit( + encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from) + ); + storage.balances.at(to).add(to_keys.npk_m, amount).emit( + encode_and_encrypt_note_with_keys_unconstrained(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to) + ); + // We don't constrain encryption of the note log in `transfer` (unlike in `transfer_from`) because the transfer + // function is only designed to be used in situations where the event is not strictly necessary (e.g. payment to + // another person where the payment is considered to be successful when the other party successfully decrypts a + // note). + Transfer { from, to, amount: amount.to_field() }.emit( + encode_and_encrypt_event_with_keys_unconstrained(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to) + ); + } + // docs:end:transfer + #[contract_library_method] + fn subtract_balance( + context: &mut PrivateContext, + storage: Storage<&mut PrivateContext>, + account: AztecAddress, + amount: U128, + max_notes: u32 + ) -> U128 { + let subtracted = storage.balances.at(account).try_sub(amount, max_notes); + // Failing to subtract any amount means that the owner was unable to produce more notes that could be nullified. + // We could in some cases fail early inside try_sub if we detected that fewer notes than the maximum were + // returned and we were still unable to reach the target amount, but that'd make the code more complicated, and + // optimizing for the failure scenario is not as important. + assert(subtracted > U128::from_integer(0), "Balance too low"); + if subtracted >= amount { + // We have achieved our goal of nullifying notes that add up to more than amount, so we return the change + subtracted - amount + } else { + // try_sub failed to nullify enough notes to reach the target amount, so we compute the amount remaining + // and try again. + let remaining = amount - subtracted; + compute_recurse_subtract_balance_call(*context, account, remaining).call(context) + } + } + // TODO(#7729): apply no_predicates to the contract interface method directly instead of having to use a wrapper + // like we do here. + #[no_predicates] + #[contract_library_method] + fn compute_recurse_subtract_balance_call( + context: PrivateContext, + account: AztecAddress, + remaining: U128 + ) -> PrivateCallInterface<25, U128, (AztecAddress, Field)> { + Token::at(context.this_address())._recurse_subtract_balance(account, remaining.to_field()) + } + // TODO(#7728): even though the amount should be a U128, we can't have that type in a contract interface due to + // serialization issues. + #[internal] + #[private] + fn _recurse_subtract_balance(account: AztecAddress, amount: Field) -> U128 { + subtract_balance( + &mut context, + storage, + account, + U128::from_integer(amount), + RECURSIVE_TRANSFER_CALL_MAX_NOTES + ) + } + /** + * Cancel a private authentication witness. + * @param inner_hash The inner hash of the authwit to cancel. + */ + // docs:start:cancel_authwit + #[private] + fn cancel_authwit(inner_hash: Field) { + let on_behalf_of = context.msg_sender(); + let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash); + context.push_nullifier(nullifier); + } + // docs:end:cancel_authwit + // docs:start:transfer_from + #[private] + fn transfer_from(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { + // docs:start:assert_current_call_valid_authwit + if (!from.eq(context.msg_sender())) { + assert_current_call_valid_authwit(&mut context, from); + } else { + assert(nonce == 0, "invalid nonce"); + } + // docs:end:assert_current_call_valid_authwit + let from_keys = get_current_public_keys(&mut context, from); + let to_keys = get_current_public_keys(&mut context, to); + let amount = U128::from_integer(amount); + // docs:start:increase_private_balance + // docs:start:encrypted + storage.balances.at(from).sub(from_keys.npk_m, amount).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); + // docs:end:encrypted + // docs:end:increase_private_balance + storage.balances.at(to).add(to_keys.npk_m, amount).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, to_keys.ivpk_m, to)); + } + // docs:end:transfer_from + // docs:start:burn + #[private] + fn burn(from: AztecAddress, amount: Field, nonce: Field) { + if (!from.eq(context.msg_sender())) { + assert_current_call_valid_authwit(&mut context, from); + } else { + assert(nonce == 0, "invalid nonce"); + } + let from_keys = get_current_public_keys(&mut context, from); + storage.balances.at(from).sub(from_keys.npk_m, U128::from_integer(amount)).emit(encode_and_encrypt_note_with_keys(&mut context, from_keys.ovpk_m, from_keys.ivpk_m, from)); + Token::at(context.this_address())._reduce_total_supply(amount).enqueue(&mut context); + } + // docs:end:burn + /// We need to use different randomness for the user and for the fee payer notes because if the randomness values + /// were the same we could fingerprint the user by doing the following: + /// 1) randomness_influence = fee_payer_point - G_npk * fee_payer_npk = + /// = (G_npk * fee_payer_npk + G_rnd * randomness + G_slot * fee_payer_slot) + /// - G_npk * fee_payer_npk - G_slot * fee_payer_slot = + /// = G_rnd * randomness + /// 2) user_fingerprint = user_point - randomness_influence = + /// = (G_npk * user_npk + G_rnd * randomness + G_slot * user_slot) - G_rnd * randomness = + /// = G_npk * user_npk + G_slot * user_slot + /// 3) Then the second time the user would use this fee paying contract we would recover the same fingerprint + /// and link that the 2 transactions were made by the same user. Given that it's expected that only + /// a limited set of fee paying contracts will be used and they will be known, searching for fingerprints + /// by trying different fee payers is a feasible attack. + /// + /// Note 1: fee_payer_npk is publicly available in a key registry contract under a fee_payer address. So if we have + /// a known set of fee payer contract addresses getting fee_payer_npk and fee_payer_slot is trivial (slot + /// is derived in a `Map<...>` as a hash of balances map slot and a fee payer address). + /// Note 2: fee_payer_point and user_point above are public information because they are passed as args to + /// the public `complete_refund(...)` function. + // docs:start:setup_refund + #[private] + fn setup_refund( + fee_payer: AztecAddress, // Address of the entity which will receive the fee note. + user: AztecAddress, // A user for which we are setting up the fee refund. + funded_amount: Field, // The amount the user funded the fee payer with (represents fee limit). + user_randomness: Field, // A randomness to mix in with the generated refund note for the sponsored user. + fee_payer_randomness: Field // A randomness to mix in with the generated fee note for the fee payer. + ) { + // 1. This function is called by fee paying contract (fee_payer) when setting up a refund so we need to support + // the authwit flow here and check that the user really permitted fee_payer to set up a refund on their behalf. + assert_current_call_valid_authwit(&mut context, user); + // 2. Get all the relevant keys + let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); + let user_keys = get_current_public_keys(&mut context, user); + let user_npk_m_hash = user_keys.npk_m.hash(); + // 3. Deduct the funded amount from the user's balance - this is a maximum fee a user is willing to pay + // (called fee limit in aztec spec). The difference between fee limit and the actual tx fee will be refunded + // to the user in the `complete_refund(...)` function. + let change = subtract_balance( + &mut context, + storage, + user, + U128::from_integer(funded_amount), + INITIAL_TRANSFER_CALL_MAX_NOTES + ); + storage.balances.at(user).add(user_keys.npk_m, change).emit( + encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) + ); + // 4. We create the partial notes for the fee payer and the user. + // --> Called "partial" because they don't have the amount set yet (that will be done in `complete_refund(...)`). + let fee_payer_partial_note = TokenNote { + header: NoteHeader { + contract_address: AztecAddress::zero(), + nonce: 0, + storage_slot: storage.balances.at(fee_payer).set.storage_slot, + note_hash_counter: 0 + }, + amount: U128::zero(), + npk_m_hash: fee_payer_npk_m_hash, + randomness: fee_payer_randomness + }; + let user_partial_note = TokenNote { + header: NoteHeader { + contract_address: AztecAddress::zero(), + nonce: 0, + storage_slot: storage.balances.at(user).set.storage_slot, + note_hash_counter: 0 + }, + amount: U128::zero(), + npk_m_hash: user_npk_m_hash, + randomness: user_randomness + }; + // 5. Now we get the note hiding points. + let mut fee_payer_point = fee_payer_partial_note.to_note_hiding_point(); + let mut user_point = user_partial_note.to_note_hiding_point(); + // 6. Set the public teardown function to `complete_refund(...)`. Public teardown is the only time when a public + // function has access to the final transaction fee, which is needed to compute the actual refund amount. + context.set_public_teardown_function( + context.this_address(), + comptime { + FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") + }, + [ + fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount + ] + ); + } + // docs:end:setup_refund + // TODO(#7728): even though the funded_amount should be a U128, we can't have that type in a contract interface due + // to serialization issues. + // docs:start:complete_refund + #[public] + #[internal] + fn complete_refund( + // TODO(#7771): the following makes macros crash --> try getting it work once we migrate to metaprogramming + // mut fee_payer_point: TokenNoteHidingPoint, + // mut user_point: TokenNoteHidingPoint, + fee_payer_point_immutable: TokenNoteHidingPoint, + user_point_immutable: TokenNoteHidingPoint, + funded_amount: Field + ) { + // TODO(#7771): nuke the following 2 lines once we have mutable args + let mut fee_payer_point = fee_payer_point_immutable; + let mut user_point = user_point_immutable; + // TODO(#7728): Remove the next line + let funded_amount = U128::from_integer(funded_amount); + let tx_fee = U128::from_integer(context.transaction_fee()); + // 1. We check that user funded the fee payer contract with at least the transaction fee. + // TODO(#7796): we should try to prevent reverts here + assert(funded_amount >= tx_fee, "funded amount not enough to cover tx fee"); + // 2. We compute the refund amount as the difference between funded amount and tx fee. + let refund_amount = funded_amount - tx_fee; + // 3. We add fee to the fee payer point and refund amount to the user point. + fee_payer_point.add_amount(tx_fee); + user_point.add_amount(refund_amount); + // 4. We finalize the hiding points to get the note hashes. + let fee_payer_note_hash = fee_payer_point.finalize(); + let user_note_hash = user_point.finalize(); + // 5. At last we emit the note hashes. + context.push_note_hash(fee_payer_note_hash); + context.push_note_hash(user_note_hash); + // --> Once the tx is settled user and fee recipient can add the notes to their pixies. + } + // docs:end:complete_refund + /// Internal /// + // docs:start:increase_public_balance + #[public] + #[internal] + fn _increase_public_balance(to: AztecAddress, amount: Field) { + let new_balance = storage.public_balances.at(to).read().add(U128::from_integer(amount)); + storage.public_balances.at(to).write(new_balance); + } + // docs:end:increase_public_balance + // docs:start:reduce_total_supply + #[public] + #[internal] + fn _reduce_total_supply(amount: Field) { + // Only to be called from burn. + let new_supply = storage.total_supply.read().sub(U128::from_integer(amount)); + storage.total_supply.write(new_supply); + } + // docs:end:reduce_total_supply + /// Unconstrained /// + // docs:start:balance_of_private + unconstrained fn balance_of_private(owner: AztecAddress) -> pub Field { + storage.balances.at(owner).balance_of().to_field() + } + // docs:end:balance_of_private } // docs:end:token_all From 14a2fd1a46e616843e7d176cf51cc9332ab00cfa Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 16 Sep 2024 11:35:59 +0000 Subject: [PATCH 11/79] heck yeah --- .../aztec-nr/aztec/src/macros/events/mod.nr | 76 ++++++ .../aztec-nr/aztec/src/macros/mod.nr | 1 + .../aztec-nr/aztec/src/macros/utils.nr | 79 ++++++- .../aztec/src/note/note_getter/mod.nr | 12 +- .../aztec/src/note/note_getter_options.nr | 2 +- .../contracts/counter_contract/src/main.nr | 10 +- .../contracts/token_contract/src/main.nr | 216 +++++++++--------- .../crates/types/src/utils/arrays/sort_by.nr | 22 -- 8 files changed, 268 insertions(+), 150 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/macros/events/mod.nr diff --git a/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr new file mode 100644 index 00000000000..9b642e6afff --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr @@ -0,0 +1,76 @@ +use protocol_types::meta::flatten_to_fields; +use super::utils::compute_event_selector; + +comptime fn generate_event_interface(s: StructDefinition) -> Quoted { + let name = s.name(); + let typ = s.as_type(); + let (fields, _) = flatten_to_fields(quote { self }, typ, &[quote {self.header}]); + let content_len = fields.len(); + + let event_type_id = compute_event_selector(s); + + quote { + impl aztec::event::event_interface::EventInterface<$content_len> for $name { + + fn private_to_be_bytes(self, randomness: Field) -> [u8; $content_len * 32 + 64] { + let mut buffer: [u8; $content_len * 32 + 64] = [0; $content_len * 32 + 64]; + + let randomness_bytes: [u8; 32] = randomness.to_be_bytes(); + let event_type_id_bytes: [u8; 32] = $name::get_event_type_id().to_field().to_be_bytes(); + + for i in 0..32 { + buffer[i] = randomness_bytes[i]; + buffer[32 + i] = event_type_id_bytes[i]; + } + + let serialized_event = self.serialize(); + + for i in 0..serialized_event.len() { + let bytes: [u8; 32] = serialized_event[i].to_be_bytes(); + for j in 0..32 { + buffer[64 + i * 32 + j] = bytes[j]; + } + } + + buffer + } + + fn to_be_bytes(self) -> [u8; $content_len * 32 + 32] { + let mut buffer: [u8; $content_len * 32 + 32] = [0; $content_len * 32 + 32]; + + let event_type_id_bytes: [u8; 32] = $name::get_event_type_id().to_field().to_be_bytes(); + + for i in 0..32 { + buffer[32 + i] = event_type_id_bytes[i]; + } + + let serialized_event = self.serialize(); + + for i in 0..serialized_event.len() { + let bytes: [u8; 32] = serialized_event[i].to_be_bytes(); + for j in 0..32 { + buffer[64 + i * 32 + j] = bytes[j]; + } + } + + buffer + } + + fn get_event_type_id() -> aztec::protocol_types::abis::event_selector::EventSelector { + $event_type_id + } + + fn emit(self, _emit: fn[Env](Self) -> ()) { + _emit(self); + } + } + } +} + +pub comptime fn event(s: StructDefinition) -> Quoted { + let event_interface = generate_event_interface(s); + s.add_attribute("abi(events)"); + quote { + $event_interface + } +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 9ba5b12b1c7..9f598398000 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -2,6 +2,7 @@ mod functions; mod utils; mod notes; mod storage; +mod events; use functions::STUBS; use storage::STORAGE_LAYOUT_NAME; diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 01d93bc6dc5..1d7504a4a2a 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -32,18 +32,61 @@ pub(crate) comptime fn fn_has_noinitcheck(f: FunctionDefinition) -> bool { f.has_named_attribute("noinitcheck") } -pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quoted) -> Expr { - let mut body_quote = body.fold( - quote {}, - |body_quote: Quoted, expr: Expr| { - let expr_quote = expr.quoted(); - let semicolon = if expr_quote.as_expr().is_some() { quote {} } else { quote {;} }; +// This is probably a terrible hack +pub(crate) comptime fn expr_as_quoted_fixed(expr: Expr) -> Quoted { + if expr.as_let().is_some() { + let quoted = expr.quoted(); + // Let statements lose semicolons + quote { $quoted; } + } else if expr.as_assert().is_some() { + let (assertion, _message) = expr.as_assert().unwrap(); + // Assertions with messages bork the compiler at compiler/noirc_frontend/src/node_interner.rs:1145 + quote { assert($assertion); } + } else if expr.as_unsafe().is_some() { + // Unsafe blocks require semicolons for some reason? Not if I write them manually + let unsafe_expr = expr.as_unsafe().unwrap(); + let unsafe_quote = expr_slice_as_quoted_fixed(unsafe_expr); + quote { unsafe { $unsafe_quote }; } + } else if expr.as_if().is_some() { + let (condition, if_branch, else_branch) = expr.as_if().unwrap(); + let fixed_if = expr_as_quoted_fixed(if_branch); + // Fix the branches + if else_branch.is_some() { + let fixed_else = expr_as_quoted_fixed(else_branch.unwrap()); + quote { if $condition { $fixed_if } else { $fixed_else } } + } else { + quote { if $condition { $fixed_if } } + } + } else if expr.as_for().is_some() { + // Fix the for body + let (variable, iterable, body) = expr.as_for().unwrap(); + let fixed_body = expr_as_quoted_fixed(body); + quote { for $variable in $iterable $fixed_body } + } else if expr.as_block().is_some() { + let fixed = expr_slice_as_quoted_fixed(expr.as_block().unwrap()); quote { - $body_quote - $expr_quote$semicolon + { $fixed } } - } - ); + } else { + quote { $expr } + } +} + +pub(crate) comptime fn expr_slice_as_quoted_fixed(exprs: [Expr]) -> Quoted { + exprs.fold( + quote {}, + |full_quote: Quoted, expr: Expr| { + let expr_quote = expr_as_quoted_fixed(expr); + quote { + $full_quote + $expr_quote + } + } + ) +} + +pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quoted) -> Expr { + let mut body_quote = expr_slice_as_quoted_fixed(body); body_quote = quote { { $prepend @@ -199,6 +242,22 @@ pub(crate) comptime fn compute_fn_selector(f: FunctionDefinition) -> Field { unquote!(computation_quote) } +pub(crate) comptime fn compute_event_selector(s: StructDefinition) -> Field { + let event_name = s.name(); + let args_signatures = s.fields().map( + | (_, typ): (Quoted, Type) | { + signature_of_type(typ) + } + ).join(quote {,}); + let signature_quote = quote { $event_name($args_signatures) }; + let signature_str_quote = signature_quote.as_str_quote(); + + let computation_quote = quote { + protocol_types::abis::event_selector::EventSelector::from_signature($signature_str_quote) + }; + unquote!(computation_quote) +} + pub(crate) comptime fn get_serialized_size(typ: Type) -> u32 { let any = fresh_type_variable(); let maybe_serialize_impl = typ.get_trait_impl(quote { protocol_types::traits::Serialize<$any> }.as_trait_constraint()); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index 5ca525f15e8..d748e33f7f1 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -34,7 +34,7 @@ fn extract_property_value_from_selector( value_field } -fn check_note_header( +fn check_note_header( context: PrivateContext, storage_slot: Field, note: Note @@ -78,7 +78,7 @@ fn check_notes_order( } } -pub fn get_note( +pub fn get_note( context: &mut PrivateContext, storage_slot: Field ) -> (Note, Field) where Note: NoteInterface + NullifiableNote + FinalizedNote { @@ -96,7 +96,7 @@ pub fn get_note( (note, note_hash_for_read_request) } -pub fn get_notes( +pub fn get_notes( context: &mut PrivateContext, storage_slot: Field, options: NoteGetterOptions @@ -118,7 +118,7 @@ unconstrained fn apply_preprocessor( preprocessor(notes, preprocessor_args) } -fn constrain_get_notes_internal( +fn constrain_get_notes_internal( context: &mut PrivateContext, storage_slot: Field, opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], @@ -163,7 +163,7 @@ fn constrain_get_notes_internal(storage_slot: Field) -> Note where Note: NoteInterface { +unconstrained fn get_note_internal(storage_slot: Field) -> Note where Note: NoteInterface { let placeholder_note = [Option::none()]; let placeholder_fields = [0; GET_NOTE_ORACLE_RETURN_LENGTH]; let placeholder_note_length = [0; N]; @@ -188,7 +188,7 @@ unconstrained fn get_note_internal(storage_slot: F )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular). } -unconstrained fn get_notes_internal( +unconstrained fn get_notes_internal( storage_slot: Field, options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr index 9d7ae804afc..23dee2c5fe7 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr @@ -129,7 +129,7 @@ impl NoteGetterOptions NoteGetterOptions where Note: NoteInterface { +impl NoteGetterOptions where Note: NoteInterface { // This function initializes a NoteGetterOptions that simply returns the maximum number of notes allowed in a call. pub fn new() -> Self { Self { diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 2161f84311f..ab69a19b18c 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -34,7 +34,7 @@ contract Counter { fn increment(owner: AztecAddress, outgoing_viewer: AztecAddress) { unsafe { dep::aztec::oracle::debug_log::debug_log_format("Incrementing counter for owner {0}", [owner.to_field()]); - }; + } let counters = storage.counters; counters.at(owner).add(1, owner, outgoing_viewer); } @@ -46,10 +46,10 @@ contract Counter { } // docs:end:get_counter // docs:start:test_imports - // use dep::aztec::test::{helpers::{test_environment::TestEnvironment}}; - // use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; - // use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; - // use dep::aztec::note::note_viewer_options::NoteViewerOptions; + use dep::aztec::test::{helpers::{test_environment::TestEnvironment}}; + use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; + use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; + use dep::aztec::note::note_viewer_options::NoteViewerOptions; // docs:end:test_imports // docs:start:txe_test_increment #[test] diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index d4266c481af..bec5c61df85 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -14,6 +14,7 @@ use dep::aztec::macros::aztec; #[aztec] contract Token { // Libs + use std::meta::derive; use dep::compressed_string::FieldCompressedString; @@ -28,7 +29,8 @@ contract Token { encrypted_event_emission::encode_and_encrypt_event_with_keys_unconstrained }, keys::getters::get_current_public_keys, - macros::{storage::storage, functions::{initializer, private, view, public}} + macros::{storage::storage, events::event, functions::{initializer, private, view, public}}, + utils::comparison::Comparator, protocol_types::traits::Serialize }; // docs:start:import_authwit @@ -36,6 +38,7 @@ contract Token { // docs:end:import_authwit use crate::types::{transparent_note::TransparentNote, token_note::TokenNote, balance_set::BalanceSet}; + // docs:end::imports // In the first transfer iteration we are computing a lot of additional information (validating inputs, retrieving @@ -47,7 +50,8 @@ contract Token { // an overall small circuit regardless. global RECURSIVE_TRANSFER_CALL_MAX_NOTES = 8; - #[aztec(event)] + #[event] + #[derive(Serialize)] struct Transfer { from: AztecAddress, to: AztecAddress, @@ -252,7 +256,7 @@ contract Token { } // docs:end:transfer_public // docs:start:burn_public - // #[public] + #[public] fn burn_public(from: AztecAddress, amount: Field, nonce: Field) { // docs:start:assert_current_call_valid_authwit_public if (!from.eq(context.msg_sender())) { @@ -453,109 +457,109 @@ contract Token { /// Note 2: fee_payer_point and user_point above are public information because they are passed as args to /// the public `complete_refund(...)` function. // docs:start:setup_refund - #[private] - fn setup_refund( - fee_payer: AztecAddress, // Address of the entity which will receive the fee note. - user: AztecAddress, // A user for which we are setting up the fee refund. - funded_amount: Field, // The amount the user funded the fee payer with (represents fee limit). - user_randomness: Field, // A randomness to mix in with the generated refund note for the sponsored user. - fee_payer_randomness: Field // A randomness to mix in with the generated fee note for the fee payer. - ) { - // 1. This function is called by fee paying contract (fee_payer) when setting up a refund so we need to support - // the authwit flow here and check that the user really permitted fee_payer to set up a refund on their behalf. - assert_current_call_valid_authwit(&mut context, user); - // 2. Get all the relevant keys - let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); - let user_keys = get_current_public_keys(&mut context, user); - let user_npk_m_hash = user_keys.npk_m.hash(); - // 3. Deduct the funded amount from the user's balance - this is a maximum fee a user is willing to pay - // (called fee limit in aztec spec). The difference between fee limit and the actual tx fee will be refunded - // to the user in the `complete_refund(...)` function. - let change = subtract_balance( - &mut context, - storage, - user, - U128::from_integer(funded_amount), - INITIAL_TRANSFER_CALL_MAX_NOTES - ); - storage.balances.at(user).add(user_keys.npk_m, change).emit( - encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) - ); - // 4. We create the partial notes for the fee payer and the user. - // --> Called "partial" because they don't have the amount set yet (that will be done in `complete_refund(...)`). - let fee_payer_partial_note = TokenNote { - header: NoteHeader { - contract_address: AztecAddress::zero(), - nonce: 0, - storage_slot: storage.balances.at(fee_payer).set.storage_slot, - note_hash_counter: 0 - }, - amount: U128::zero(), - npk_m_hash: fee_payer_npk_m_hash, - randomness: fee_payer_randomness - }; - let user_partial_note = TokenNote { - header: NoteHeader { - contract_address: AztecAddress::zero(), - nonce: 0, - storage_slot: storage.balances.at(user).set.storage_slot, - note_hash_counter: 0 - }, - amount: U128::zero(), - npk_m_hash: user_npk_m_hash, - randomness: user_randomness - }; - // 5. Now we get the note hiding points. - let mut fee_payer_point = fee_payer_partial_note.to_note_hiding_point(); - let mut user_point = user_partial_note.to_note_hiding_point(); - // 6. Set the public teardown function to `complete_refund(...)`. Public teardown is the only time when a public - // function has access to the final transaction fee, which is needed to compute the actual refund amount. - context.set_public_teardown_function( - context.this_address(), - comptime { - FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") - }, - [ - fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount - ] - ); - } - // docs:end:setup_refund - // TODO(#7728): even though the funded_amount should be a U128, we can't have that type in a contract interface due - // to serialization issues. - // docs:start:complete_refund - #[public] - #[internal] - fn complete_refund( - // TODO(#7771): the following makes macros crash --> try getting it work once we migrate to metaprogramming - // mut fee_payer_point: TokenNoteHidingPoint, - // mut user_point: TokenNoteHidingPoint, - fee_payer_point_immutable: TokenNoteHidingPoint, - user_point_immutable: TokenNoteHidingPoint, - funded_amount: Field - ) { - // TODO(#7771): nuke the following 2 lines once we have mutable args - let mut fee_payer_point = fee_payer_point_immutable; - let mut user_point = user_point_immutable; - // TODO(#7728): Remove the next line - let funded_amount = U128::from_integer(funded_amount); - let tx_fee = U128::from_integer(context.transaction_fee()); - // 1. We check that user funded the fee payer contract with at least the transaction fee. - // TODO(#7796): we should try to prevent reverts here - assert(funded_amount >= tx_fee, "funded amount not enough to cover tx fee"); - // 2. We compute the refund amount as the difference between funded amount and tx fee. - let refund_amount = funded_amount - tx_fee; - // 3. We add fee to the fee payer point and refund amount to the user point. - fee_payer_point.add_amount(tx_fee); - user_point.add_amount(refund_amount); - // 4. We finalize the hiding points to get the note hashes. - let fee_payer_note_hash = fee_payer_point.finalize(); - let user_note_hash = user_point.finalize(); - // 5. At last we emit the note hashes. - context.push_note_hash(fee_payer_note_hash); - context.push_note_hash(user_note_hash); - // --> Once the tx is settled user and fee recipient can add the notes to their pixies. - } + // #[private] + // fn setup_refund( + // fee_payer: AztecAddress, // Address of the entity which will receive the fee note. + // user: AztecAddress, // A user for which we are setting up the fee refund. + // funded_amount: Field, // The amount the user funded the fee payer with (represents fee limit). + // user_randomness: Field, // A randomness to mix in with the generated refund note for the sponsored user. + // fee_payer_randomness: Field // A randomness to mix in with the generated fee note for the fee payer. + // ) { + // // 1. This function is called by fee paying contract (fee_payer) when setting up a refund so we need to support + // // the authwit flow here and check that the user really permitted fee_payer to set up a refund on their behalf. + // assert_current_call_valid_authwit(&mut context, user); + // // 2. Get all the relevant keys + // let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); + // let user_keys = get_current_public_keys(&mut context, user); + // let user_npk_m_hash = user_keys.npk_m.hash(); + // // 3. Deduct the funded amount from the user's balance - this is a maximum fee a user is willing to pay + // // (called fee limit in aztec spec). The difference between fee limit and the actual tx fee will be refunded + // // to the user in the `complete_refund(...)` function. + // let change = subtract_balance( + // &mut context, + // storage, + // user, + // U128::from_integer(funded_amount), + // INITIAL_TRANSFER_CALL_MAX_NOTES + // ); + // storage.balances.at(user).add(user_keys.npk_m, change).emit( + // encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) + // ); + // // 4. We create the partial notes for the fee payer and the user. + // // --> Called "partial" because they don't have the amount set yet (that will be done in `complete_refund(...)`). + // let fee_payer_partial_note = TokenNote { + // header: NoteHeader { + // contract_address: AztecAddress::zero(), + // nonce: 0, + // storage_slot: storage.balances.at(fee_payer).set.storage_slot, + // note_hash_counter: 0 + // }, + // amount: U128::zero(), + // npk_m_hash: fee_payer_npk_m_hash, + // randomness: fee_payer_randomness + // }; + // let user_partial_note = TokenNote { + // header: NoteHeader { + // contract_address: AztecAddress::zero(), + // nonce: 0, + // storage_slot: storage.balances.at(user).set.storage_slot, + // note_hash_counter: 0 + // }, + // amount: U128::zero(), + // npk_m_hash: user_npk_m_hash, + // randomness: user_randomness + // }; + // // 5. Now we get the note hiding points. + // let mut fee_payer_point = fee_payer_partial_note.to_note_hiding_point(); + // let mut user_point = user_partial_note.to_note_hiding_point(); + // // 6. Set the public teardown function to `complete_refund(...)`. Public teardown is the only time when a public + // // function has access to the final transaction fee, which is needed to compute the actual refund amount. + // context.set_public_teardown_function( + // context.this_address(), + // comptime { + // FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") + // }, + // [ + // fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount + // ] + // ); + // } + // // docs:end:setup_refund + // // TODO(#7728): even though the funded_amount should be a U128, we can't have that type in a contract interface due + // // to serialization issues. + // // docs:start:complete_refund + // #[public] + // #[internal] + // fn complete_refund( + // // TODO(#7771): the following makes macros crash --> try getting it work once we migrate to metaprogramming + // // mut fee_payer_point: TokenNoteHidingPoint, + // // mut user_point: TokenNoteHidingPoint, + // fee_payer_point_immutable: TokenNoteHidingPoint, + // user_point_immutable: TokenNoteHidingPoint, + // funded_amount: Field + // ) { + // // TODO(#7771): nuke the following 2 lines once we have mutable args + // let mut fee_payer_point = fee_payer_point_immutable; + // let mut user_point = user_point_immutable; + // // TODO(#7728): Remove the next line + // let funded_amount = U128::from_integer(funded_amount); + // let tx_fee = U128::from_integer(context.transaction_fee()); + // // 1. We check that user funded the fee payer contract with at least the transaction fee. + // // TODO(#7796): we should try to prevent reverts here + // assert(funded_amount >= tx_fee, "funded amount not enough to cover tx fee"); + // // 2. We compute the refund amount as the difference between funded amount and tx fee. + // let refund_amount = funded_amount - tx_fee; + // // 3. We add fee to the fee payer point and refund amount to the user point. + // fee_payer_point.add_amount(tx_fee); + // user_point.add_amount(refund_amount); + // // 4. We finalize the hiding points to get the note hashes. + // let fee_payer_note_hash = fee_payer_point.finalize(); + // let user_note_hash = user_point.finalize(); + // // 5. At last we emit the note hashes. + // context.push_note_hash(fee_payer_note_hash); + // context.push_note_hash(user_note_hash); + // // --> Once the tx is settled user and fee recipient can add the notes to their pixies. + // } // docs:end:complete_refund /// Internal /// // docs:start:increase_public_balance diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/sort_by.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/sort_by.nr index 8de75844a71..22e31f626e8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/sort_by.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/sort_by.nr @@ -1,27 +1,5 @@ use crate::utils::arrays::find_index_hint; -/// Returns the index of the elements in the array that would sort it, using the provided custom sorting function. -unconstrained fn get_sorting_index(some_array: [T; N], ordering: fn[Env](T, T) -> bool) -> [u32; N] { - let mut result = [0; N]; - let mut a = some_array; - for i in 0..N { - result[i] = i; - } - for i in 1..N { - for j in 0..i { - if ordering(a[i], a[j]) { - let old_a_j = a[j]; - a[j] = a[i]; - a[i] = old_a_j; - let old_j = result[j]; - result[j] = result[i]; - result[i] = old_j; - } - } - } - result -} - // Copied from the stdlib Array.sort_via. // But this one doesn't use `ordering` to check that the array is sorted. // This is to allow preserving the order of equal values. From bc3c873cbbe23a1fc1dc8dea0eae3e8d81760a53 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 16 Sep 2024 16:01:55 +0000 Subject: [PATCH 12/79] almost there --- .../aztec/src/encrypted_logs/incoming_body.nr | 10 +- .../aztec/src/history/note_inclusion.nr | 6 +- .../aztec/src/history/note_validity.nr | 6 +- .../aztec/src/history/nullifier_inclusion.nr | 6 +- .../src/history/nullifier_non_inclusion.nr | 6 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 108 ++++++++-- .../aztec-nr/aztec/src/note/lifecycle.nr | 10 +- .../aztec/src/note/note_getter/mod.nr | 8 +- .../aztec-nr/aztec/src/note/note_interface.nr | 26 +-- .../aztec-nr/aztec/src/note/utils.nr | 10 +- .../aztec/src/state_vars/private_immutable.nr | 8 +- .../aztec/src/state_vars/private_mutable.nr | 6 +- .../aztec/src/state_vars/private_set.nr | 11 +- .../src/test/helpers/test_environment.nr | 4 +- .../aztec/src/test/mocks/mock_note.nr | 18 +- .../contracts/token_contract/src/main.nr | 186 ++++++++---------- .../token_contract/src/types/balance_set.nr | 14 +- .../token_contract/src/types/token_note.nr | 4 +- 18 files changed, 239 insertions(+), 208 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr index 67747c6f87c..72bac692afd 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr @@ -72,12 +72,6 @@ mod test { inner: Point } - impl PartialNote for AddressNote { - fn compute_note_hiding_point(_self: Self) -> Point { - crate::generators::Ga1 - } - } - impl NoteInterface for AddressNote { fn get_note_type_id() -> Field { @@ -126,6 +120,10 @@ mod test { } buffer } + + fn compute_note_hash(self) -> Field { + crate::generators::Ga1.x + } } impl AddressNote { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index b144c4910be..3a0564e088a 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -2,19 +2,19 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use dep::protocol_types::header::Header; use crate::{ - note::{utils::compute_note_hash_for_nullify, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}}, + note::{utils::compute_note_hash_for_nullify, note_interface::{NoteInterface, NullifiableNote}}, oracle::get_membership_witness::get_note_hash_membership_witness }; trait ProveNoteInclusion { - fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote + FinalizedNote; + fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote; } impl ProveNoteInclusion for Header { fn prove_note_inclusion( self, note: Note - ) where Note: NoteInterface + NullifiableNote + FinalizedNote { + ) where Note: NoteInterface + NullifiableNote { let note_hash = compute_note_hash_for_nullify(note); let witness = unsafe { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr index 4f38f37a22c..d3d820510f1 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr @@ -1,9 +1,9 @@ -use crate::{context::PrivateContext, note::note_interface::{NoteInterface, NullifiableNote, FinalizedNote}}; +use crate::{context::PrivateContext, note::note_interface::{NoteInterface, NullifiableNote}}; use dep::protocol_types::header::Header; trait ProveNoteValidity { - fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote + FinalizedNote; + fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteValidity for Header { @@ -11,7 +11,7 @@ impl ProveNoteValidity for Header { self, note: Note, context: &mut PrivateContext - ) where Note: NoteInterface + NullifiableNote + FinalizedNote { + ) where Note: NoteInterface + NullifiableNote { self.prove_note_inclusion(note); self.prove_note_not_nullified(note, context); } diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index bd6b285f8ea..ab000a248a1 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -3,7 +3,7 @@ use dep::protocol_types::header::Header; use crate::{ context::PrivateContext, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, - note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}} + note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote}} }; trait ProveNullifierInclusion { @@ -32,7 +32,7 @@ impl ProveNullifierInclusion for Header { } trait ProveNoteIsNullified { - fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote + FinalizedNote; + fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteIsNullified for Header { @@ -41,7 +41,7 @@ impl ProveNoteIsNullified for Header { self, note: Note, context: &mut PrivateContext - ) where Note: NoteInterface + NullifiableNote + FinalizedNote { + ) where Note: NoteInterface + NullifiableNote { let nullifier = compute_siloed_nullifier(note, context); self.prove_nullifier_inclusion(nullifier); diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index d3545a5d672..d4d378f716a 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -2,7 +2,7 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use dep::protocol_types::{header::Header, utils::field::{full_field_less_than, full_field_greater_than}}; use crate::{ context::PrivateContext, - note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}}, + note::{utils::compute_siloed_nullifier, note_interface::{NoteInterface, NullifiableNote}}, oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness }; @@ -42,7 +42,7 @@ impl ProveNullifierNonInclusion for Header { } trait ProveNoteNotNullified { - fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote + FinalizedNote; + fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteNotNullified for Header { @@ -51,7 +51,7 @@ impl ProveNoteNotNullified for Header { self, note: Note, context: &mut PrivateContext - ) where Note: NoteInterface + NullifiableNote + FinalizedNote { + ) where Note: NoteInterface + NullifiableNote { let nullifier = compute_siloed_nullifier(note, context); self.prove_nullifier_non_inclusion(nullifier); diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 21eb11bdea9..6353f2fe5a9 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -23,7 +23,12 @@ comptime fn compute_note_type_id(name: Quoted) -> Field { field_from_bytes(selector_be_bytes, true) } -comptime fn generate_note_interface(s: StructDefinition) -> (Quoted, u32, Field) { +comptime fn generate_note_interface( + s: StructDefinition, + hiding_point_name: Quoted, + fixed_fields: [(Quoted, Type)], + nullable_fields: [Quoted] +) -> (Quoted, u32, Field) { let name = s.name(); let typ = s.as_type(); let (fields, aux_vars) = flatten_to_fields(quote { self }, typ, &[quote {self.header}]); @@ -47,6 +52,8 @@ comptime fn generate_note_interface(s: StructDefinition) -> (Quoted, u32, Field) ); let note_type_id = compute_note_type_id(name); + let fixed_fields_args = fixed_fields.map(| (name, _): (Quoted, Type) | quote{self.$name}).push_back(quote {self.get_header().storage_slot}).join(quote {,}); + let nullable_fields_args = nullable_fields.map(|field| quote { self.$field }).join(quote {,}); (quote { impl aztec::note::note_interface::NoteInterface<$content_len> for $name { @@ -93,6 +100,9 @@ comptime fn generate_note_interface(s: StructDefinition) -> (Quoted, u32, Field) self.header } + fn compute_note_hash(self) -> Field { + $hiding_point_name::new($fixed_fields_args).finalize($nullable_fields_args) + } } }, content_len, note_type_id) } @@ -149,25 +159,28 @@ pub(crate) comptime fn generate_note_export(s: StructDefinition, note_type_id: F } } -comptime fn generate_note_hiding_point(s: StructDefinition, nullable_fields: [Quoted]) -> (Quoted, Quoted) { +comptime fn generate_note_hiding_point( + s: StructDefinition, + fixed_fields: [(Quoted, Type)], + nullable_fields: [Quoted] +) -> (Quoted, Quoted) { let name = s.name(); let hiding_point_name = f"{name}HidingPoint".quoted_contents(); - let note_header_type: Type = type_of(NoteHeader::empty()); - - let fixed_fields = s.fields().filter( - | (name, typ): (Quoted, Type) | (typ != note_header_type) & nullable_fields.all(| field | field != name) - ); + let mut new_args_list = &[]; let mut new_generators_list = &[]; let mut new_scalars_list = &[]; for i in 0..fixed_fields.len() { - let (field_name, _) = fixed_fields[i]; + let (field_name, field_type) = fixed_fields[i]; let generator_index = i + 1; new_generators_list = new_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); - new_scalars_list = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(note.$field_name.to_field()) }); + new_scalars_list = new_scalars_list.push_back(quote { std::hash::from_field_unsafe($field_name.to_field()) }); + new_args_list = new_args_list.push_back(quote { $field_name: $field_type }); } + new_args_list = new_args_list.push_back(quote { storage_slot: Field }); let new_generators = new_generators_list.push_back(quote { aztec::generators::G_slot }).join(quote {,}); - let new_scalars = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(note.get_header().storage_slot) }).join(quote {,}); + let new_scalars = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(storage_slot) }).join(quote {,}); + let new_args = new_args_list.join(quote {,}); let mut finalize_generators_list = &[]; let mut finalize_scalars_list = &[]; @@ -179,7 +192,7 @@ comptime fn generate_note_hiding_point(s: StructDefinition, nullable_fields: [Qu let field_name = nullable_fields[i]; let arg_type = f"N{i}".quoted_contents(); finalize_args_list = finalize_args_list.push_back(quote { $field_name: $arg_type }); - let generator_index = i + 1; + let generator_index = i + 1 + fixed_fields.len(); finalize_generators_list = finalize_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); finalize_scalars_list = finalize_scalars_list.push_back(quote { std::hash::from_field_unsafe($field_name.to_field()) }); finalize_generics_list = finalize_generics_list.push_back(quote { $arg_type }); @@ -199,7 +212,7 @@ comptime fn generate_note_hiding_point(s: StructDefinition, nullable_fields: [Qu let point = std::embedded_curve_ops::multi_scalar_mul( [$finalize_generators], [$finalize_scalars] - ) + self.inner.x; + ) + self.inner; point.x } } else { @@ -220,13 +233,24 @@ comptime fn generate_note_hiding_point(s: StructDefinition, nullable_fields: [Qu quote {} }; + let initialize_args = if new_args_list.len() > 0 { + &[quote {mut self}].append(new_args_list).join(quote {,}) + } else { + quote {mut self} + }; + (quote { struct $hiding_point_name { inner: aztec::protocol_types::point::Point } impl $hiding_point_name { - fn new(note: $name) -> $hiding_point_name { + + fn empty() -> $hiding_point_name { + $hiding_point_name { inner: aztec::protocol_types::point::Point::empty() } + } + + fn new($new_args) -> $hiding_point_name { let generators = [$new_generators]; let point = std::embedded_curve_ops::multi_scalar_mul( [$new_generators], @@ -235,6 +259,21 @@ comptime fn generate_note_hiding_point(s: StructDefinition, nullable_fields: [Qu $hiding_point_name { inner: point } } + fn from_point(mut self, point: aztec::protocol_types::point::Point) -> $hiding_point_name { + self.inner = point; + self + } + + fn initialize($initialize_args) -> $hiding_point_name { + let generators = [$new_generators]; + let point = std::embedded_curve_ops::multi_scalar_mul( + [$new_generators], + [$new_scalars] + ); + self.inner = point; + self + } + fn $finalize_name($finalize_args) -> Field $finalize_trait_bounds { $finalize_body } @@ -248,17 +287,45 @@ comptime fn generate_note_hiding_point(s: StructDefinition, nullable_fields: [Qu }, hiding_point_name) } -pub comptime fn generate_finalized_note_for_complete_note(s: StructDefinition, hiding_point_name: Quoted) -> Quoted { +comptime fn generate_partial_note_impl(s: StructDefinition, hiding_point_name: Quoted) -> Quoted { let name = s.name(); quote { - impl aztec::note::note_interface::FinalizedNote for $name { - fn compute_note_hash(self) -> Field { - $hiding_point_name::new(self).finalize() + impl aztec::note::note_interface::PartialNote<$hiding_point_name> for $name { + fn hiding_point() -> $hiding_point_name { + $hiding_point_name::empty() } } } } +#[varargs] +pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { + // Automatically inject header if not present + let note_header_type = type_of(NoteHeader::empty()); + let filtered_header = s.fields().filter(| (_, typ): (Quoted, Type) | typ == note_header_type); + if (filtered_header.len() == 0) { + let new_fields = s.fields().push_back((quote { header }, note_header_type)); + s.set_fields(new_fields); + } + let fixed_fields = s.fields().filter( + | (name, typ): (Quoted, Type) | (typ != note_header_type) & nullable_fields.all(| field | field != name) + ); + let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, fixed_fields, nullable_fields); + let (note_interface_impl, note_serialized_len, note_type_id) = generate_note_interface(s, hiding_point_name, fixed_fields, nullable_fields); + let note_properties = generate_note_properties(s); + let partial_note_impl = generate_partial_note_impl(s, hiding_point_name); + + // Register note here + NOTES = NOTES.push_back((s, note_serialized_len, note_type_id)); + + quote { + $note_interface_impl + $note_properties + $note_hiding_point + $partial_note_impl + } +} + pub comptime fn note(s: StructDefinition) -> Quoted { // Automatically inject header if not present let note_header_type = type_of(NoteHeader::empty()); @@ -267,11 +334,11 @@ pub comptime fn note(s: StructDefinition) -> Quoted { let new_fields = s.fields().push_back((quote { header }, note_header_type)); s.set_fields(new_fields); } + let fixed_fields = s.fields().filter(| (_, typ): (Quoted, Type) | typ != note_header_type); - let (note_interface_impl, note_serialized_len, note_type_id) = generate_note_interface(s); + let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, fixed_fields, &[]); + let (note_interface_impl, note_serialized_len, note_type_id) = generate_note_interface(s, hiding_point_name, fixed_fields, &[]); let note_properties = generate_note_properties(s); - let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, &[]); - let finalized_note = generate_finalized_note_for_complete_note(s, hiding_point_name); // Register note here NOTES = NOTES.push_back((s, note_serialized_len, note_type_id)); @@ -280,6 +347,5 @@ pub comptime fn note(s: StructDefinition) -> Quoted { $note_interface_impl $note_properties $note_hiding_point - $finalized_note } } diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index 6cfddaeed90..3eb09e9bd78 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -1,6 +1,6 @@ use crate::context::{PrivateContext, PublicContext}; use crate::note::{ - note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, + note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}, utils::{compute_note_hash_for_read_request, compute_note_hash_for_nullify_internal}, note_emission::NoteEmission }; @@ -10,7 +10,7 @@ pub fn create_note( context: &mut PrivateContext, storage_slot: Field, note: &mut Note -) -> NoteEmission where Note: NoteInterface + NullifiableNote + FinalizedNote { +) -> NoteEmission where Note: NoteInterface + NullifiableNote { let contract_address = (*context).this_address(); let note_hash_counter = context.side_effect_counter; @@ -39,7 +39,7 @@ pub fn create_note_hash_from_public( context: &mut PublicContext, storage_slot: Field, note: &mut Note -) where Note: NoteInterface + NullifiableNote + FinalizedNote { +) where Note: NoteInterface + NullifiableNote { let contract_address = (*context).this_address(); // Public note hashes are transient, but have no side effect counters, so we just need note_hash_counter != 0 let header = NoteHeader { contract_address, storage_slot, nonce: 0, note_hash_counter: 1 }; @@ -53,7 +53,7 @@ pub fn create_note_hash_from_public( pub fn destroy_note( context: &mut PrivateContext, note: Note -) where Note: NoteInterface + NullifiableNote + FinalizedNote { +) where Note: NoteInterface + NullifiableNote { let note_hash_for_read_request = compute_note_hash_for_read_request(note); destroy_note_unsafe(context, note, note_hash_for_read_request) @@ -63,7 +63,7 @@ pub fn destroy_note_unsafe( context: &mut PrivateContext, note: Note, note_hash_for_read_request: Field -) where Note: NoteInterface + NullifiableNote + FinalizedNote { +) where Note: NoteInterface + NullifiableNote { let note_hash_for_nullify = compute_note_hash_for_nullify_internal(note, note_hash_for_read_request); let nullifier = note.compute_nullifier(context, note_hash_for_nullify); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index d748e33f7f1..6c7d698eea0 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -3,7 +3,7 @@ use crate::context::PrivateContext; use crate::note::{ constants::{GET_NOTE_ORACLE_RETURN_LENGTH, VIEW_NOTE_ORACLE_RETURN_LENGTH}, note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, NoteStatus, PropertySelector}, - note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_request }; use crate::oracle; @@ -81,7 +81,7 @@ fn check_notes_order( pub fn get_note( context: &mut PrivateContext, storage_slot: Field -) -> (Note, Field) where Note: NoteInterface + NullifiableNote + FinalizedNote { +) -> (Note, Field) where Note: NoteInterface + NullifiableNote { let note = unsafe { get_note_internal(storage_slot) }; @@ -100,7 +100,7 @@ pub fn get_notes( context: &mut PrivateContext, storage_slot: Field, options: NoteGetterOptions -) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + FinalizedNote + Eq { +) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + Eq { let opt_notes = unsafe { get_notes_internal(storage_slot, options) }; @@ -123,7 +123,7 @@ fn constrain_get_notes_internal; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], options: NoteGetterOptions -) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + FinalizedNote + Eq { +) -> (BoundedVec, BoundedVec) where Note: NoteInterface + NullifiableNote + Eq { // The filter is applied first to avoid pushing note read requests for notes we're not interested in. Note that // while the filter function can technically mutate the contents of the notes (as opposed to simply removing some), // the private kernel will later validate that these note actually exist, so transformations would cause for that diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index 221f6015145..df04e1c4d6f 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -1,17 +1,12 @@ use crate::context::PrivateContext; use crate::note::note_header::NoteHeader; -use dep::protocol_types::point::Point; trait NoteProperties { fn properties() -> T; } -trait PartialNote { - fn compute_note_hiding_point(self) -> Point; -} - -trait FinalizedNote { - fn compute_note_hash(self) -> Field; +trait PartialNote { + fn hiding_point() -> T; } trait NullifiableNote { @@ -28,24 +23,29 @@ trait NullifiableNote { } // docs:start:note_interface +// Autogenerated by the #[note] macro + trait NoteInterface { - // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation + // Autogenerated by the #[aztec(note)] macro fn serialize_content(self) -> [Field; N]; - // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation + // Autogenerated by the #[aztec(note)] macro fn deserialize_content(fields: [Field; N]) -> Self; - // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation + // Autogenerated by the #[aztec(note)] macro fn get_header(self) -> NoteHeader; - // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation + // Autogenerated by the #[aztec(note)] macro fn set_header(&mut self, header: NoteHeader) -> (); - // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation + // Autogenerated by the #[aztec(note)] macro fn get_note_type_id() -> Field; - // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation + // Autogenerated by the #[aztec(note)] macro fn to_be_bytes(self, storage_slot: Field) -> [u8; N*32 + 64]; + + // Autogenerated by the #[aztec(note)] macro + fn compute_note_hash(self) -> Field; } // docs:end:note_interface diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 1c7888a28a4..7b2f671f6ed 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -1,6 +1,6 @@ use crate::{ context::PrivateContext, - note::{note_header::NoteHeader, note_interface::{NullifiableNote, NoteInterface, FinalizedNote}} + note::{note_header::NoteHeader, note_interface::{NullifiableNote, NoteInterface}} }; use dep::protocol_types::{ @@ -14,7 +14,7 @@ use dep::protocol_types::{ pub fn compute_siloed_nullifier( note_with_header: Note, context: &mut PrivateContext -) -> Field where Note: NoteInterface + NullifiableNote + FinalizedNote { +) -> Field where Note: NoteInterface + NullifiableNote { let header = note_with_header.get_header(); let note_hash_for_nullify = compute_note_hash_for_nullify(note_with_header); let inner_nullifier = note_with_header.compute_nullifier(context, note_hash_for_nullify); @@ -23,7 +23,7 @@ pub fn compute_siloed_nullifier( } // TODO(#7775): make this not impossible to understand -pub fn compute_note_hash_for_read_request(note: Note) -> Field where Note: NoteInterface + NullifiableNote + FinalizedNote { +pub fn compute_note_hash_for_read_request(note: Note) -> Field where Note: NoteInterface + NullifiableNote { let note_hash = note.compute_note_hash(); let nonce = note.get_header().nonce; let counter = note.get_header().note_hash_counter; @@ -100,7 +100,7 @@ pub fn compute_note_hash_for_nullify_internal( // } // } -pub fn compute_note_hash_for_nullify(note: Note) -> Field where Note: NoteInterface + NullifiableNote + FinalizedNote { +pub fn compute_note_hash_for_nullify(note: Note) -> Field where Note: NoteInterface + NullifiableNote { let note_hash_for_read_request = compute_note_hash_for_read_request(note); compute_note_hash_for_nullify_internal(note, note_hash_for_read_request) } @@ -110,7 +110,7 @@ pub fn compute_note_hash_and_optionally_a_nullifier( note_header: NoteHeader, compute_nullifier: bool, serialized_note: [Field; S] -) -> [Field; 4] where T: NoteInterface + NullifiableNote + FinalizedNote { +) -> [Field; 4] where T: NoteInterface + NullifiableNote { let mut note = deserialize_content(arr_copy_slice(serialized_note, [0; N], 0)); note.set_header(note_header); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 3c6d6c77de8..687a3e87153 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -3,7 +3,7 @@ use dep::protocol_types::{constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, use crate::context::{PrivateContext, UnconstrainedContext}; use crate::note::{ lifecycle::create_note, note_getter::{get_note, view_notes}, - note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, note_emission::NoteEmission }; use crate::oracle::notes::check_nullifier_exists; @@ -45,7 +45,7 @@ impl PrivateImmutable { pub fn initialize( self, note: &mut Note - ) -> NoteEmission where Note: NoteInterface + NullifiableNote + FinalizedNote { + ) -> NoteEmission where Note: NoteInterface + NullifiableNote { // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); self.context.push_nullifier(nullifier); @@ -55,7 +55,7 @@ impl PrivateImmutable { // docs:end:initialize // docs:start:get_note - pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote + FinalizedNote { + pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote { let storage_slot = self.storage_slot; get_note(self.context, storage_slot).0 } @@ -72,7 +72,7 @@ impl PrivateImmutable { // view_note does not actually use the context, but it calls oracles that are only available in private // docs:start:view_note - unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote + FinalizedNote { + unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(0) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index 4eec6ab22ee..aa634e6d103 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -3,7 +3,7 @@ use dep::protocol_types::{constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, use crate::context::{PrivateContext, UnconstrainedContext}; use crate::note::{ lifecycle::{create_note, destroy_note_unsafe}, note_getter::{get_note, view_notes}, - note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, note_emission::NoteEmission }; use crate::oracle::notes::check_nullifier_exists; @@ -44,7 +44,7 @@ impl PrivateMutable { } } -impl PrivateMutable where Note: NoteInterface + NullifiableNote + FinalizedNote { +impl PrivateMutable where Note: NoteInterface + NullifiableNote { // docs:start:initialize pub fn initialize(self, note: &mut Note) -> NoteEmission { // Nullify the storage slot. @@ -103,7 +103,7 @@ impl PrivateMutable where Note: NoteInter // docs:end:get_note } -impl PrivateMutable where Note: NoteInterface + NullifiableNote + FinalizedNote { +impl PrivateMutable where Note: NoteInterface + NullifiableNote { unconstrained pub fn is_initialized(self) -> bool { let nullifier = self.compute_initialization_nullifier(); check_nullifier_exists(nullifier) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index d8a1a6d70ea..0eb7822218f 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -4,9 +4,8 @@ use crate::note::{ constants::MAX_NOTES_PER_PAGE, lifecycle::{create_note, create_note_hash_from_public, destroy_note_unsafe}, note_getter::{get_notes, view_notes}, note_getter_options::NoteGetterOptions, - note_interface::{NoteInterface, NullifiableNote, FinalizedNote}, - note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_request, - note_emission::NoteEmission + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, + utils::compute_note_hash_for_read_request, note_emission::NoteEmission }; use crate::state_vars::storage::Storage; @@ -28,7 +27,7 @@ impl PrivateSet { // docs:end:new } -impl PrivateSet where Note: NoteInterface + NullifiableNote + FinalizedNote { +impl PrivateSet where Note: NoteInterface + NullifiableNote { // docs:start:insert_from_public pub fn insert_from_public(self, note: &mut Note) { create_note_hash_from_public(self.context, self.storage_slot, note); @@ -36,7 +35,7 @@ impl PrivateSet where Note: NoteInte // docs:end:insert_from_public } -impl PrivateSet where Note: NoteInterface + NullifiableNote + FinalizedNote + Eq { +impl PrivateSet where Note: NoteInterface + NullifiableNote + Eq { // docs:start:insert pub fn insert(self, note: &mut Note) -> NoteEmission { create_note(self.context, self.storage_slot, note) @@ -84,7 +83,7 @@ impl PrivateSet where Note: NoteInt } } -impl PrivateSet where Note: NoteInterface + NullifiableNote + FinalizedNote { +impl PrivateSet where Note: NoteInterface + NullifiableNote { // docs:start:view_notes unconstrained pub fn view_notes( self, diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index 88a43625f03..7f3a516381d 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -11,7 +11,7 @@ use crate::test::helpers::{cheatcodes, utils::{apply_side_effects_private, Deplo use crate::keys::constants::{NULLIFIER_INDEX, INCOMING_INDEX, OUTGOING_INDEX, TAGGING_INDEX}; use crate::hash::hash_args; -use crate::note::{note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote, FinalizedNote}}; +use crate::note::{note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}}; use crate::oracle::{execution::{get_block_number, get_contract_address}, notes::notify_created_note}; struct TestEnvironment {} @@ -212,7 +212,7 @@ impl TestEnvironment { note: &mut Note, storage_slot: Field, contract_address: AztecAddress - ) where Note: NoteInterface + NullifiableNote + FinalizedNote { + ) where Note: NoteInterface + NullifiableNote { let original_contract_address = get_contract_address(); cheatcodes::set_contract_address(contract_address); let note_hash_counter = cheatcodes::get_side_effects_counter(); diff --git a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr index a01bde28a5d..e95367b8b4f 100644 --- a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr +++ b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr @@ -5,7 +5,7 @@ use crate::{ use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, traits::Eq}; use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; -use crate::note::note_interface::{NullifiableNote, FinalizedNote}; +use crate::note::note_interface::NullifiableNote; global MOCK_NOTE_LENGTH = 1; @@ -35,15 +35,6 @@ impl NullifiableNote for MockNote { } } -impl FinalizedNote for MockNote { - fn compute_note_hash(self: Self) -> Field { - assert(self.header.storage_slot != 0, "Storage slot must be set before computing note hash"); - // We use the unsafe version because the multi_scalar_mul will constrain the scalars. - let value_scalar = from_field_unsafe(self.value); - multi_scalar_mul([G_val], [value_scalar]).x - } -} - impl NoteInterface for MockNote { fn serialize_content(self) -> [Field; MOCK_NOTE_LENGTH] { [self.value] @@ -87,6 +78,13 @@ impl NoteInterface for MockNote { } buffer } + + fn compute_note_hash(self: Self) -> Field { + assert(self.header.storage_slot != 0, "Storage slot must be set before computing note hash"); + // We use the unsafe version because the multi_scalar_mul will constrain the scalars. + let value_scalar = from_field_unsafe(self.value); + multi_scalar_mul([G_val], [value_scalar]).x + } } impl Eq for MockNote { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index bec5c61df85..8e9637d0ff2 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -20,17 +20,14 @@ contract Token { use dep::aztec::{ context::{PrivateContext, PrivateCallInterface}, hash::compute_secret_hash, - prelude::{ - NoteGetterOptions, Map, PublicMutable, SharedImmutable, PrivateSet, AztecAddress, - FunctionSelector, NoteHeader - }, + prelude::{NoteGetterOptions, Map, PublicMutable, SharedImmutable, PrivateSet, AztecAddress, FunctionSelector}, encrypted_logs::{ encrypted_note_emission::{encode_and_encrypt_note_with_keys, encode_and_encrypt_note_with_keys_unconstrained}, encrypted_event_emission::encode_and_encrypt_event_with_keys_unconstrained }, keys::getters::get_current_public_keys, macros::{storage::storage, events::event, functions::{initializer, private, view, public}}, - utils::comparison::Comparator, protocol_types::traits::Serialize + utils::comparison::Comparator, protocol_types::{point::Point, traits::Serialize} }; // docs:start:import_authwit @@ -457,109 +454,82 @@ contract Token { /// Note 2: fee_payer_point and user_point above are public information because they are passed as args to /// the public `complete_refund(...)` function. // docs:start:setup_refund - // #[private] - // fn setup_refund( - // fee_payer: AztecAddress, // Address of the entity which will receive the fee note. - // user: AztecAddress, // A user for which we are setting up the fee refund. - // funded_amount: Field, // The amount the user funded the fee payer with (represents fee limit). - // user_randomness: Field, // A randomness to mix in with the generated refund note for the sponsored user. - // fee_payer_randomness: Field // A randomness to mix in with the generated fee note for the fee payer. - // ) { - // // 1. This function is called by fee paying contract (fee_payer) when setting up a refund so we need to support - // // the authwit flow here and check that the user really permitted fee_payer to set up a refund on their behalf. - // assert_current_call_valid_authwit(&mut context, user); - // // 2. Get all the relevant keys - // let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); - // let user_keys = get_current_public_keys(&mut context, user); - // let user_npk_m_hash = user_keys.npk_m.hash(); - // // 3. Deduct the funded amount from the user's balance - this is a maximum fee a user is willing to pay - // // (called fee limit in aztec spec). The difference between fee limit and the actual tx fee will be refunded - // // to the user in the `complete_refund(...)` function. - // let change = subtract_balance( - // &mut context, - // storage, - // user, - // U128::from_integer(funded_amount), - // INITIAL_TRANSFER_CALL_MAX_NOTES - // ); - // storage.balances.at(user).add(user_keys.npk_m, change).emit( - // encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) - // ); - // // 4. We create the partial notes for the fee payer and the user. - // // --> Called "partial" because they don't have the amount set yet (that will be done in `complete_refund(...)`). - // let fee_payer_partial_note = TokenNote { - // header: NoteHeader { - // contract_address: AztecAddress::zero(), - // nonce: 0, - // storage_slot: storage.balances.at(fee_payer).set.storage_slot, - // note_hash_counter: 0 - // }, - // amount: U128::zero(), - // npk_m_hash: fee_payer_npk_m_hash, - // randomness: fee_payer_randomness - // }; - // let user_partial_note = TokenNote { - // header: NoteHeader { - // contract_address: AztecAddress::zero(), - // nonce: 0, - // storage_slot: storage.balances.at(user).set.storage_slot, - // note_hash_counter: 0 - // }, - // amount: U128::zero(), - // npk_m_hash: user_npk_m_hash, - // randomness: user_randomness - // }; - // // 5. Now we get the note hiding points. - // let mut fee_payer_point = fee_payer_partial_note.to_note_hiding_point(); - // let mut user_point = user_partial_note.to_note_hiding_point(); - // // 6. Set the public teardown function to `complete_refund(...)`. Public teardown is the only time when a public - // // function has access to the final transaction fee, which is needed to compute the actual refund amount. - // context.set_public_teardown_function( - // context.this_address(), - // comptime { - // FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") - // }, - // [ - // fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount - // ] - // ); - // } - // // docs:end:setup_refund - // // TODO(#7728): even though the funded_amount should be a U128, we can't have that type in a contract interface due - // // to serialization issues. - // // docs:start:complete_refund - // #[public] - // #[internal] - // fn complete_refund( - // // TODO(#7771): the following makes macros crash --> try getting it work once we migrate to metaprogramming - // // mut fee_payer_point: TokenNoteHidingPoint, - // // mut user_point: TokenNoteHidingPoint, - // fee_payer_point_immutable: TokenNoteHidingPoint, - // user_point_immutable: TokenNoteHidingPoint, - // funded_amount: Field - // ) { - // // TODO(#7771): nuke the following 2 lines once we have mutable args - // let mut fee_payer_point = fee_payer_point_immutable; - // let mut user_point = user_point_immutable; - // // TODO(#7728): Remove the next line - // let funded_amount = U128::from_integer(funded_amount); - // let tx_fee = U128::from_integer(context.transaction_fee()); - // // 1. We check that user funded the fee payer contract with at least the transaction fee. - // // TODO(#7796): we should try to prevent reverts here - // assert(funded_amount >= tx_fee, "funded amount not enough to cover tx fee"); - // // 2. We compute the refund amount as the difference between funded amount and tx fee. - // let refund_amount = funded_amount - tx_fee; - // // 3. We add fee to the fee payer point and refund amount to the user point. - // fee_payer_point.add_amount(tx_fee); - // user_point.add_amount(refund_amount); - // // 4. We finalize the hiding points to get the note hashes. - // let fee_payer_note_hash = fee_payer_point.finalize(); - // let user_note_hash = user_point.finalize(); - // // 5. At last we emit the note hashes. - // context.push_note_hash(fee_payer_note_hash); - // context.push_note_hash(user_note_hash); - // // --> Once the tx is settled user and fee recipient can add the notes to their pixies. - // } + #[private] + fn setup_refund( + fee_payer: AztecAddress, // Address of the entity which will receive the fee note. + user: AztecAddress, // A user for which we are setting up the fee refund. + funded_amount: Field, // The amount the user funded the fee payer with (represents fee limit). + user_randomness: Field, // A randomness to mix in with the generated refund note for the sponsored user. + fee_payer_randomness: Field // A randomness to mix in with the generated fee note for the fee payer. + ) { + // 1. This function is called by fee paying contract (fee_payer) when setting up a refund so we need to support + // the authwit flow here and check that the user really permitted fee_payer to set up a refund on their behalf. + assert_current_call_valid_authwit(&mut context, user); + // 2. Get all the relevant keys + let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); + let user_keys = get_current_public_keys(&mut context, user); + let user_npk_m_hash = user_keys.npk_m.hash(); + // 3. Deduct the funded amount from the user's balance - this is a maximum fee a user is willing to pay + // (called fee limit in aztec spec). The difference between fee limit and the actual tx fee will be refunded + // to the user in the `complete_refund(...)` function. + let change = subtract_balance( + &mut context, + storage, + user, + U128::from_integer(funded_amount), + INITIAL_TRANSFER_CALL_MAX_NOTES + ); + storage.balances.at(user).add(user_keys.npk_m, change).emit( + encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) + ); + // 4. Now we get the note hiding points. + let mut fee_payer_point = TokenNote::hiding_point().initialize( + fee_payer_npk_m_hash, + fee_payer_randomness, + storage.balances.at(fee_payer).set.storage_slot + ); + let mut user_point = TokenNote::hiding_point().initialize( + user_npk_m_hash, + user_randomness, + storage.balances.at(user).set.storage_slot + ); + // 5. Set the public teardown function to `complete_refund(...)`. Public teardown is the only time when a public + // function has access to the final transaction fee, which is needed to compute the actual refund amount. + context.set_public_teardown_function( + context.this_address(), + comptime { + FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") + }, + [ + fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount + ] + ); + } + // docs:end:setup_refund + // TODO(#7728): even though the funded_amount should be a U128, we can't have that type in a contract interface due + // to serialization issues. + // docs:start:complete_refund + #[public] + #[internal] + fn complete_refund(fee_payer_point: Point, user_point: Point, funded_amount: Field) { + let mut fee_payer_hiding_point = TokenNote::hiding_point().from_point(fee_payer_point); + let mut user_hiding_point = TokenNote::hiding_point().from_point(user_point); + // TODO(#7728): Remove the next line + let funded_amount = U128::from_integer(funded_amount); + let tx_fee = U128::from_integer(context.transaction_fee()); + // 1. We check that user funded the fee payer contract with at least the transaction fee. + // TODO(#7796): we should try to prevent reverts here + assert(funded_amount >= tx_fee, "funded amount not enough to cover tx fee"); + // 2. We compute the refund amount as the difference between funded amount and tx fee. + let refund_amount = funded_amount - tx_fee; + // 3. We finalize the hiding points with the correct amounts to get the note hashes. + let fee_payer_note_hash = fee_payer_hiding_point.finalize(tx_fee); + let user_note_hash = user_hiding_point.finalize(refund_amount); + // 5. At last we emit the note hashes. + context.push_note_hash(fee_payer_note_hash); + context.push_note_hash(user_note_hash); + // --> Once the tx is settled user and fee recipient can add the notes to their pixies. + } // docs:end:complete_refund /// Internal /// // docs:start:increase_public_balance diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr index dda5f9d8f80..df3fb51adf0 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr @@ -2,7 +2,7 @@ use dep::aztec::prelude::{NoteGetterOptions, NoteViewerOptions, NoteInterface, P use dep::aztec::{ context::{PrivateContext, UnconstrainedContext}, protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, - note::{note_interface::{FinalizedNote, NullifiableNote}, note_getter::view_notes, note_emission::OuterNoteEmission}, + note::{note_interface::NullifiableNote, note_getter::view_notes, note_emission::OuterNoteEmission}, keys::{getters::get_current_public_keys, public_keys::NpkM} }; use crate::types::token_note::OwnedNote; @@ -19,14 +19,14 @@ impl BalanceSet { } impl BalanceSet { - unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote { + unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { self.balance_of_with_offset(0) } unconstrained pub fn balance_of_with_offset( self: Self, offset: u32 - ) -> U128 where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote { + ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { let mut balance = U128::from_integer(0); // docs:start:view_notes let mut options = NoteViewerOptions::new(); @@ -50,7 +50,7 @@ impl BalanceSet { self: Self, owner_npk_m: NpkM, addend: U128 - ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote + Eq { + ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + OwnedNote + Eq { if addend == U128::from_integer(0) { OuterNoteEmission::new(Option::none()) } else { @@ -67,7 +67,7 @@ impl BalanceSet { self: Self, owner_npk_m: NpkM, amount: U128 - ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote + Eq { + ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + OwnedNote + Eq { let subtracted = self.try_sub(amount, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL); // try_sub may have substracted more or less than amount. We must ensure that we subtracted at least as much as @@ -89,7 +89,7 @@ impl BalanceSet { self: Self, target_amount: U128, max_notes: u32 - ) -> U128 where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote + Eq { + ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote + Eq { // We are using a preprocessor here (filter applied in an unconstrained context) instead of a filter because // we do not need to prove correct execution of the preprocessor. // Because the `min_sum` notes is not constrained, users could choose to e.g. not call it. However, all this @@ -118,7 +118,7 @@ impl BalanceSet { pub fn preprocess_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 -) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + NullifiableNote + FinalizedNote + OwnedNote { +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + NullifiableNote + OwnedNote { let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(0); for i in 0..notes.len() { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 4f8eaf39370..a57ad749c7f 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, note::utils::compute_note_hash_for_nullify, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app, macros::notes::note + keys::getters::get_nsk_app, macros::notes::partial_note }; trait OwnedNote { @@ -11,7 +11,7 @@ trait OwnedNote { } // docs:start:TokenNote -#[note] +#[partial_note(quote {amount})] struct TokenNote { // The amount of tokens in the note amount: U128, From e55f2cd50ecd32ef71c0eb504cb7db70d27f334b Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 16 Sep 2024 16:08:33 +0000 Subject: [PATCH 13/79] removed dumb helper --- noir-projects/aztec-nr/aztec/src/macros/utils.nr | 9 ++------- .../noir-contracts/contracts/token_contract/src/main.nr | 4 +++- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 1d7504a4a2a..3bc940ffa51 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -102,13 +102,8 @@ pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quo body_expr.unwrap() } -pub(crate) comptime fn is_bool(typ: Type) -> bool { - let a_bool = true; - typ == type_of(a_bool) -} - pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: Type) -> Quoted { - if typ.is_field() | typ.as_integer().is_some() | is_bool(typ) { + if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { quote { $slice_name = $slice_name.push_back($name as Field); } } else if typ.as_struct().is_some() { quote { $slice_name = $slice_name.append($name.serialize()); } @@ -132,7 +127,7 @@ pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: } pub(crate) comptime fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted { - if typ.is_field() | typ.as_integer().is_some() | is_bool(typ) { + if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { quote { $hasher_name.add($name as Field); } } else if typ.as_struct().is_some() { quote { $hasher_name.add_multiple($name.serialize()); } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 8e9637d0ff2..41c0b50eec1 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -1,7 +1,7 @@ // docs:start:token_all // docs:start:imports mod types; -//mod test; +mod test; use dep::aztec::macros::aztec; @@ -30,6 +30,8 @@ contract Token { utils::comparison::Comparator, protocol_types::{point::Point, traits::Serialize} }; + use std::embedded_curve_ops::EmbeddedCurvePoint; + // docs:start:import_authwit use dep::authwit::auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public, compute_authwit_nullifier}; // docs:end:import_authwit From 1b7e2941ae5e046740e00a63bce9cb6280b583c4 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 16 Sep 2024 19:47:44 +0000 Subject: [PATCH 14/79] first pass at all contracts --- boxes/boxes/react/src/contracts/src/main.nr | 14 +- boxes/boxes/vanilla/src/contracts/src/main.nr | 14 +- boxes/init/src/main.nr | 7 +- .../aztec-nr/address-note/src/address_note.nr | 2 +- .../aztec-nr/aztec/src/note/note_interface.nr | 14 +- .../aztec-nr/uint-note/src/uint_note.nr | 2 +- .../app_subscription_contract/src/main.nr | 30 ++-- .../src/subscription_note.nr | 2 +- .../contracts/auth_contract/src/main.nr | 43 ++--- .../auth_registry_contract/src/main.nr | 51 +++--- .../auth_wit_test_contract/src/main.nr | 13 +- .../avm_initializer_test_contract/src/main.nr | 18 ++- .../contracts/avm_test_contract/src/main.nr | 150 +++++++++--------- .../benchmarking_contract/src/main.nr | 21 ++- .../contracts/card_game_contract/src/main.nr | 36 +++-- .../contracts/child_contract/src/main.nr | 41 ++--- .../contracts/claim_contract/src/main.nr | 20 ++- .../src/events/class_registered.nr | 2 +- .../events/private_function_broadcasted.nr | 10 +- .../unconstrained_function_broadcasted.nr | 6 +- .../src/main.nr | 17 +- .../src/main.nr | 13 +- .../crowdfunding_contract/src/main.nr | 35 ++-- .../delegated_on_contract/src/main.nr | 20 ++- .../contracts/delegator_contract/src/main.nr | 21 +-- .../docs_example_contract/src/main.nr | 59 +++---- .../src/types/card_note.nr | 11 +- .../easy_private_token_contract/src/main.nr | 18 ++- .../easy_private_voting_contract/src/main.nr | 32 ++-- .../ecdsa_k_account_contract/src/main.nr | 24 +-- .../ecdsa_public_key_note/src/lib.nr | 4 +- .../ecdsa_r_account_contract/src/main.nr | 24 +-- .../contracts/escrow_contract/src/main.nr | 18 ++- .../contracts/fee_juice_contract/src/main.nr | 32 ++-- .../contracts/fpc_contract/src/main.nr | 32 ++-- .../import_test_contract/src/main.nr | 13 +- .../inclusion_proofs_contract/src/main.nr | 45 +++--- .../key_registry_contract/src/main.nr | 16 +- .../contracts/lending_contract/src/main.nr | 71 +++++---- .../src/main.nr | 6 +- .../contracts/parent_contract/src/main.nr | 37 +++-- .../pending_note_hashes_contract/src/main.nr | 42 ++--- .../contracts/price_feed_contract/src/main.nr | 17 +- .../private_fpc_contract/src/main.nr | 17 +- .../contracts/router_contract/src/main.nr | 5 +- .../schnorr_account_contract/src/main.nr | 24 +-- .../src/public_key_note.nr | 10 +- .../src/main.nr | 11 +- .../src/main.nr | 11 +- .../stateful_test_contract/src/main.nr | 49 +++--- .../static_child_contract/src/main.nr | 36 +++-- .../static_parent_contract/src/main.nr | 35 ++-- .../contracts/test_contract/src/main.nr | 93 +++++------ .../contracts/test_contract/src/test_note.nr | 12 +- .../contracts/test_log_contract/src/main.nr | 20 ++- .../token_blacklist_contract/src/main.nr | 52 +++--- .../src/types/token_note.nr | 10 +- .../src/types/transparent_note.nr | 33 +--- .../token_bridge_contract/src/main.nr | 35 ++-- .../contracts/uniswap_contract/src/main.nr | 28 ++-- 60 files changed, 868 insertions(+), 716 deletions(-) diff --git a/boxes/boxes/react/src/contracts/src/main.nr b/boxes/boxes/react/src/contracts/src/main.nr index d0fafea3250..fc0fa76ca55 100644 --- a/boxes/boxes/react/src/contracts/src/main.nr +++ b/boxes/boxes/react/src/contracts/src/main.nr @@ -1,18 +1,22 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract BoxReact { use dep::aztec::{ keys::public_keys::{IvpkM, OvpkM}, prelude::{AztecAddress, PrivateMutable, Map, NoteInterface, NoteHeader, Point}, - encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys + encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, + macros::{storage::storage, functions::{private, public, initializer}} }; use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; - #[aztec(storage)] + #[storage] struct Storage { numbers: Map>, } - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor( number: Field, owner: AztecAddress, @@ -25,7 +29,7 @@ contract BoxReact { numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_note_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m, owner)); } - #[aztec(private)] + #[private] fn setNumber( number: Field, owner: AztecAddress, diff --git a/boxes/boxes/vanilla/src/contracts/src/main.nr b/boxes/boxes/vanilla/src/contracts/src/main.nr index 401a2c86989..65a871dfaaf 100644 --- a/boxes/boxes/vanilla/src/contracts/src/main.nr +++ b/boxes/boxes/vanilla/src/contracts/src/main.nr @@ -1,18 +1,22 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract Vanilla { use dep::aztec::{ keys::public_keys::{IvpkM, OvpkM}, prelude::{AztecAddress, PrivateMutable, Map, NoteInterface, NoteHeader, Point}, - encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys + encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, + macros::{storage::storage, functions::{private, public, initializer}} }; use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; - #[aztec(storage)] + #[storage] struct Storage { numbers: Map>, } - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor( number: Field, owner: AztecAddress, @@ -25,7 +29,7 @@ contract Vanilla { numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_note_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m, owner)); } - #[aztec(private)] + #[private] fn setNumber( number: Field, owner: AztecAddress, diff --git a/boxes/init/src/main.nr b/boxes/init/src/main.nr index 8e06a99f11c..7924ff03505 100644 --- a/boxes/init/src/main.nr +++ b/boxes/init/src/main.nr @@ -1,6 +1,9 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract Main { - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor() { } } diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index 6be58816d1e..f83e1ef20bc 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -14,7 +14,7 @@ global ADDRESS_NOTE_BYTES_LEN: Field = 3 * 32 + 64; // docs:start:address_note_def // docs:start:address_note_struct // Stores an address -#[aztec(note)] +#[note] struct AddressNote { address: AztecAddress, // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index df04e1c4d6f..9ebfb8a8827 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -26,25 +26,25 @@ trait NullifiableNote { // Autogenerated by the #[note] macro trait NoteInterface { - // Autogenerated by the #[aztec(note)] macro + // Autogenerated by the #[note] macro fn serialize_content(self) -> [Field; N]; - // Autogenerated by the #[aztec(note)] macro + // Autogenerated by the #[note] macro fn deserialize_content(fields: [Field; N]) -> Self; - // Autogenerated by the #[aztec(note)] macro + // Autogenerated by the #[note] macro fn get_header(self) -> NoteHeader; - // Autogenerated by the #[aztec(note)] macro + // Autogenerated by the #[note] macro fn set_header(&mut self, header: NoteHeader) -> (); - // Autogenerated by the #[aztec(note)] macro + // Autogenerated by the #[note] macro fn get_note_type_id() -> Field; - // Autogenerated by the #[aztec(note)] macro + // Autogenerated by the #[note] macro fn to_be_bytes(self, storage_slot: Field) -> [u8; N*32 + 64]; - // Autogenerated by the #[aztec(note)] macro + // Autogenerated by the #[note] macro fn compute_note_hash(self) -> Field; } // docs:end:note_interface diff --git a/noir-projects/aztec-nr/uint-note/src/uint_note.nr b/noir-projects/aztec-nr/uint-note/src/uint_note.nr index 96660b551d4..d7c89c4019a 100644 --- a/noir-projects/aztec-nr/uint-note/src/uint_note.nr +++ b/noir-projects/aztec-nr/uint-note/src/uint_note.nr @@ -13,7 +13,7 @@ use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; global UINT_NOTE_LEN: Field = 3; // 3 plus a header. global UINT_NOTE_BYTES_LEN: Field = 3 * 32 + 64; -#[aztec(note)] +#[note] struct UintNote { // The integer stored by the note value: U128, diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 7be2b0de514..5c484123d78 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -1,36 +1,38 @@ mod subscription_note; mod dapp_payload; +use dep::aztec::macros::aztec; + +#[aztec] contract AppSubscription { use crate::{dapp_payload::DAppPayload, subscription_note::SubscriptionNote}; use aztec::{ prelude::{AztecAddress, Map, PrivateMutable, SharedImmutable}, - encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note, encode_and_encrypt_note_with_keys}, keys::getters::get_current_public_keys, protocol_types::constants::MAX_FIELD_VALUE, - utils::comparison::Comparator + utils::comparison::Comparator, macros::{storage, functions::{public, initializer, private}} }; use authwit::auth::assert_current_call_valid_authwit; use token::Token; use router::utils::privately_check_block_number; - #[aztec(storage)] - struct Storage { + #[storage] + struct Storage { // The following is only needed in private but we use ShareImmutable here instead of PrivateImmutable because // the value can be publicly known and SharedImmutable provides us with a better devex here because we don't // have to bother with sharing the note between pixies of users. - target_address: SharedImmutable, - subscription_token_address: SharedImmutable, - subscription_recipient_address: SharedImmutable, - subscription_price: SharedImmutable, - subscriptions: Map>, - fee_juice_limit_per_tx: SharedImmutable, + target_address: SharedImmutable, + subscription_token_address: SharedImmutable, + subscription_recipient_address: SharedImmutable, + subscription_price: SharedImmutable, + subscriptions: Map, Context>, + fee_juice_limit_per_tx: SharedImmutable, } global SUBSCRIPTION_DURATION_IN_BLOCKS = 5; global SUBSCRIPTION_TXS = 5; - #[aztec(private)] + #[private] fn entrypoint(payload: DAppPayload, user_address: AztecAddress) { // Default msg_sender for entrypoints is now Fr.max_value rather than 0 addr (see #7190 & #7404) assert(context.msg_sender().to_field() == MAX_FIELD_VALUE); @@ -59,8 +61,8 @@ contract AppSubscription { payload.execute_calls(&mut context, storage.target_address.read_private()); } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor( target_address: AztecAddress, subscription_recipient_address: AztecAddress, @@ -75,7 +77,7 @@ contract AppSubscription { storage.fee_juice_limit_per_tx.initialize(fee_juice_limit_per_tx); } - #[aztec(private)] + #[private] fn subscribe(subscriber: AztecAddress, nonce: Field, expiry_block_number: Field, tx_count: Field) { assert(tx_count as u64 <= SUBSCRIPTION_TXS as u64); diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index 36ca60c7515..d10a99b49b6 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -9,7 +9,7 @@ global SUBSCRIPTION_NOTE_LEN: Field = 4; // SUBSCRIPTION_NOTE_BYTES_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) global SUBSCRIPTION_NOTE_BYTES_LEN: Field = SUBSCRIPTION_NOTE_LEN * 32 + 64; -#[aztec(note)] +#[note] struct SubscriptionNote { // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. npk_m_hash: Field, diff --git a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr index 885fbdbd162..7149c6a162a 100644 --- a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr @@ -1,30 +1,35 @@ // Test contract showing basic public access control that can be used in private. It uses a SharedMutable state variable to // publicly store the address of an authorized account that can call private functions. +use dep::aztec::macros::aztec; + +#[aztec] contract Auth { - use dep::aztec::protocol_types::address::AztecAddress; - use dep::aztec::state_vars::{PublicImmutable, SharedMutable}; + use dep::aztec::{protocol_types::address::AztecAddress, + state_vars::{PublicImmutable, SharedMutable }, + macros::{storage::storage, functions::{private, public, initializer, view }} + }; // Authorizing a new address has a certain block delay before it goes into effect. global CHANGE_AUTHORIZED_DELAY_BLOCKS = 5; - #[aztec(storage)] - struct Storage { + #[storage] + struct Storage { // Admin can change the value of the authorized address via set_authorized() - admin: PublicImmutable, + admin: PublicImmutable, // docs:start:shared_mutable_storage - authorized: SharedMutable, + authorized: SharedMutable, // docs:end:shared_mutable_storage } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(admin: AztecAddress) { assert(!admin.is_zero(), "invalid admin"); storage.admin.initialize(admin); } // docs:start:shared_mutable_schedule - #[aztec(public)] + #[public] fn set_authorized(authorized: AztecAddress) { assert_eq(storage.admin.read(), context.msg_sender(), "caller is not admin"); storage.authorized.schedule_value_change(authorized); @@ -32,8 +37,8 @@ contract Auth { } // docs:start:public_getter - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_authorized() -> AztecAddress { // docs:start:shared_mutable_get_current_public storage.authorized.get_current_value_in_public() @@ -41,8 +46,8 @@ contract Auth { } // docs:end:public_getter - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_scheduled_authorized() -> AztecAddress { // docs:start:shared_mutable_get_scheduled_public let (scheduled_value, _block_of_change): (AztecAddress, u32) = storage.authorized.get_scheduled_value_in_public(); @@ -50,18 +55,18 @@ contract Auth { scheduled_value } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_authorized_delay() -> pub u32 { storage.authorized.get_current_delay_in_public() } - #[aztec(public)] + #[public] fn set_authorized_delay(new_delay: u32) { storage.authorized.schedule_delay_change(new_delay); } - #[aztec(private)] + #[private] fn do_private_authorized_thing() { // Reading a value from authorized in private automatically adds an extra validity condition: the base rollup // circuit will reject this tx if included in a block past the block horizon, which is as far as the circuit can @@ -72,8 +77,8 @@ contract Auth { assert_eq(authorized, context.msg_sender(), "caller is not authorized"); } - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn get_authorized_in_private() -> AztecAddress { storage.authorized.get_current_value_in_private() } diff --git a/noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr index 12b35516ba2..dcedab28bd9 100644 --- a/noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr @@ -1,12 +1,19 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract AuthRegistry { - use dep::aztec::{state_vars::{PublicMutable, Map}, protocol_types::address::AztecAddress}; + use dep::aztec::{ + state_vars::{PublicMutable, Map}, + protocol_types::address::AztecAddress, + macros::{storage::storage, functions::{private, public, internal}} + }; use dep::authwit::auth::{IS_VALID_SELECTOR, compute_authwit_message_hash, assert_current_call_valid_authwit}; - #[aztec(storage)] - struct Storage { - reject_all: Map>, + #[storage] + struct Storage { + reject_all: Map, Context>, // on_behalf_of => authwit hash => authorized - approved_actions: Map>>, + approved_actions: Map, Context>, Context>, } /** @@ -15,26 +22,26 @@ contract AuthRegistry { * @param message_hash The message hash being authorized * @param authorize True if the caller is authorized to perform the message hash, false otherwise */ - #[aztec(public)] + #[public] fn set_authorized(message_hash: Field, authorize: bool) { storage.approved_actions.at(context.msg_sender()).at(message_hash).write(authorize); } /** * Updates the `reject_all` value for `msg_sender`. - * + * * When `reject_all` is `true` any `consume` on `msg_sender` will revert. - * + * * @param reject True if all actions should be rejected, false otherwise */ - #[aztec(public)] + #[public] fn set_reject_all(reject: bool) { storage.reject_all.at(context.msg_sender()).write(reject); } /** * Consumes an `inner_hash` on behalf of `on_behalf_of` if the caller is authorized to do so. - * + * * Will revert even if the caller is authorized if `reject_all` is set to true for `on_behalf_of`. * This is to support "mass-revoke". * @@ -42,7 +49,7 @@ contract AuthRegistry { * @param inner_hash The inner_hash of the authwit * @return `IS_VALID_SELECTOR` if the action was consumed, revert otherwise */ - #[aztec(public)] + #[public] fn consume(on_behalf_of: AztecAddress, inner_hash: Field) -> Field { assert_eq(false, storage.reject_all.at(on_behalf_of).read(), "rejecting all"); @@ -63,7 +70,7 @@ contract AuthRegistry { /** * Updates a public authwit using a private authwit - * + * * Useful for the case where you want someone else to insert a public authwit for you. * For example, if Alice wants Bob to insert an authwit in public, such that they can execute * a trade, Alice can create a private authwit, and Bob can call this function with it. @@ -72,7 +79,7 @@ contract AuthRegistry { * @param message_hash The message hash to authorize * @param authorize True if the message hash should be authorized, false otherwise */ - #[aztec(private)] + #[private] fn set_authorized_private(approver: AztecAddress, message_hash: Field, authorize: bool) { assert_current_call_valid_authwit(&mut context, approver); AuthRegistry::at(context.this_address())._set_authorized(approver, message_hash, authorize).enqueue(&mut context); @@ -81,38 +88,38 @@ contract AuthRegistry { /** * Internal function to update the `authorized` value for `approver` for `messageHash`. * Used along with `set_authorized_private` to update the public authwit. - * + * * @param approver The address of the approver * @param message_hash The message hash being authorized * @param authorize True if the caller is authorized to perform the message hash, false otherwise */ - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _set_authorized(approver: AztecAddress, message_hash: Field, authorize: bool) { storage.approved_actions.at(approver).at(message_hash).write(authorize); } /** * Fetches the `reject_all` value for `on_behalf_of`. - * + * * @param on_behalf_of The address to check * @return True if all actions are rejected, false otherwise */ - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn is_reject_all(on_behalf_of: AztecAddress) -> bool { storage.reject_all.at(on_behalf_of).read() } /** * Fetches the `authorized` value for `on_behalf_of` for `message_hash`. - * + * * @param on_behalf_of The address on whose behalf the action is being consumed * @param message_hash The message hash to check * @return True if the caller is authorized to perform the action, false otherwise */ - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn is_consumable(on_behalf_of: AztecAddress, message_hash: Field) -> bool { storage.approved_actions.at(on_behalf_of).at(message_hash).read() } diff --git a/noir-projects/noir-contracts/contracts/auth_wit_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_wit_test_contract/src/main.nr index 997d53439a6..0f40ca3c24d 100644 --- a/noir-projects/noir-contracts/contracts/auth_wit_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_wit_test_contract/src/main.nr @@ -1,13 +1,20 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract AuthWitTest { - use dep::aztec::protocol_types::address::AztecAddress; + use dep::aztec::{ + protocol_types::address::AztecAddress, + macros::{functions::{private, public}} + }; + use dep::authwit::auth::{assert_inner_hash_valid_authwit, assert_inner_hash_valid_authwit_public}; - #[aztec(private)] + #[private] fn consume(on_behalf_of: AztecAddress, inner_hash: Field) { assert_inner_hash_valid_authwit(&mut context, on_behalf_of, inner_hash); } - #[aztec(public)] + #[public] fn consume_public(on_behalf_of: AztecAddress, inner_hash: Field) { assert_inner_hash_valid_authwit_public(&mut context, on_behalf_of, inner_hash); } diff --git a/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr index 6e075e89a3e..8c74544a783 100644 --- a/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr @@ -1,23 +1,25 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract AvmInitializerTest { // Libs - use dep::aztec::state_vars::PublicImmutable; - use dep::aztec::protocol_types::address::AztecAddress; + use dep::aztec::{state_vars::PublicImmutable, macros::{storage::storage, functions::{initializer, public}}}; - #[aztec(storage)] - struct Storage { - immutable: PublicImmutable, + #[storage] + struct Storage { + immutable: PublicImmutable, } /************************************************************************ * Storage ************************************************************************/ - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor() { storage.immutable.initialize(42); } - #[aztec(public)] + #[public] fn read_storage_immutable() -> pub Field { storage.immutable.read() } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index a0fa23e74bc..b044038861d 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -17,6 +17,9 @@ impl Deserialize<2> for Note { } } +use dep::aztec::macros::aztec; + +#[aztec] contract AvmTest { use crate::Note; @@ -32,55 +35,56 @@ contract AvmTest { use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, point::Point, scalar::Scalar}; use dep::aztec::oracle::get_contract_instance::{get_contract_instance_avm, get_contract_instance_internal_avm}; use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, storage::map::derive_storage_slot_in_map}; - use dep::aztec::context::gas::GasOpts; use dep::compressed_string::CompressedString; + use dep::aztec::macros::{storage::storage, functions::public}; + - #[aztec(storage)] - struct Storage { - single: PublicMutable, - list: PublicMutable, - map: Map>, + #[storage] + struct Storage { + single: PublicMutable, + list: PublicMutable, + map: Map, Context>, } /************************************************************************ * Storage ************************************************************************/ - #[aztec(public)] + #[public] fn set_storage_single(a: Field) { storage.single.write(a); } - #[aztec(public)] + #[public] fn read_storage_single() -> Field { storage.single.read() } // should still be able to use ` -> pub *` for return type even though macro forces `pub` - #[aztec(public)] + #[public] fn set_read_storage_single(a: Field) -> pub Field { storage.single.write(a); storage.single.read() } - #[aztec(public)] + #[public] fn set_storage_list(a: Field, b: Field) { storage.list.write(Note { a, b }); } - #[aztec(public)] + #[public] fn read_storage_list() -> [Field; 2] { let note: Note = storage.list.read(); note.serialize() } - #[aztec(public)] + #[public] fn set_storage_map(to: AztecAddress, amount: u32) -> Field { storage.map.at(to).write(amount); // returns storage slot for key derive_storage_slot_in_map(storage.map.storage_slot, to) } - #[aztec(public)] + #[public] fn add_storage_map(to: AztecAddress, amount: u32) -> Field { let new_balance = storage.map.at(to).read().add(amount); storage.map.at(to).write(new_balance); @@ -88,12 +92,12 @@ contract AvmTest { derive_storage_slot_in_map(storage.map.storage_slot, to) } - #[aztec(public)] + #[public] fn read_storage_map(address: AztecAddress) -> u32 { storage.map.at(address).read() } - #[aztec(public)] + #[public] fn add_args_return(arg_a: Field, arg_b: Field) -> Field { arg_a + arg_b } @@ -101,47 +105,47 @@ contract AvmTest { /************************************************************************ * General Opcodes ************************************************************************/ - #[aztec(public)] + #[public] fn set_opcode_u8() -> u8 { 8 as u8 } - #[aztec(public)] + #[public] fn set_opcode_u32() -> u32 { 1 << 30 as u8 } - #[aztec(public)] + #[public] fn set_opcode_u64() -> u64 { 1 << 60 as u8 } - #[aztec(public)] + #[public] fn set_opcode_small_field() -> Field { big_field_128_bits } - #[aztec(public)] + #[public] fn set_opcode_big_field() -> Field { big_field_136_bits } - #[aztec(public)] + #[public] fn set_opcode_really_big_field() -> Field { big_field_254_bits } - #[aztec(public)] + #[public] fn add_u128(a: U128, b: U128) -> U128 { a + b } - #[aztec(public)] + #[public] fn modulo2(a: u64) -> u64 { a % 2 } - #[aztec(public)] + #[public] fn elliptic_curve_add_and_double() -> Point { let g = Point { x: 1, y: 17631683881184975370165255887551781615748388533673675138860, is_infinite: false }; @@ -150,7 +154,7 @@ contract AvmTest { added } - #[aztec(public)] + #[public] fn variable_base_msm() -> Point { let g = Point { x: 1, y: 17631683881184975370165255887551781615748388533673675138860, is_infinite: false }; let scalar = Scalar { lo: 3, hi: 0 }; @@ -159,7 +163,7 @@ contract AvmTest { triple_g } - #[aztec(public)] + #[public] fn pedersen_commit(x: Field, y: Field) -> EmbeddedCurvePoint { let commitment = dep::std::hash::pedersen_commitment_with_separator([x, y], 20); commitment @@ -169,20 +173,20 @@ contract AvmTest { * Misc ************************************************************************/ - #[aztec(public)] + #[public] fn u128_addition_overflow() -> U128 { let max_u128: U128 = U128::from_hex("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); let one: U128 = U128::from_integer(1); max_u128 + one } - #[aztec(public)] + #[public] fn u128_from_integer_overflow() -> U128 { let should_overflow: Field = 2.pow_32(128); // U128::max() + 1; U128::from_integer(should_overflow) } - #[aztec(public)] + #[public] fn to_radix_le(input: Field) -> [u8; 10] { input.to_le_radix(/*base=*/ 2) } @@ -196,12 +200,12 @@ contract AvmTest { inner_helper_with_failed_assertion(); } - #[aztec(public)] + #[public] fn assertion_failure() { helper_with_failed_assertion() } - #[aztec(public)] + #[public] fn debug_logging() { dep::aztec::oracle::debug_log::debug_log("just text"); dep::aztec::oracle::debug_log::debug_log_format("second: {1}", [1, 2, 3, 4]); @@ -209,7 +213,7 @@ contract AvmTest { dep::aztec::oracle::debug_log::debug_log("tabs and newlines\n\t- first\n\t- second"); } - #[aztec(public)] + #[public] fn assert_same(arg_a: Field, arg_b: Field) -> pub Field { assert(arg_a == arg_b, "Values are not equal"); 1 @@ -218,32 +222,32 @@ contract AvmTest { /************************************************************************ * Hashing functions ************************************************************************/ - #[aztec(public)] + #[public] fn keccak_hash(data: [u8; 10]) -> [u8; 32] { std::hash::keccak256(data, data.len() as u32) } - #[aztec(public)] + #[public] fn keccak_f1600(data: [u64; 25]) -> [u64; 25] { std::hash::keccak::keccakf1600(data) } - #[aztec(public)] + #[public] fn poseidon2_hash(data: [Field; 10]) -> Field { std::hash::poseidon2::Poseidon2::hash(data, data.len()) } - #[aztec(public)] + #[public] fn sha256_hash(data: [u8; 10]) -> [u8; 32] { std::hash::sha256(data) } - #[aztec(public)] + #[public] fn pedersen_hash(data: [Field; 10]) -> Field { std::hash::pedersen_hash(data) } - #[aztec(public)] + #[public] fn pedersen_hash_with_index(data: [Field; 10]) -> Field { std::hash::pedersen_hash_with_separator(data, /*index=*/ 20) } @@ -251,7 +255,7 @@ contract AvmTest { /************************************************************************ * Contract instance ************************************************************************/ - #[aztec(public)] + #[public] fn test_get_contract_instance_raw() { let fields = get_contract_instance_internal_avm(context.this_address()); // The values here should match those in `avm_simulator.test.ts>Contract>GETCONTRACTINSTANCE deserializes correctly` @@ -264,7 +268,7 @@ contract AvmTest { assert(fields[5] == 0x161718); } - #[aztec(public)] + #[public] fn test_get_contract_instance() { let ci = get_contract_instance_avm(context.this_address()); assert(ci.is_some(), "Contract instance not found!"); @@ -273,78 +277,78 @@ contract AvmTest { /************************************************************************ * AvmContext functions ************************************************************************/ - #[aztec(public)] + #[public] fn get_address() -> AztecAddress { context.this_address() } - #[aztec(public)] + #[public] fn get_storage_address() -> AztecAddress { context.storage_address() } - #[aztec(public)] + #[public] fn get_sender() -> AztecAddress { context.msg_sender() } - #[aztec(public)] + #[public] fn get_function_selector() -> FunctionSelector { context.selector() } - #[aztec(public)] + #[public] fn get_transaction_fee() -> Field { context.transaction_fee() } - #[aztec(public)] + #[public] fn get_chain_id() -> Field { context.chain_id() } - #[aztec(public)] + #[public] fn get_version() -> Field { context.version() } - #[aztec(public)] + #[public] fn get_block_number() -> Field { context.block_number() } - #[aztec(public)] + #[public] fn get_timestamp() -> u64 { context.timestamp() } - #[aztec(public)] + #[public] fn get_fee_per_l2_gas() -> Field { context.fee_per_l2_gas() } - #[aztec(public)] + #[public] fn get_fee_per_da_gas() -> Field { context.fee_per_da_gas() } - #[aztec(public)] + #[public] fn get_l2_gas_left() -> Field { context.l2_gas_left() } - #[aztec(public)] + #[public] fn get_da_gas_left() -> Field { context.da_gas_left() } - #[aztec(public)] + #[public] fn assert_timestamp(expected_timestamp: u64) { let timestamp = context.timestamp(); assert(timestamp == expected_timestamp, "timestamp does not match"); } - #[aztec(public)] + #[public] fn check_selector() { assert( context.selector() == comptime { @@ -353,12 +357,12 @@ contract AvmTest { ); } - #[aztec(public)] + #[public] fn get_args_hash(_a: u8, _fields: [Field; 3]) -> Field { context.get_args_hash() } - #[aztec(public)] + #[public] fn emit_unencrypted_log() { context.emit_unencrypted_log(/*message=*/ [10, 20, 30]); context.emit_unencrypted_log(/*message=*/ "Hello, world!"); @@ -366,36 +370,36 @@ contract AvmTest { context.emit_unencrypted_log(/*message=*/ s); } - #[aztec(public)] + #[public] fn note_hash_exists(note_hash: Field, leaf_index: Field) -> bool { context.note_hash_exists(note_hash, leaf_index) } // Use the standard context interface to emit a new note hash - #[aztec(public)] + #[public] fn new_note_hash(note_hash: Field) { context.push_note_hash(note_hash); } // Use the standard context interface to emit a new nullifier - #[aztec(public)] + #[public] fn new_nullifier(nullifier: Field) { context.push_nullifier(nullifier); } // Use the standard context interface to check for a nullifier - #[aztec(public)] + #[public] fn nullifier_exists(nullifier: Field) -> bool { context.nullifier_exists(nullifier, context.storage_address()) } - #[aztec(public)] + #[public] fn assert_nullifier_exists(nullifier: Field) { assert(context.nullifier_exists(nullifier, context.storage_address()), "Nullifier doesn't exist!"); } // Use the standard context interface to emit a new nullifier - #[aztec(public)] + #[public] fn emit_nullifier_and_check(nullifier: Field) { context.push_nullifier(nullifier); let exists = context.nullifier_exists(nullifier, context.storage_address()); @@ -403,19 +407,19 @@ contract AvmTest { } // Create the same nullifier twice (shouldn't work!) - #[aztec(public)] + #[public] fn nullifier_collision(nullifier: Field) { context.push_nullifier(nullifier); // Can't do this twice! context.push_nullifier(nullifier); } - #[aztec(public)] + #[public] fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> bool { context.l1_to_l2_msg_exists(msg_hash, msg_leaf_index) } - #[aztec(public)] + #[public] fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) { context.message_portal(recipient, content) } @@ -423,7 +427,7 @@ contract AvmTest { /************************************************************************ * Nested calls ************************************************************************/ - #[aztec(public)] + #[public] fn nested_call_to_add_with_gas( arg_a: Field, arg_b: Field, @@ -434,30 +438,30 @@ contract AvmTest { } // Use the `call_public_function` wrapper to initiate a nested call to the add function - #[aztec(public)] + #[public] fn nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { AvmTest::at(context.this_address()).add_args_return(arg_a, arg_b).call(&mut context) } // Indirectly call_static the external call opcode to initiate a nested call to the add function - #[aztec(public)] + #[public] fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { AvmTest::at(context.this_address()).add_args_return(arg_a, arg_b).view(&mut context) } // Indirectly call_static `set_storage_single`. Should revert since it's accessing storage. - #[aztec(public)] + #[public] fn nested_static_call_to_set_storage() { AvmTest::at(context.this_address()).set_storage_single(20).view(&mut context); } - #[aztec(public)] + #[public] fn create_same_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field) { context.push_nullifier(nullifier); AvmTest::at(nestedAddress).new_nullifier(nullifier).call(&mut context); } - #[aztec(public)] + #[public] fn create_different_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field) { context.push_nullifier(nullifier); AvmTest::at(nestedAddress).new_nullifier(nullifier + 1).call(&mut context); @@ -466,7 +470,7 @@ contract AvmTest { /** * Enqueue a public call from private */ - #[aztec(private)] + #[private] fn enqueue_public_from_private() { AvmTest::at(context.this_address()).set_opcode_u8().enqueue_view(&mut context); AvmTest::at(context.this_address()).set_read_storage_single(5).enqueue(&mut context); diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr index 5f7690615da..a9c6e7daed3 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -3,20 +3,25 @@ // would alter the metrics we're capturing in the benchmarks, and we want to keep the // subject being tested as unmodified as possible so we can detect metric changes that +use dep::aztec::macros::aztec; + +#[aztec] contract Benchmarking { use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, Map, PublicMutable, PrivateSet}; use dep::value_note::{utils::{increment, decrement}, value_note::ValueNote}; use dep::aztec::context::gas::GasOpts; + use dep::aztec::macros::{storage::storage, functions::{private, public}}; + - #[aztec(storage)] - struct Storage { - notes: Map>, - balances: Map>, + #[storage] + struct Storage { + notes: Map, Context>, + balances: Map, Context>, } // Creates a new value note for the target owner. Use this method to seed an initial set of notes. - #[aztec(private)] + #[private] fn create_note(owner: AztecAddress, outgoing_viewer: AztecAddress, value: Field) { // docs:start:increment_valuenote increment(storage.notes.at(owner), value, owner, outgoing_viewer); @@ -27,7 +32,7 @@ contract Benchmarking { // multiple txs that will land on the same block. // See https://discourse.aztec.network/t/utxo-concurrency-issues-for-private-state/635 // by @rahul-kothari for a full explanation on why this is needed. - #[aztec(private)] + #[private] fn recreate_note(owner: AztecAddress, outgoing_viewer: AztecAddress, index: u32) { let owner_notes = storage.notes.at(owner); let mut getter_options = NoteGetterOptions::new(); @@ -37,7 +42,7 @@ contract Benchmarking { } // Reads and writes to public storage and enqueues a call to another public function. - #[aztec(public)] + #[public] fn increment_balance(owner: AztecAddress, value: Field) { let current = storage.balances.at(owner).read(); storage.balances.at(owner).write(current + value); @@ -45,7 +50,7 @@ contract Benchmarking { } // Emits a public log. - #[aztec(public)] + #[public] fn broadcast(owner: AztecAddress) { context.emit_unencrypted_log(storage.balances.at(owner).read()); } diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr index df8318028a1..83d4f70f6e5 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr @@ -1,6 +1,9 @@ mod cards; mod game; +use dep::aztec::macros::aztec; + +#[aztec] contract CardGame { use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; use dep::aztec::{hash::pedersen_hash, state_vars::{Map, PublicMutable}}; @@ -11,15 +14,16 @@ contract CardGame { use crate::cards::{PACK_CARDS, Deck, Card, get_pack_cards, compute_deck_strength}; use crate::game::{NUMBER_OF_PLAYERS, NUMBER_OF_CARDS_DECK, PLAYABLE_CARDS, PlayerEntry, Game, GAME_SERIALIZED_LEN}; + use dep::aztec::macros::{storage::storage, functions::{private, public, internal}}; - #[aztec(storage)] - struct Storage { - collections: Map, - game_decks: Map>, - games: Map>, + #[storage] + struct Storage { + collections: Map, + game_decks: Map, Context>, + games: Map, Context>, } - #[aztec(private)] + #[private] fn buy_pack(seed: Field // The randomness used to generate the cards. Passed in for now. ) { let buyer = context.msg_sender(); @@ -29,7 +33,7 @@ contract CardGame { let _inserted_cards = collection.add_cards(cards, buyer); } - #[aztec(private)] + #[private] fn join_game(game: u32, cards_fields: [Field; 2]) { let cards = cards_fields.map(|card_field| Card::from_field(card_field)); @@ -43,8 +47,8 @@ contract CardGame { CardGame::at(context.this_address()).on_game_joined(game, player, strength as u32).enqueue(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn on_game_joined(game: u32, player: AztecAddress, deck_strength: u32) { let game_storage = storage.games.at(game as Field); @@ -54,7 +58,7 @@ contract CardGame { game_storage.write(game_data); } - #[aztec(public)] + #[public] fn start_game(game: u32) { let game_storage = storage.games.at(game as Field); @@ -63,7 +67,7 @@ contract CardGame { game_storage.write(game_data); } - #[aztec(private)] + #[private] fn play_card(game: u32, card: Card) { let player = context.msg_sender(); @@ -75,8 +79,8 @@ contract CardGame { // docs:end:call_public_function } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn on_card_played(game: u32, player: AztecAddress, card_as_field: Field) { let game_storage = storage.games.at(game as Field); @@ -90,7 +94,7 @@ contract CardGame { game_storage.write(game_data); } - #[aztec(private)] + #[private] fn claim_cards(game: u32, cards_fields: [Field; PLAYABLE_CARDS]) { let player = context.msg_sender(); let cards = cards_fields.map(|card_field| Card::from_field(card_field)); @@ -100,8 +104,8 @@ contract CardGame { CardGame::at(context.this_address()).on_cards_claimed(game, player, pedersen_hash(cards_fields, 0)).enqueue(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn on_cards_claimed(game: u32, player: AztecAddress, cards_hash: Field) { let game_storage = storage.games.at(game as Field); let mut game_data = game_storage.read(); diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 50074872b2a..a2e8fecd9ed 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -1,4 +1,7 @@ // A contract used along with `Parent` contract to test nested calls. +use dep::aztec::macros::aztec; + +#[aztec] contract Child { use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize, Map}; @@ -6,31 +9,33 @@ contract Child { context::gas::GasOpts, protocol_types::{abis::call_context::CallContext}, note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, - keys::getters::get_current_public_keys, utils::comparison::Comparator + keys::getters::get_current_public_keys, utils::comparison::Comparator, + macros::{storage::storage, functions::{private, public, internal}}; + }; use dep::value_note::value_note::ValueNote; - #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_map_with_private_values: Map>, + #[storage] + struct Storage { + current_value: PublicMutable, + a_map_with_private_values: Map, Context>, } // 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)] + #[private] fn value(input: Field) -> Field { input + context.chain_id() + context.version() } // Returns a sum of the input and the chain id and version of the contract in private circuit public input's return_values. // Can only be called from this contract. - #[aztec(private)] - #[aztec(internal)] + #[private] + #[internal] fn value_internal(input: Field) -> Field { input + context.chain_id() + context.version() } // Returns base_value + chain_id + version + block_number + timestamp - #[aztec(public)] + #[public] fn pub_get_value(base_value: Field) -> Field { let return_value = base_value + context.chain_id() @@ -42,7 +47,7 @@ contract Child { } // Sets `current_value` to `new_value` - #[aztec(public)] + #[public] fn pub_set_value(new_value: Field) -> Field { storage.current_value.write(new_value); context.emit_unencrypted_log(new_value); @@ -50,7 +55,7 @@ contract Child { new_value } - #[aztec(private)] + #[private] fn private_set_value(new_value: Field, owner: AztecAddress) -> Field { let owner_keys = get_current_public_keys(&mut context, owner); @@ -59,7 +64,7 @@ contract Child { new_value } - #[aztec(private)] + #[private] fn private_get_value(amount: Field, owner: AztecAddress) -> Field { let mut options = NoteGetterOptions::new(); options = options.select(ValueNote::properties().value, Comparator.EQ, amount).set_limit(1); @@ -68,7 +73,7 @@ contract Child { } // Increments `current_value` by `new_value` - #[aztec(public)] + #[public] fn pub_inc_value(new_value: Field) -> Field { let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); @@ -78,8 +83,8 @@ contract Child { } // Increments `current_value` by `new_value`. Can only be called from this contract. - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn pub_inc_value_internal(new_value: Field) -> Field { let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); @@ -88,21 +93,21 @@ contract Child { new_value } - #[aztec(public)] + #[public] fn set_value_twice_with_nested_first() { let _result = Child::at(context.this_address()).pub_set_value(10).call(&mut context); storage.current_value.write(20); context.emit_unencrypted_log(20); } - #[aztec(public)] + #[public] fn set_value_twice_with_nested_last() { storage.current_value.write(20); context.emit_unencrypted_log(20); let _result = Child::at(context.this_address()).pub_set_value(10).call(&mut context); } - #[aztec(public)] + #[public] fn set_value_with_two_nested_calls() { Child::at(context.this_address()).set_value_twice_with_nested_first().call(&mut context); Child::at(context.this_address()).set_value_twice_with_nested_last().call(&mut context); diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index e39e00df441..9bc2f323d8f 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -1,28 +1,32 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract Claim { use dep::aztec::{ note::utils::compute_note_hash_for_nullify, protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}, - state_vars::SharedImmutable + state_vars::SharedImmutable, + macros::{storage::storage, functions::{private, public, initializer}} }; use dep::value_note::value_note::ValueNote; use dep::token::Token; - #[aztec(storage)] - struct Storage { + #[storage] + struct Storage { // Address of a contract based on whose notes we distribute the rewards - target_contract: SharedImmutable, + target_contract: SharedImmutable, // Token to be distributed as a reward when claiming - reward_token: SharedImmutable, + reward_token: SharedImmutable, } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(target_contract: AztecAddress, reward_token: AztecAddress) { storage.target_contract.initialize(target_contract); storage.reward_token.initialize(reward_token); } - #[aztec(private)] + #[private] fn claim(proof_note: ValueNote, recipient: AztecAddress) { // 1) Check that the note corresponds to the target contract and belongs to the sender let target_address = storage.target_contract.read_private(); diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr index 3cbea7c57ca..5705f9378d1 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr @@ -4,7 +4,7 @@ use dep::aztec::protocol_types::{ traits::Serialize }; -// #[aztec(event)] +// #[event] struct ContractClassRegistered { contract_class_id: ContractClassId, version: Field, diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr index 3e23539c72f..11735b33316 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr @@ -13,8 +13,8 @@ use dep::aztec::protocol_types::{ struct InnerPrivateFunction { selector: FunctionSelector, - metadata_hash: Field, - vk_hash: Field, + metadata_hash: Field, + vk_hash: Field, } impl Serialize<3> for InnerPrivateFunction { @@ -25,8 +25,8 @@ impl Serialize<3> for InnerPrivateFunction { struct PrivateFunction { selector: FunctionSelector, - metadata_hash: Field, - vk_hash: Field, + metadata_hash: Field, + vk_hash: Field, bytecode: [Field; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS], } @@ -43,7 +43,7 @@ impl Serialize for } } -// #[aztec(event)] +// #[event] struct ClassPrivateFunctionBroadcasted { contract_class_id: ContractClassId, artifact_metadata_hash: Field, diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr index 382f94aac9f..28a6e791e85 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr @@ -12,7 +12,7 @@ use dep::aztec::protocol_types::{ struct InnerUnconstrainedFunction { selector: FunctionSelector, - metadata_hash: Field, + metadata_hash: Field, } impl Serialize<2> for InnerUnconstrainedFunction { @@ -23,7 +23,7 @@ impl Serialize<2> for InnerUnconstrainedFunction { struct UnconstrainedFunction { selector: FunctionSelector, - metadata_hash: Field, + metadata_hash: Field, bytecode: [Field; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS], } @@ -39,7 +39,7 @@ impl Serialize { // Token used for donations (e.g. DAI) - donation_token: SharedImmutable, + donation_token: SharedImmutable, // Crowdfunding campaign operator - operator: SharedImmutable, + operator: SharedImmutable, // End of the crowdfunding campaign after which no more donations are accepted - deadline: SharedImmutable, + deadline: SharedImmutable, // Notes emitted to donors when they donate (can be used as proof to obtain rewards, eg in Claim contracts) - donation_receipts: PrivateSet, + donation_receipts: PrivateSet, } // docs:end:storage @@ -40,8 +45,8 @@ contract Crowdfunding { // docs:start:init // docs:start:init-header // docs:start:init-header-error - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] // this-will-error:init-header-error fn init(donation_token: AztecAddress, operator: AztecAddress, deadline: u64) { // docs:end:init-header @@ -53,7 +58,7 @@ contract Crowdfunding { // docs:end:init // docs:start:donate - #[aztec(private)] + #[private] fn donate(amount: u64) { // 1) Check that the deadline has not passed --> we do that via the router contract to conceal which contract // is performing the check. @@ -80,7 +85,7 @@ contract Crowdfunding { // docs:start:operator-withdrawals // Withdraws balance to the operator. Requires that msg_sender() is the operator. - #[aztec(private)] + #[private] fn withdraw(amount: u64) { // 1) Check that msg_sender() is the operator let operator_address = storage.operator.read_private(); @@ -93,8 +98,8 @@ contract Crowdfunding { } // docs:end:operator-withdrawals - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _publish_donation_receipts(amount: u64, to: AztecAddress) { WithdrawalProcessed { amount: amount as Field, who: to.to_field() }.emit(encode_event(&mut context)); } diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr index c1ae841fa6c..ff84f8cf231 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr @@ -1,4 +1,7 @@ // A contract used along with `Parent` contract to test nested calls. +use dep::aztec::macros::aztec; + +#[aztec] contract DelegatedOn { use dep::aztec::prelude::{ AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, NoteViewerOptions, PublicMutable, @@ -6,17 +9,18 @@ contract DelegatedOn { }; use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note, - keys::getters::get_current_public_keys, utils::comparison::Comparator + keys::getters::get_current_public_keys, utils::comparison::Comparator, + macros::{storage::storage, functions::{private, public}} }; use dep::value_note::value_note::ValueNote; - #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_map_with_private_values: Map>, + #[storage] + struct Storage { + current_value: PublicMutable, + a_map_with_private_values: Map, Context>, } - #[aztec(private)] + #[private] fn private_set_value(new_value: Field, owner: AztecAddress) -> Field { let owner_npk_m_hash = get_current_public_keys(&mut context, owner).npk_m.hash(); @@ -25,13 +29,13 @@ contract DelegatedOn { new_value } - #[aztec(public)] + #[public] fn public_set_value(new_value: Field) -> Field { storage.current_value.write(new_value); new_value } - #[aztec(private)] + #[private] fn get_private_value(amount: Field, owner: AztecAddress) -> pub Field { let mut options = NoteGetterOptions::new(); options = options.select(ValueNote::properties().value, Comparator.EQ, amount).set_limit(1); diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index 402230a2fb8..6e7acf7f8c0 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -1,17 +1,20 @@ // A contract used along with `Parent` contract to test nested calls. +use dep::aztec::macros::aztec; + +#[aztec] contract Delegator { use dep::aztec::prelude::{AztecAddress, NoteGetterOptions, PublicMutable, PrivateSet, Map}; use dep::value_note::value_note::ValueNote; use dep::delegated_on::DelegatedOn; - use dep::aztec::utils::comparison::Comparator; + use dep::aztec::{utils::comparison::Comparator, macros::{storage::storage, functions::{private, public}}}; - #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_map_with_private_values: Map>, + #[storage] + struct Storage { + current_value: PublicMutable, + a_map_with_private_values: Map, Context>, } - #[aztec(private)] + #[private] fn private_delegate_set_value( target_contract: AztecAddress, value: Field, @@ -21,17 +24,17 @@ contract Delegator { DelegatedOn::at(target_contract).private_set_value(value, owner).delegate_call(&mut context) } - #[aztec(private)] + #[private] fn enqueued_delegate_set_value(target_contract: AztecAddress, value: Field) { DelegatedOn::at(target_contract).public_set_value(value).delegate_enqueue(&mut context) } - #[aztec(public)] + #[public] fn public_delegate_set_value(target_contract: AztecAddress, value: Field) -> Field { DelegatedOn::at(target_contract).public_set_value(value).delegate_call(&mut context) } - #[aztec(private)] + #[private] fn get_private_value(amount: Field, owner: AztecAddress) -> pub Field { let mut options = NoteGetterOptions::new(); options = options.select(ValueNote::properties().value, Comparator.EQ, amount).set_limit(1); diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index 7a84beae36f..598d161f0c9 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -11,6 +11,9 @@ mod types; // also has `options.nr` which shows various ways of using `NoteGetterOptions` to query notes // it also shows what our macros do behind the scenes! +use dep::aztec::macros::aztec; + +#[aztec] contract DocsExample { // how to import dependencies defined in your workspace use dep::aztec::prelude::{ @@ -22,17 +25,17 @@ contract DocsExample { // how to import methods from other files/folders within your workspace use crate::types::{card_note::CardNote, leader::Leader}; - #[aztec(storage)] - struct Storage { + #[storage] + struct Storage { // Shows how to create a custom struct in PublicMutable // docs:start:storage-leader-declaration - leader: PublicMutable, + leader: PublicMutable, // docs:end:storage-leader-declaration // docs:start:storage-private-mutable-declaration - legendary_card: PrivateMutable, + legendary_card: PrivateMutable, // docs:end:storage-private-mutable-declaration // just used for docs example to show how to create a private mutable map. - profiles: Map>, + profiles: Map, Context>, // docs:start:storage-set-declaration set: PrivateSet, // docs:end:storage-set-declaration @@ -91,13 +94,13 @@ contract DocsExample { } } - #[aztec(public)] + #[public] fn initialize_shared_immutable(points: u8) { let mut new_leader = Leader { account: context.msg_sender(), points }; storage.shared_immutable.initialize(new_leader); } - #[aztec(private)] + #[private] fn match_shared_immutable(account: AztecAddress, points: u8) { let expected = Leader { account, points }; let read = storage.shared_immutable.read_private(); @@ -106,7 +109,7 @@ contract DocsExample { assert(read.points == expected.points, "Invalid points"); } - #[aztec(private)] + #[private] fn get_shared_immutable_constrained_private_indirect() -> pub Leader { // This is a private function that calls another private function // and returns the response. @@ -117,7 +120,7 @@ contract DocsExample { leader } - #[aztec(public)] + #[public] fn get_shared_immutable_constrained_public_indirect() -> pub Leader { // This is a public function that calls another public function // and returns the response. @@ -128,20 +131,20 @@ contract DocsExample { leader } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_shared_immutable_constrained_public() -> pub Leader { storage.shared_immutable.read_public() } - #[aztec(public)] + #[public] fn get_shared_immutable_constrained_public_multiple() -> pub [Leader; 5] { let a = storage.shared_immutable.read_public(); [a, a, a, a, a] } - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn get_shared_immutable_constrained_private() -> pub Leader { storage.shared_immutable.read_private() } @@ -150,7 +153,7 @@ contract DocsExample { storage.shared_immutable.read_public() } - #[aztec(public)] + #[public] fn initialize_public_immutable(points: u8) { // docs:start:initialize_public_immutable let mut new_leader = Leader { account: context.msg_sender(), points }; @@ -165,7 +168,7 @@ contract DocsExample { } // docs:start:initialize-private-mutable - #[aztec(private)] + #[private] fn initialize_private_immutable(randomness: Field, points: u8) { let msg_sender_npk_m_hash = get_current_public_keys(&mut context, context.msg_sender()).npk_m.hash(); @@ -174,7 +177,7 @@ contract DocsExample { } // docs:end:initialize-private-mutable - #[aztec(private)] + #[private] // msg_sender() is 0 at deploy time. So created another function fn initialize_private(randomness: Field, points: u8) { let msg_sender_npk_m_hash = get_current_public_keys(&mut context, context.msg_sender()).npk_m.hash(); @@ -184,7 +187,7 @@ contract DocsExample { storage.legendary_card.initialize(&mut legendary_card).emit(encode_and_encrypt_note(&mut context, context.msg_sender(), context.msg_sender())); } - #[aztec(private)] + #[private] fn insert_notes(amounts: [u8; 3]) { let sender_keys = get_current_public_keys(&mut context, context.msg_sender()); let sender_npk_m_hash = sender_keys.npk_m.hash(); @@ -202,7 +205,7 @@ contract DocsExample { } } - #[aztec(private)] + #[private] fn insert_note(amount: u8, randomness: Field) { let sender_npk_m_hash = get_current_public_keys(&mut context, context.msg_sender()).npk_m.hash(); @@ -217,7 +220,7 @@ contract DocsExample { } // docs:end:state_vars-NoteGetterOptionsComparatorExampleNoir - #[aztec(private)] + #[private] fn update_legendary_card(randomness: Field, points: u8) { let sender_npk_m_hash = get_current_public_keys(&mut context, context.msg_sender()).npk_m.hash(); @@ -226,7 +229,7 @@ contract DocsExample { DocsExample::at(context.this_address()).update_leader(context.msg_sender(), points).enqueue(&mut context); } - #[aztec(private)] + #[private] fn increase_legendary_points() { // Ensure `points` > current value // Also serves as a e2e test that you can `get_note()` and then `replace()` @@ -248,19 +251,19 @@ contract DocsExample { DocsExample::at(context.this_address()).update_leader(context.msg_sender(), points).enqueue(&mut context); } - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn verify_private_authwit(inner_hash: Field) -> Field { 1 } - #[aztec(public)] + #[public] fn spend_public_authwit(inner_hash: Field) -> Field { 1 } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn update_leader(account: AztecAddress, points: u8) { let new_leader = Leader { account, points }; storage.leader.write(new_leader); @@ -281,7 +284,7 @@ contract DocsExample { // docs:end:private_mutable_is_initialized // docs:start:get_note-private-immutable - #[aztec(private)] + #[private] fn get_imm_card() -> CardNote { storage.private_immutable.get_note() } @@ -300,7 +303,7 @@ contract DocsExample { use dep::aztec::context::inputs::PrivateContextInputs; // docs:start:simple_macro_example - #[aztec(private)] + #[private] fn simple_macro_example(a: Field, b: Field) -> Field { a + b } diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 053db37aa93..18ddb819354 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -1,17 +1,12 @@ -use dep::aztec::prelude::{NoteInterface, NoteHeader, PrivateContext}; +use dep::aztec::prelude::{NullifiableNote, PrivateContext}; use dep::aztec::{ note::{utils::compute_note_hash_for_nullify}, keys::getters::get_nsk_app, protocol_types::{traits::Serialize, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; -// Shows how to create a custom note - -global CARD_NOTE_LEN: Field = 3; -// CARD_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global CARD_NOTE_BYTES_LEN: Field = 3 * 32 + 64; // docs:start:state_vars-CardNote -#[aztec(note)] +#[note] struct CardNote { points: u8, randomness: Field, @@ -29,7 +24,7 @@ impl CardNote { // docs:end:cardnote_impl // docs:start:note_interface -impl NoteInterface for CardNote { +impl NullifiableNote for CardNote { fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); poseidon2_hash_with_separator( diff --git a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr index 72959179f75..8e118629ed8 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr @@ -1,19 +1,23 @@ // docs:start:easy_private_token_contract +use dep::aztec::macros::aztec; + +#[aztec] contract EasyPrivateToken { use dep::aztec::prelude::{AztecAddress, Map}; use dep::value_note::balance_utils; use dep::easy_private_state::EasyPrivateUint; + use dep::aztec::macros::{storage::storage, functions::{initializer, private}}; - #[aztec(storage)] - struct Storage { - balances: Map, + #[storage] + struct Storage { + balances: Map, Context>, } /** * initialize the contract's initial state variables. */ - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor(initial_supply: u64, owner: AztecAddress, outgoing_viewer: AztecAddress) { let balances = storage.balances; @@ -21,7 +25,7 @@ contract EasyPrivateToken { } // Mints `amount` of tokens to `owner`. - #[aztec(private)] + #[private] fn mint(amount: u64, owner: AztecAddress, outgoing_viewer: AztecAddress) { let balances = storage.balances; @@ -29,7 +33,7 @@ contract EasyPrivateToken { } // Transfers `amount` of tokens from `sender` to a `recipient`. - #[aztec(private)] + #[private] fn transfer( amount: u64, sender: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 387e6b9fdf9..0749500796a 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -1,21 +1,27 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract EasyPrivateVoting { // docs:start:imports use dep::aztec::prelude::{AztecAddress, Map, PublicMutable, SharedImmutable}; - use dep::aztec::keys::getters::get_historical_public_keys; + use dep::aztec::{ + keys::getters::get_historical_public_keys, + macros::{storage::storage, functions::{public, initializer, private, internal}} + }; // docs:end:imports // docs:start:storage_struct - #[aztec(storage)] - struct Storage { - admin: PublicMutable, // admin can end vote - tally: Map>, // we will store candidate as key and number of votes as value - vote_ended: PublicMutable, // vote_ended is boolean - active_at_block: SharedImmutable, // when people can start voting + #[storage] + struct Storage { + admin: PublicMutable, // admin can end vote + tally: Map, Context>, // we will store candidate as key and number of votes as value + vote_ended: PublicMutable, // vote_ended is boolean + active_at_block: SharedImmutable, // when people can start voting } // docs:end:storage_struct // docs:start:constructor - #[aztec(public)] - #[aztec(initializer)] // annotation to mark function as a constructor + #[public] + #[initializer] // annotation to mark function as a constructor fn constructor(admin: AztecAddress) { storage.admin.write(admin); storage.vote_ended.write(false); @@ -24,7 +30,7 @@ contract EasyPrivateVoting { // docs:end:constructor // docs:start:cast_vote - #[aztec(private)] // annotation to mark function as private and expose private context + #[private] // annotation to mark function as private and expose private context fn cast_vote(candidate: Field) { // Below, we make sure to get our nullifier public key at a specific block. By pinning the nullifier public key at a specific block, // rotating keys will have no effect on the nullifier being produced, and voting again after will fail because the same nullifier is computed each time the user votes. @@ -39,8 +45,8 @@ contract EasyPrivateVoting { // docs:end:cast_vote // docs:start:add_to_tally_public - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn add_to_tally_public(candidate: Field) { assert(storage.vote_ended.read() == false, "Vote has ended"); // assert that vote has not ended let new_tally = storage.tally.at(candidate).read() + 1; @@ -49,7 +55,7 @@ contract EasyPrivateVoting { // docs:end:add_to_tally_public // docs:start:end_vote - #[aztec(public)] + #[public] fn end_vote() { assert(storage.admin.read().eq(context.msg_sender()), "Only admin can end votes"); // assert that caller is admin storage.vote_ended.write(true); diff --git a/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr index b80c6d00f98..920f5a5303f 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr @@ -1,10 +1,14 @@ // Account contract that uses ECDSA signatures for authentication on the same curve as Ethereum. // The signing key is stored in an immutable private note and should be different from the signing key. +use dep::aztec::macros::aztec; + +#[aztec] contract EcdsaKAccount { use dep::aztec::prelude::{PrivateContext, PrivateImmutable}; use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, - keys::getters::get_current_public_keys + keys::getters::get_current_public_keys, + macros::{storage::storage, functions::{private, initializer, view, noinitcheck}}, }; use dep::authwit::{ @@ -14,14 +18,14 @@ contract EcdsaKAccount { use dep::ecdsa_public_key_note::EcdsaPublicKeyNote; - #[aztec(storage)] - struct Storage { - public_key: PrivateImmutable, + #[storage] + struct Storage { + public_key: PrivateImmutable, } // Creates a new account out of an ECDSA public key to use for signature verification - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor(signing_pub_key_x: [u8; 32], signing_pub_key_y: [u8; 32]) { let this = context.this_address(); let this_keys = get_current_public_keys(&mut context, this); @@ -34,15 +38,15 @@ contract EcdsaKAccount { } // Note: If you globally change the entrypoint signature don't forget to update account_entrypoint.ts - #[aztec(private)] + #[private] fn entrypoint(app_payload: AppPayload, fee_payload: FeePayload, cancellable: bool) { let actions = AccountActions::init(&mut context, is_valid_impl); actions.entrypoint(app_payload, fee_payload, cancellable); } - #[aztec(private)] - #[aztec(noinitcheck)] - #[aztec(view)] + #[private] + #[noinitcheck] + #[view] fn verify_private_authwit(inner_hash: Field) -> Field { let actions = AccountActions::init(&mut context, is_valid_impl); actions.verify_private_authwit(inner_hash) diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index 511e046c7ce..0d2c577f677 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -11,7 +11,7 @@ global ECDSA_PUBLIC_KEY_NOTE_BYTES_LEN: Field = 5 * 32 + 64; // Stores an ECDSA public key composed of two 32-byte elements // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? -#[aztec(note)] +#[note] struct EcdsaPublicKeyNote { x: [u8; 32], y: [u8; 32], @@ -19,7 +19,7 @@ struct EcdsaPublicKeyNote { npk_m_hash: Field, } -impl NoteInterface for EcdsaPublicKeyNote { +impl NullifiableNote for EcdsaPublicKeyNote { // Cannot use the automatic serialization since x and y don't fit. Serialize the note as 5 fields where: // [0] = x[0..31] (upper bound excluded) // [1] = x[31] diff --git a/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr index 9c9ca530495..307a9ca506b 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr @@ -1,9 +1,13 @@ // Account contract that uses ECDSA signatures for authentication on random version of the p256 curve (to use with touchID). +use dep::aztec::macros::aztec; + +#[aztec] contract EcdsaRAccount { use dep::aztec::prelude::{PrivateContext, PrivateImmutable}; use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, - keys::getters::get_current_public_keys + keys::getters::get_current_public_keys, + macros::{storage::storage, functions::{private, initializer, view, noinitcheck}}, }; use dep::authwit::{ @@ -13,14 +17,14 @@ contract EcdsaRAccount { use dep::ecdsa_public_key_note::EcdsaPublicKeyNote; - #[aztec(storage)] - struct Storage { - public_key: PrivateImmutable, + #[storage] + struct Storage { + public_key: PrivateImmutable, } // Creates a new account out of an ECDSA public key to use for signature verification - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor(signing_pub_key_x: [u8; 32], signing_pub_key_y: [u8; 32]) { let this = context.this_address(); let this_keys = get_current_public_keys(&mut context, this); @@ -33,15 +37,15 @@ contract EcdsaRAccount { } // Note: If you globally change the entrypoint signature don't forget to update account_entrypoint.ts - #[aztec(private)] + #[private] fn entrypoint(app_payload: AppPayload, fee_payload: FeePayload, cancellable: bool) { let actions = AccountActions::init(&mut context, is_valid_impl); actions.entrypoint(app_payload, fee_payload, cancellable); } - #[aztec(private)] - #[aztec(noinitcheck)] - #[aztec(view)] + #[private] + #[noinitcheck] + #[view] fn verify_private_authwit(inner_hash: Field) -> Field { let actions = AccountActions::init(&mut context, is_valid_impl); actions.verify_private_authwit(inner_hash) diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index 9d17a6833fa..c283dd12237 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -1,9 +1,13 @@ // Sample escrow contract that stores a balance of a private token on behalf of an owner. +use dep::aztec::macros::aztec; + +#[aztec] contract Escrow { use dep::aztec::prelude::{AztecAddress, PrivateImmutable}; use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, - keys::getters::get_current_public_keys + keys::getters::get_current_public_keys, + macros::{storage::storage, functions::{private, initializer}}, }; // docs:start:addressnote_import @@ -11,14 +15,14 @@ contract Escrow { // docs:end:addressnote_import use dep::token::Token; - #[aztec(storage)] - struct Storage { - owner: PrivateImmutable, + #[storage] + struct Storage { + owner: PrivateImmutable, } // Creates a new instance - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor(owner: AztecAddress) { let owner_keys = get_current_public_keys(&mut context, owner); let msg_sender_keys = get_current_public_keys(&mut context, context.msg_sender()); @@ -31,7 +35,7 @@ contract Escrow { } // Withdraws balance. Requires that msg.sender is the owner. - #[aztec(private)] + #[private] fn withdraw(token: AztecAddress, amount: Field, recipient: AztecAddress) { let sender = context.msg_sender(); diff --git a/noir-projects/noir-contracts/contracts/fee_juice_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fee_juice_contract/src/main.nr index a5d008e160e..5718d59a554 100644 --- a/noir-projects/noir-contracts/contracts/fee_juice_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fee_juice_contract/src/main.nr @@ -1,5 +1,8 @@ mod lib; +use dep::aztec::macros::aztec; + +#[aztec] contract FeeJuice { use dep::aztec::{ protocol_types::{ @@ -7,7 +10,8 @@ contract FeeJuice { constants::{DEPLOYER_CONTRACT_ADDRESS, REGISTERER_CONTRACT_ADDRESS, FEE_JUICE_INITIAL_MINT} }, state_vars::{SharedImmutable, PublicMutable, Map}, - oracle::get_contract_instance::get_contract_instance + oracle::get_contract_instance::get_contract_instance, + macros::{storage::storage, functions::{private, public, view, internal}} }; use dep::deployer::ContractInstanceDeployer; @@ -15,17 +19,17 @@ contract FeeJuice { use crate::lib::get_bridge_gas_msg_hash; - #[aztec(storage)] - struct Storage { + #[storage] + struct Storage { // This map is accessed directly by protocol circuits to check balances for fee payment. // Do not change this storage layout unless you also update the base rollup circuits. - balances: Map>, - portal_address: SharedImmutable, + balances: Map, Context>, + portal_address: SharedImmutable, } // Not flagged as initializer to reduce cost of checking init nullifier in all functions. // This function should be called as entrypoint to initialize the contract by minting itself funds. - #[aztec(private)] + #[private] fn deploy( artifact_hash: Field, private_functions_root: Field, @@ -70,13 +74,13 @@ contract FeeJuice { // We purposefully not set this function as an initializer so we do not bind // the contract to a specific L1 portal address, since the Fee Juice address // is a hardcoded constant in the rollup circuits. - #[aztec(public)] + #[public] fn set_portal(portal_address: EthAddress) { assert(storage.portal_address.read_public().is_zero()); storage.portal_address.initialize(portal_address); } - #[aztec(private)] + #[private] fn claim(to: AztecAddress, amount: Field, secret: Field) { let content_hash = get_bridge_gas_msg_hash(to, amount); let portal_address = storage.portal_address.read_private(); @@ -91,23 +95,23 @@ contract FeeJuice { FeeJuice::at(context.this_address())._increase_public_balance(to, amount).enqueue(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _increase_public_balance(to: AztecAddress, amount: Field) { let new_balance = storage.balances.at(to).read().add(U128::from_integer(amount)); storage.balances.at(to).write(new_balance); } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn check_balance(fee_limit: Field) { let fee_limit = U128::from_integer(fee_limit); assert(storage.balances.at(context.msg_sender()).read() >= fee_limit, "Balance too low"); } // utility function for testing - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn balance_of_public(owner: AztecAddress) -> pub Field { storage.balances.at(owner).read().to_field() } diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 7c301aa6b33..33c966b0c45 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -1,25 +1,29 @@ mod lib; +use dep::aztec::macros::aztec; + +#[aztec] contract FPC { use dep::aztec::{ protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}, - state_vars::SharedImmutable + state_vars::SharedImmutable, + macros::{storage::storage, functions::{private, public, initializer}} }; use dep::token::Token; use crate::lib::compute_rebate; - #[aztec(storage)] - struct Storage { - other_asset: SharedImmutable, + #[storage] + struct Storage { + other_asset: SharedImmutable, } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(other_asset: AztecAddress) { storage.other_asset.initialize(other_asset); } - #[aztec(private)] + #[private] fn fee_entrypoint_private(amount: Field, asset: AztecAddress, secret_hash: Field, nonce: Field) { assert(asset == storage.other_asset.read_private()); Token::at(asset).unshield(context.msg_sender(), context.this_address(), amount, nonce).call(&mut context); @@ -35,7 +39,7 @@ contract FPC { ); } - #[aztec(private)] + #[private] fn fee_entrypoint_public(amount: Field, asset: AztecAddress, nonce: Field) { FPC::at(context.this_address()).prepare_fee(context.msg_sender(), amount, asset, nonce).enqueue(&mut context); context.set_as_fee_payer(); @@ -50,24 +54,24 @@ contract FPC { ); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn prepare_fee(from: AztecAddress, amount: Field, asset: AztecAddress, nonce: Field) { // docs:start:public_call Token::at(asset).transfer_public(from, context.this_address(), amount, nonce).call(&mut context); // docs:end:public_call } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn pay_refund(refund_address: AztecAddress, amount: Field, asset: AztecAddress) { // Just do public refunds for the present let refund = compute_rebate(context, amount); Token::at(asset).transfer_public(context.this_address(), refund_address, refund, 0).call(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn pay_refund_with_shielded_rebate(amount: Field, asset: AztecAddress, secret_hash: Field) { let refund = compute_rebate(context, amount); Token::at(asset).shield(context.this_address(), refund, secret_hash, 0).call(&mut context); diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr index 6e125f3979a..df4ad22d792 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr @@ -1,15 +1,20 @@ // Contract that uses the autogenerated interface of the Test contract for calling its functions. // Used for testing calling into other contracts via autogenerated interfaces. +use dep::aztec::macros::aztec; + +#[aztec] contract ImportTest { use dep::aztec::prelude::AztecAddress; use dep::test::{Test, Test::DeepStruct, Test::DummyNote}; + use dep::aztec::macros::functions::{private, public}; + // Calls the test_code_gen on the Test contract at the target address // Used for testing calling a function with arguments of multiple types // See yarn-project/simulator/src/client/private_execution.ts // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts - #[aztec(private)] + #[private] fn main_contract(target: AztecAddress) -> Field { Test::at(target).test_code_gen( 1, @@ -33,7 +38,7 @@ contract ImportTest { // Calls the get_this_address on the Test contract at the target address // Used for testing calling a function with no arguments // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts - #[aztec(private)] + #[private] fn call_no_args(target: AztecAddress) -> AztecAddress { Test::at(target).get_this_address().call(&mut context) } @@ -41,7 +46,7 @@ contract ImportTest { // Calls the emit_nullifier_public on the Test contract at the target address // Used for testing calling a public function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts - #[aztec(private)] + #[private] fn call_public_fn(target: AztecAddress) { Test::at(target).emit_nullifier_public(1).enqueue(&mut context); } @@ -49,7 +54,7 @@ contract ImportTest { // Calls the emit_nullifier_public on the Test contract at the target address // Used for testing calling a public function from another public function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts - #[aztec(public)] + #[public] fn pub_call_public_fn(target: AztecAddress) { Test::at(target).emit_nullifier_public(1).call(&mut context); } diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 0d654b91c42..adcbd993abf 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -1,4 +1,7 @@ // A demonstration of inclusion and non-inclusion proofs. +use dep::aztec::macros::aztec; + +#[aztec] contract InclusionProofs { use dep::aztec::prelude::{AztecAddress, NoteGetterOptions, Map, PrivateSet, PublicMutable}; use dep::aztec::{ @@ -6,26 +9,26 @@ contract InclusionProofs { keys::getters::get_current_public_keys }; - use dep::aztec::{note::note_getter_options::NoteStatus}; + use dep::aztec::{note::note_getter_options::NoteStatus, macros::{storage::storage, functions::{private, public, initializer}}}; // docs:start:value_note_imports use dep::value_note::value_note::ValueNote; // docs:end:value_note_imports - #[aztec(storage)] - struct Storage { - private_values: Map>, - public_value: PublicMutable, - public_unused_value: PublicMutable, + #[storage] + struct Storage { + private_values: Map, Context>, + public_value: PublicMutable, + public_unused_value: PublicMutable, } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(public_value: Field) { storage.public_value.write(public_value); } // docs:start:create_note // Creates a value note owned by `owner`. - #[aztec(private)] + #[private] fn create_note(owner: AztecAddress, value: Field) { let owner_private_values = storage.private_values.at(owner); let owner_npk_m_hash = get_current_public_keys(&mut context, owner).npk_m.hash(); @@ -35,7 +38,7 @@ contract InclusionProofs { } // docs:end:create_note - #[aztec(private)] + #[private] fn test_note_inclusion( owner: AztecAddress, use_block_number: bool, @@ -65,7 +68,7 @@ contract InclusionProofs { // docs:end:prove_note_inclusion } - #[aztec(private)] + #[private] fn test_note_inclusion_fail_case( owner: AztecAddress, use_block_number: bool, @@ -85,7 +88,7 @@ contract InclusionProofs { } // Proves that the note was not yet nullified at block `block_number`. - #[aztec(private)] + #[private] fn test_note_not_nullified( owner: AztecAddress, use_block_number: bool, @@ -114,7 +117,7 @@ contract InclusionProofs { // docs:end:prove_note_not_nullified } - #[aztec(private)] + #[private] fn test_note_validity( owner: AztecAddress, use_block_number: bool, @@ -142,7 +145,7 @@ contract InclusionProofs { } // docs:start:nullify_note - #[aztec(private)] + #[private] fn nullify_note(owner: AztecAddress) { let private_values = storage.private_values.at(owner); let mut options = NoteGetterOptions::new(); @@ -155,7 +158,7 @@ contract InclusionProofs { // Proves nullifier existed at block `block_number`. // Note: I am not getting a nullifier of the note that was created in this contract in this function because it is // currently not possible to obtain a nullified note from PXE. - #[aztec(private)] + #[private] fn test_nullifier_inclusion( nullifier: Field, use_block_number: bool, @@ -171,18 +174,18 @@ contract InclusionProofs { // docs:end:prove_nullifier_inclusion } - #[aztec(public)] + #[public] fn push_nullifier_public(nullifier: Field) { context.push_nullifier(nullifier); } // Proves nullifier existed at latest block - #[aztec(public)] + #[public] fn test_nullifier_inclusion_from_public(nullifier: Field) { assert(context.nullifier_exists(nullifier, context.this_address())); } - #[aztec(private)] + #[private] fn test_storage_historical_read_unset_slot(block_number: u32 // The block at which we'll read the public storage value ) { let header = context.get_header_at(block_number); @@ -196,7 +199,7 @@ contract InclusionProofs { // docs:end:public_storage_historical_read } - #[aztec(private)] + #[private] fn test_storage_historical_read( expected: Field, use_block_number: bool, @@ -214,7 +217,7 @@ contract InclusionProofs { } // Proves that a contract was publicly deployed and/or initialized at block `block_number`. - #[aztec(private)] + #[private] fn test_contract_inclusion( contract_address: AztecAddress, block_number: u32, @@ -236,7 +239,7 @@ contract InclusionProofs { } // Proves that a contract was NOT publicly deployed and/or initialized at block `block_number`. - #[aztec(private)] + #[private] fn test_contract_non_inclusion( contract_address: AztecAddress, block_number: u32, diff --git a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr index d4ff344ed17..911aa1d5522 100644 --- a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr @@ -1,14 +1,18 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract KeyRegistry { use dep::authwit::auth::assert_current_call_valid_authwit_public; use dep::aztec::{ keys::{PublicKeys, stored_keys::StoredKeys, public_keys::NpkM}, - state_vars::{PublicMutable, Map}, protocol_types::address::{AztecAddress, PartialAddress} + state_vars::{PublicMutable, Map}, protocol_types::address::{AztecAddress, PartialAddress}, + macros::{storage::storage, functions::public} }; - #[aztec(storage)] - struct Storage { - current_keys: Map>, + #[storage] + struct Storage { + current_keys: Map, Context>, } impl Storage { @@ -34,7 +38,7 @@ contract KeyRegistry { storage.current_keys.at(account).read().public_keys } - #[aztec(public)] + #[public] fn register_initial_keys(account: AztecAddress, partial_address: PartialAddress, keys: PublicKeys) { let computed_address = AztecAddress::compute(keys.hash(), partial_address); assert(computed_address.eq(account), "Computed address does not match supplied address"); @@ -42,7 +46,7 @@ contract KeyRegistry { storage.current_keys.at(account).write(StoredKeys::new(keys)); } - #[aztec(public)] + #[public] fn rotate_npk_m(account: AztecAddress, new_npk_m: NpkM, nonce: Field) { if (!account.eq(context.msg_sender())) { assert_current_call_valid_authwit_public(&mut context, account); diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index 93d7052e876..b0e0469acee 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -10,6 +10,9 @@ mod helpers; // - Update accumulator should be for specific asset, just abusing only 1 asset atm. // - A way to repay all debt at once // - Liquidations +use dep::aztec::macros::aztec; + +#[aztec] contract Lending { use dep::aztec::prelude::{AztecAddress, Map, PublicMutable}; @@ -20,23 +23,25 @@ contract Lending { use dep::token::Token; use dep::price_feed::PriceFeed; + use dep::aztec::macros::{storage::storage, functions::{private, public, initializer, internal}}; + // Storage structure, containing all storage, and specifying what slots they use. - #[aztec(storage)] - struct Storage { - collateral_asset: PublicMutable, - stable_coin: PublicMutable, - assets: Map>, - collateral: Map>, - static_debt: Map>, // abusing keys very heavily + #[storage] + struct Storage { + collateral_asset: PublicMutable, + stable_coin: PublicMutable, + assets: Map, Context>, + collateral: Map, Context>, + static_debt: Map, Context>, // abusing keys very heavily } // Constructs the contract. - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor( ) {} - #[aztec(public)] + #[public] fn init( oracle: AztecAddress, loan_to_value: Field, @@ -63,7 +68,7 @@ contract Lending { } // Create a position. - #[aztec(public)] + #[public] fn update_accumulator() -> Asset { let asset_loc = storage.assets.at(0); let mut asset: Asset = asset_loc.read(); @@ -88,7 +93,7 @@ contract Lending { asset } - #[aztec(private)] + #[private] fn deposit_private( from: AztecAddress, amount: Field, @@ -108,7 +113,7 @@ contract Lending { // docs:end:enqueue_public } - #[aztec(public)] + #[public] fn deposit_public(amount: Field, nonce: Field, on_behalf_of: Field, collateral_asset: AztecAddress) { let _ = Token::at(collateral_asset).transfer_public(context.msg_sender(), context.this_address(), amount, nonce).call(&mut context); let _ = Lending::at(context.this_address())._deposit( @@ -118,8 +123,8 @@ contract Lending { ).call(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _deposit(owner: AztecAddress, amount: Field, collateral_asset: AztecAddress) { let _asset = Lending::at(context.this_address()).update_accumulator().call(&mut context); @@ -131,19 +136,19 @@ contract Lending { coll_loc.write(collateral + amount); } - #[aztec(private)] + #[private] fn withdraw_private(secret: Field, to: AztecAddress, amount: Field) { let on_behalf_of = compute_identifier(secret, 0, context.msg_sender().to_field()); Lending::at(context.this_address())._withdraw(AztecAddress::from_field(on_behalf_of), to, amount).enqueue(&mut context); } - #[aztec(public)] + #[public] fn withdraw_public(to: AztecAddress, amount: Field) { let _ = Lending::at(context.this_address())._withdraw(context.msg_sender(), to, amount).call(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _withdraw(owner: AztecAddress, recipient: AztecAddress, amount: Field) { let asset = Lending::at(context.this_address()).update_accumulator().call(&mut context); let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; @@ -179,19 +184,19 @@ contract Lending { let _ = Token::at(collateral_asset).transfer_public(context.this_address(), recipient, amount, 0).call(&mut context); } - #[aztec(private)] + #[private] fn borrow_private(secret: Field, to: AztecAddress, amount: Field) { let on_behalf_of = compute_identifier(secret, 0, context.msg_sender().to_field()); let _ = Lending::at(context.this_address())._borrow(AztecAddress::from_field(on_behalf_of), to, amount).enqueue(&mut context); } - #[aztec(public)] + #[public] fn borrow_public(to: AztecAddress, amount: Field) { let _ = Lending::at(context.this_address())._borrow(context.msg_sender(), to, amount).call(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _borrow(owner: AztecAddress, to: AztecAddress, amount: Field) { let asset = Lending::at(context.this_address()).update_accumulator().call(&mut context); let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; @@ -223,7 +228,7 @@ contract Lending { let _ = Token::at(stable_coin).mint_public(to, amount).call(&mut context); } - #[aztec(private)] + #[private] fn repay_private( from: AztecAddress, amount: Field, @@ -239,14 +244,14 @@ contract Lending { let _ = Lending::at(context.this_address())._repay(AztecAddress::from_field(on_behalf_of), amount, stable_coin).enqueue(&mut context); } - #[aztec(public)] + #[public] fn repay_public(amount: Field, nonce: Field, owner: AztecAddress, stable_coin: AztecAddress) { let _ = Token::at(stable_coin).burn_public(context.msg_sender(), amount, nonce).call(&mut context); let _ = Lending::at(context.this_address())._repay(owner, amount, stable_coin).call(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _repay(owner: AztecAddress, amount: Field, stable_coin: AztecAddress) { let asset = Lending::at(context.this_address()).update_accumulator().call(&mut context); @@ -264,14 +269,14 @@ contract Lending { storage.static_debt.at(owner).write(debt_returns.static_debt.to_integer()); } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_asset(asset_id: Field) -> pub Asset { storage.assets.at(asset_id).read() } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_position(owner: AztecAddress) -> pub Position { let collateral = storage.collateral.at(owner).read(); let static_debt = storage.static_debt.at(owner).read(); @@ -283,8 +288,8 @@ contract Lending { Position { collateral, static_debt, debt } } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_assets() -> pub [AztecAddress; 2] { [storage.collateral_asset.read(), storage.stable_coin.read()] } diff --git a/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/src/main.nr b/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/src/main.nr index f14d751d344..2351f61ecc0 100644 --- a/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/src/main.nr @@ -1,9 +1,13 @@ // An entrypoint contract that allows everything to go through. Only used for testing // Pair this with SignerlessWallet to perform multiple actions before any account contracts are deployed (and without authentication) +use dep::aztec::macros::aztec; + +#[aztec] contract MultiCallEntrypoint { use dep::authwit::entrypoint::app::AppPayload; + use dep::aztec::macros::functions::private; - #[aztec(private)] + #[private] fn entrypoint(app_payload: AppPayload) { app_payload.execute_calls(&mut context); } diff --git a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr index 7825f85a167..b5df22e44c2 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr @@ -1,17 +1,20 @@ // A contract used along with `Child` contract to test nested calls. +use dep::aztec::macros::aztec; + +#[aztec] contract Parent { use dep::aztec::prelude::{AztecAddress, FunctionSelector}; - use dep::aztec::context::gas::GasOpts; + use dep::aztec::{context::gas::GasOpts, macros::functions::{private, public}}; // Private function to call another private function in the target_contract using the provided selector - #[aztec(private)] + #[private] fn entry_point(target_contract: AztecAddress, target_selector: FunctionSelector) -> Field { // Call the target private function context.call_private_function(target_contract, target_selector, [0]).unpack_into() } // Public function to directly call another public function to the target_contract using the selector and value provided - #[aztec(public)] + #[public] fn pub_entry_point( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -26,7 +29,7 @@ contract Parent { } // Same as pub_entry_point, but calls the target contract twice, using the return value from the first invocation as the argument for the second. - #[aztec(public)] + #[public] fn pub_entry_point_twice( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -47,7 +50,7 @@ contract Parent { } // Private function to enqueue a call to the target_contract address using the selector and argument provided - #[aztec(private)] + #[private] fn enqueue_call_to_child( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -59,7 +62,7 @@ contract Parent { // Private function that enqueues two calls to a child contract: // - one through a nested call to enqueue_call_to_child with value 10, // - followed by one issued directly from this function with value 20. - #[aztec(private)] + #[private] fn enqueue_calls_to_child_with_nested_first( target_contract: AztecAddress, target_selector: FunctionSelector @@ -78,7 +81,7 @@ contract Parent { // Private function that enqueues two calls to a child contract: // - one issued directly from this function with value 20, // - followed by one through a nested call to enqueue_call_to_child with value 10. - #[aztec(private)] + #[private] fn enqueue_calls_to_child_with_nested_last( target_contract: AztecAddress, target_selector: FunctionSelector @@ -95,7 +98,7 @@ contract Parent { } // Private function to enqueue a call to the target_contract address using the selector and argument provided - #[aztec(private)] + #[private] fn enqueue_call_to_child_twice( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -108,7 +111,7 @@ contract Parent { } // Private function to enqueue a call to the pub_entry_point function of this same contract, passing the target arguments provided - #[aztec(private)] + #[private] fn enqueue_call_to_pub_entry_point( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -126,7 +129,7 @@ contract Parent { } // Private function to enqueue two calls to the pub_entry_point function of this same contract, passing the target arguments provided - #[aztec(private)] + #[private] fn enqueue_calls_to_pub_entry_point( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -150,7 +153,7 @@ contract Parent { ); } - #[aztec(private)] + #[private] fn private_static_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -160,7 +163,7 @@ contract Parent { context.static_call_private_function(target_contract, target_selector, args).unpack_into() } - #[aztec(private)] + #[private] fn private_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -171,7 +174,7 @@ contract Parent { } // Private function to set a static context and verify correct propagation for nested private calls - #[aztec(private)] + #[private] fn private_nested_static_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -191,7 +194,7 @@ contract Parent { } // Public function to directly call another public function to the target_contract using the selector and value provided - #[aztec(public)] + #[public] fn public_static_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -206,7 +209,7 @@ contract Parent { } // Public function to set a static context and verify correct propagation for nested public calls - #[aztec(public)] + #[public] fn public_nested_static_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -224,7 +227,7 @@ contract Parent { } // Private function to enqueue a static call to the pub_entry_point function of another contract, passing the target arguments provided - #[aztec(private)] + #[private] fn enqueue_static_nested_call_to_pub_function( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -241,7 +244,7 @@ contract Parent { } // Private function to enqueue a static call to the pub_entry_point function of another contract, passing the target arguments provided - #[aztec(private)] + #[private] fn enqueue_static_call_to_pub_function( target_contract: AztecAddress, target_selector: FunctionSelector, diff --git a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr index 021c304c75f..e1b87cf1715 100644 --- a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr @@ -2,6 +2,9 @@ // read (eventually even nullified) in the same TX. This contract // also contains some "bad" test cases to ensure that notes cannot // be read/nullified before their creation etc. +use dep::aztec::macros::aztec; + +#[aztec] contract PendingNoteHashes { // Libs use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteGetterOptions, PrivateContext, Map, PrivateSet}; @@ -10,10 +13,11 @@ contract PendingNoteHashes { use dep::aztec::encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note, encode_and_encrypt_note_with_keys}; use dep::aztec::note::note_emission::NoteEmission; use dep::aztec::keys::getters::get_current_public_keys; + use dep::aztec::macros::{storage::storage, functions::private}; - #[aztec(storage)] - struct Storage { - balances: Map>, + #[storage] + struct Storage, Context>, } // TODO(dbanks12): consolidate code into internal helper functions @@ -22,7 +26,7 @@ contract PendingNoteHashes { // Confirm can access pending note hashes by creating / inserting a note and then // getting / reading that note all in the same contract function // Realistic way to describe this test is "Mint note A, then burn note A in the same transaction" - #[aztec(private)] + #[private] fn test_insert_then_get_then_nullify_flat( amount: Field, owner: AztecAddress, @@ -49,7 +53,7 @@ contract PendingNoteHashes { } // Confirm cannot access note hashes inserted later in same function - #[aztec(private)] + #[private] fn test_bad_get_then_insert_flat(amount: Field, owner: AztecAddress) -> Field { let owner_balance = storage.balances.at(owner); @@ -69,11 +73,11 @@ contract PendingNoteHashes { } // Dummy nested/inner function (to pass a function which does nothing) - #[aztec(private)] + #[private] fn dummy(amount: Field, owner: AztecAddress, outgoing_viewer: AztecAddress) {} // Nested/inner function to create and insert a note - #[aztec(private)] + #[private] fn insert_note(amount: Field, owner: AztecAddress, outgoing_viewer: AztecAddress) { let owner_balance = storage.balances.at(owner); @@ -88,7 +92,7 @@ contract PendingNoteHashes { // Nested/inner function to create and insert a note // TESTING: inserts a static randomness value to test notes with // the same note hash are dealt with correctly - #[aztec(private)] + #[private] fn insert_note_static_randomness( amount: Field, owner: AztecAddress, @@ -107,7 +111,7 @@ contract PendingNoteHashes { // Nested/inner function to create and insert a note // then emit another note log for the same note - #[aztec(private)] + #[private] fn insert_note_extra_emit(amount: Field, owner: AztecAddress, outgoing_viewer: AztecAddress) { let mut owner_balance = storage.balances.at(owner); @@ -125,7 +129,7 @@ contract PendingNoteHashes { } // Nested/inner function to get a note and confirm it matches the expected value - #[aztec(private)] + #[private] fn get_then_nullify_note(expected_value: Field, owner: AztecAddress) -> Field { let owner_balance = storage.balances.at(owner); @@ -138,7 +142,7 @@ contract PendingNoteHashes { } // Nested/inner function to get a note and confirms that none is returned - #[aztec(private)] + #[private] fn get_note_zero_balance(owner: AztecAddress) { let owner_balance = storage.balances.at(owner); @@ -151,7 +155,7 @@ contract PendingNoteHashes { // Test pending note hashes with note insertion done in a nested call // and "read" / get of that pending note hash in another nested call // Realistic way to describe this test is "Mint note A, then burn note A in the same transaction" - #[aztec(private)] + #[private] fn test_insert_then_get_then_nullify_all_in_nested_calls( amount: Field, owner: AztecAddress, @@ -174,7 +178,7 @@ contract PendingNoteHashes { } // same test as above, but insert 2, get 2, nullify 2 - #[aztec(private)] + #[private] fn test_insert2_then_get2_then_nullify2_all_in_nested_calls( amount: Field, owner: AztecAddress, @@ -214,7 +218,7 @@ contract PendingNoteHashes { } // same test as above, but insert 2, get 1, nullify 1 - #[aztec(private)] + #[private] fn test_insert2_then_get2_then_nullify1_all_in_nested_calls( amount: Field, owner: AztecAddress, @@ -248,7 +252,7 @@ contract PendingNoteHashes { // insert 1 note, then get 2 notes (one pending, one persistent) and nullify both. // one nullifier will be squashed with the pending note, one will become persistent. // ONLY WORKS IF THERE IS A PERSISTENT NOTE TO GET - #[aztec(private)] + #[private] fn test_insert1_then_get2_then_nullify2_all_in_nested_calls( amount: Field, owner: AztecAddress, @@ -285,7 +289,7 @@ contract PendingNoteHashes { // nested call (later kernel iteration) should not be able to read the note hash despite // it being present at that stage in the kernel. // If we can somehow force the simulator to allow execution to succeed can ensure that this test fails in the kernel - // #[aztec(private)] + // #[private] //fn test_bad_get_in_nested_call_then_insert( // amount: Field, // owner: AztecAddress, @@ -293,7 +297,7 @@ contract PendingNoteHashes { //) { //} - #[aztec(private)] + #[private] fn test_recursively_create_notes( owner: AztecAddress, outgoing_viewer: AztecAddress, @@ -304,7 +308,7 @@ contract PendingNoteHashes { PendingNoteHashes::at(context.this_address()).recursively_destroy_and_create_notes(owner, outgoing_viewer, how_many_recursions).call(&mut context); } - #[aztec(private)] + #[private] fn recursively_destroy_and_create_notes( owner: AztecAddress, outgoing_viewer: AztecAddress, @@ -325,7 +329,7 @@ contract PendingNoteHashes { // TESTING: Forces the private context to accept a note log for a non-existent note // by using an existing note's counter via its header. This is used to check that // the pxe rejects the note log later. - #[aztec(private)] + #[private] fn test_emit_bad_note_log(owner: AztecAddress, outgoing_viewer: AztecAddress) { let owner_balance = storage.balances.at(owner); diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index 3c919579009..40485f87919 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -1,23 +1,28 @@ mod asset; +use dep::aztec::macros::aztec; + +#[aztec] contract PriceFeed { use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext, Map, PublicMutable}; use crate::asset::Asset; + use dep::aztec::macros::{storage::storage, functions::{public, view}}; + // Storage structure, containing all storage, and specifying what slots they use. - #[aztec(storage)] - struct Storage { - assets: Map>, + #[storage] + struct Storage { + assets: Map, Context>, } - #[aztec(public)] + #[public] fn set_price(asset_id: Field, price: Field) { let asset = storage.assets.at(asset_id); asset.write(Asset { price: U128::from_integer(price) }); } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_price(asset_id: Field) -> Asset { storage.assets.at(asset_id).read() } diff --git a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr index c8716b0f9d4..80234d2c04f 100644 --- a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr @@ -1,23 +1,26 @@ mod settings; +use dep::aztec::macros::aztec; + +#[aztec] contract PrivateFPC { - use dep::aztec::{protocol_types::{address::AztecAddress, hash::compute_siloed_nullifier}, state_vars::SharedImmutable}; + use dep::aztec::{protocol_types::{address::AztecAddress, hash::compute_siloed_nullifier}, state_vars::SharedImmutable, macros::{storage::storage, functions::{private, initializer, public}}}; use dep::token::Token; use crate::settings::Settings; - #[aztec(storage)] - struct Storage { - settings: SharedImmutable, + #[storage] + struct Storage { + settings: SharedImmutable, } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(other_asset: AztecAddress, admin: AztecAddress) { let settings = Settings { other_asset, admin }; storage.settings.initialize(settings); } - #[aztec(private)] + #[private] fn fund_transaction_privately(amount: Field, asset: AztecAddress, user_randomness: Field) { // TODO: Once SharedImmutable performs only 1 merkle proof here, we'll save ~4k gates let settings = storage.settings.read_private(); diff --git a/noir-projects/noir-contracts/contracts/router_contract/src/main.nr b/noir-projects/noir-contracts/contracts/router_contract/src/main.nr index 1ea96c506ae..1bfe4f28242 100644 --- a/noir-projects/noir-contracts/contracts/router_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/router_contract/src/main.nr @@ -6,9 +6,12 @@ use dep::aztec::macros::aztec; /// The purpose of this contract is to perform a check in public without revealing what contract enqued the public /// call. This is achieved by having a private function on this contract that enques the public call and hence /// the `msg_sender` in the public call is the address of this contract. +#[aztec] +use dep::aztec::macros::aztec; + #[aztec] contract Router { - use aztec::{macros::functions::{private, public}, utils::comparison::compare}; + use aztec::{macros::functions::{private, public, view, internal}, utils::comparison::compare}; // docs:start:check_timestamp /// Asserts that the current timestamp in the enqueued public call satisfies the `operation` with respect diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 882423aa75a..9b65405cb8e 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -2,6 +2,9 @@ mod public_key_note; // Account contract that uses Schnorr signatures for authentication. // The signing key is stored in an immutable private note and should be different from the encryption/nullifying key. +use dep::aztec::macros::aztec; + +#[aztec] contract SchnorrAccount { use dep::std; @@ -13,17 +16,18 @@ contract SchnorrAccount { }; use dep::aztec::{hash::compute_siloed_nullifier, keys::getters::get_current_public_keys}; use dep::aztec::oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness; + use dep::aztec::macros::{storage::storage, functions::{private, initializer, view, noinitcheck}}; use crate::public_key_note::PublicKeyNote; - #[aztec(storage)] - struct Storage { - signing_public_key: PrivateImmutable, + #[storage] + struct Storage { + signing_public_key: PrivateImmutable, } // Constructs the contract - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor(signing_pub_key_x: Field, signing_pub_key_y: Field) { let this = context.this_address(); let this_keys = get_current_public_keys(&mut context, this); @@ -36,16 +40,16 @@ contract SchnorrAccount { } // Note: If you globally change the entrypoint signature don't forget to update account_entrypoint.ts file - #[aztec(private)] - #[aztec(noinitcheck)] + #[private] + #[noinitcheck] fn entrypoint(app_payload: AppPayload, fee_payload: FeePayload, cancellable: bool) { let actions = AccountActions::init(&mut context, is_valid_impl); actions.entrypoint(app_payload, fee_payload, cancellable); } - #[aztec(private)] - #[aztec(noinitcheck)] - #[aztec(view)] + #[private] + #[noinitcheck] + #[view] fn verify_private_authwit(inner_hash: Field) -> Field { let actions = AccountActions::init(&mut context, is_valid_impl); actions.verify_private_authwit(inner_hash) diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 948367a413a..d070b413b6b 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -1,16 +1,12 @@ -use dep::aztec::prelude::{NoteHeader, NoteInterface, PrivateContext}; +use dep::aztec::prelude::{NoteHeader, NullifiableNote, PrivateContext}; use dep::aztec::{ note::utils::compute_note_hash_for_nullify, keys::getters::get_nsk_app, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; -global PUBLIC_KEY_NOTE_LEN: Field = 3; -// PUBLIC_KEY_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global PUBLIC_KEY_NOTE_BYTES_LEN: Field = 3 * 32 + 64; - // Stores a public key composed of two fields // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? -#[aztec(note)] +#[note] struct PublicKeyNote { x: Field, y: Field, @@ -18,7 +14,7 @@ struct PublicKeyNote { npk_m_hash: Field, } -impl NoteInterface for PublicKeyNote { +impl NullifiableNote for PublicKeyNote { fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); poseidon2_hash_with_separator( diff --git a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index b6bca50d603..cfe370fba5f 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -1,5 +1,8 @@ // docs:start:contract // Account contract that uses Schnorr signatures for authentication using a hardcoded public key. +use dep::aztec::macros::aztec; + +#[aztec] contract SchnorrHardcodedAccount { use dep::aztec::prelude::PrivateContext; use dep::authwit::{ @@ -7,18 +10,20 @@ contract SchnorrHardcodedAccount { auth_witness::get_auth_witness }; + use dep::aztec::macros::{functions::{private, initializer, view}}; + global public_key_x: Field = 0x16b93f4afae55cab8507baeb8e7ab4de80f5ab1e9e1f5149bf8cd0d375451d90; global public_key_y: Field = 0x208d44b36eb6e73b254921134d002da1a90b41131024e3b1d721259182106205; // Note: If you globally change the entrypoint signature don't forget to update account_entrypoint.ts - #[aztec(private)] + #[private] fn entrypoint(app_payload: AppPayload, fee_payload: FeePayload, cancellable: bool) { let actions = AccountActions::init(&mut context, is_valid_impl); actions.entrypoint(app_payload, fee_payload, cancellable); } - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn verify_private_authwit(inner_hash: Field) -> Field { let actions = AccountActions::init(&mut context, is_valid_impl); actions.verify_private_authwit(inner_hash) diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr index ec4c9037b63..b9f00815f63 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr @@ -1,6 +1,9 @@ mod util; mod auth_oracle; +use dep::aztec::macros::aztec; + +#[aztec] contract SchnorrSingleKeyAccount { use dep::aztec::prelude::PrivateContext; @@ -8,15 +11,17 @@ contract SchnorrSingleKeyAccount { use crate::{util::recover_address, auth_oracle::get_auth_witness}; + use dep::aztec::macros::{functions::{private, view}}; + // Note: If you globally change the entrypoint signature don't forget to update account_entrypoint.ts - #[aztec(private)] + #[private] fn entrypoint(app_payload: AppPayload, fee_payload: FeePayload, cancellable: bool) { let actions = AccountActions::init(&mut context, is_valid_impl); actions.entrypoint(app_payload, fee_payload, cancellable); } - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn verify_private_authwit(inner_hash: Field) -> Field { let actions = AccountActions::init(&mut context, is_valid_impl); actions.verify_private_authwit(inner_hash) diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index ba8b82fee3e..2a99ac707c7 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -1,23 +1,26 @@ // A contract used for testing a random hodgepodge of small features from simulator and end-to-end tests. +use dep::aztec::macros::aztec; + +#[aztec] contract StatefulTest { use dep::aztec::prelude::{Map, PublicMutable, PrivateSet, AztecAddress, FunctionSelector}; use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::ValueNote}; - use dep::aztec::{initializer::assert_is_initialized_private}; + use dep::aztec::{initializer::assert_is_initialized_private, macros::{storage::storage, functions::{private, public, initializer, noinitcheck, view}}; - #[aztec(storage)] - struct Storage { - notes: Map>, - public_values: Map>, + #[storage] + struct Storage { + notes: Map, Context>, + public_values: Map, Context>, } - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn constructor(owner: AztecAddress, outgoing_viewer: AztecAddress, value: Field) { StatefulTest::at(context.this_address()).create_note_no_init_check(owner, outgoing_viewer, value).call(&mut context); } - #[aztec(private)] - #[aztec(initializer)] + #[private] + #[initializer] fn wrong_constructor() { let selector = FunctionSelector::from_signature("not_exists(Field)"); let _res = context.call_public_function(context.this_address(), selector, [42]); @@ -25,13 +28,13 @@ contract StatefulTest { // Having _ignored_arg here as it makes the params the same as for the private constructor which makes // contract_class_registration tests way less cluttered. This is a test contract. Don't judge me. - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn public_constructor(owner: AztecAddress, _ignored_arg: AztecAddress, value: Field) { StatefulTest::at(context.this_address()).increment_public_value_no_init_check(owner, value).call(&mut context); } - #[aztec(private)] + #[private] fn create_note(owner: AztecAddress, outgoing_viewer: AztecAddress, value: Field) { if (value != 0) { let loc = storage.notes.at(owner); @@ -39,8 +42,8 @@ contract StatefulTest { } } - #[aztec(private)] - #[aztec(noinitcheck)] + #[private] + #[noinitcheck] fn create_note_no_init_check(owner: AztecAddress, outgoing_viewer: AztecAddress, value: Field) { if (value != 0) { let loc = storage.notes.at(owner); @@ -48,7 +51,7 @@ contract StatefulTest { } } - #[aztec(private)] + #[private] fn destroy_and_create(recipient: AztecAddress, amount: Field) { assert_is_initialized_private(&mut context); let sender = context.msg_sender(); @@ -60,8 +63,8 @@ contract StatefulTest { increment(recipient_notes, amount, recipient, context.msg_sender()); } - #[aztec(private)] - #[aztec(noinitcheck)] + #[private] + #[noinitcheck] fn destroy_and_create_no_init_check(recipient: AztecAddress, amount: Field) { let sender = context.msg_sender(); @@ -72,14 +75,14 @@ contract StatefulTest { increment(recipient_notes, amount, recipient, context.msg_sender()); } - #[aztec(public)] + #[public] fn increment_public_value(owner: AztecAddress, value: Field) { let loc = storage.public_values.at(owner); loc.write(loc.read() + value); } - #[aztec(public)] - #[aztec(noinitcheck)] + #[public] + #[noinitcheck] fn increment_public_value_no_init_check(owner: AztecAddress, value: Field) { let loc = storage.public_values.at(owner); loc.write(loc.read() + value); @@ -94,9 +97,9 @@ contract StatefulTest { // docs:end:get_balance } - #[aztec(public)] - #[aztec(noinitcheck)] - #[aztec(view)] + #[public] + #[noinitcheck] + #[view] fn get_public_value(owner: AztecAddress) -> pub Field { storage.public_values.at(owner).read() } diff --git a/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr index 828f077d95d..00ab4557fd2 100644 --- a/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr @@ -1,4 +1,7 @@ // A contract used along with `StaticParent` contract to test static calls. +use dep::aztec::macros::aztec; + +#[aztec] contract StaticChild { use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize}; @@ -6,19 +9,20 @@ contract StaticChild { context::{PublicContext, gas::GasOpts}, protocol_types::{abis::{call_context::CallContext}}, note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, encrypted_logs::encrypted_note_emission::encode_and_encrypt_note, - keys::getters::get_current_public_keys, utils::comparison::Comparator + keys::getters::get_current_public_keys, utils::comparison::Comparator, + macros::{storage::storage, functions::{private, public, view}} }; use dep::value_note::value_note::ValueNote; - #[aztec(storage)] - struct Storage { - current_value: PublicMutable, - a_private_value: PrivateSet, + #[storage] + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, } // Returns base_value + chain_id + version + block_number + timestamp statically - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn pub_get_value(base_value: Field) -> Field { let return_value = base_value + context.chain_id() @@ -30,7 +34,7 @@ contract StaticChild { } // Sets `current_value` to `new_value` - #[aztec(public)] + #[public] fn pub_set_value(new_value: Field) -> Field { storage.current_value.write(new_value); context.emit_unencrypted_log(new_value); @@ -38,8 +42,8 @@ contract StaticChild { } // View function that attempts to modify state. Should always fail regardless how it's called. - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn private_illegal_set_value(new_value: Field, owner: AztecAddress) -> Field { let owner_npk_m_hash = get_current_public_keys(&mut context, owner).npk_m.hash(); let mut note = ValueNote::new(new_value, owner_npk_m_hash); @@ -48,7 +52,7 @@ contract StaticChild { } // Modify a note - #[aztec(private)] + #[private] fn private_set_value( new_value: Field, owner: AztecAddress, @@ -61,8 +65,8 @@ contract StaticChild { } // Retrieve note value statically - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn private_get_value(amount: Field, owner: AztecAddress) -> Field { let owner_npk_m_hash = get_current_public_keys(&mut context, owner).npk_m.hash(); let mut options = NoteGetterOptions::new(); @@ -76,7 +80,7 @@ contract StaticChild { } // Increments `current_value` by `new_value` - #[aztec(public)] + #[public] fn pub_inc_value(new_value: Field) -> Field { let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); @@ -85,8 +89,8 @@ contract StaticChild { } // View function that attempts to modify state. Should always fail regardless how it's called. - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn pub_illegal_inc_value(new_value: Field) -> Field { let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); diff --git a/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr index 1b30deb1b8f..d363d073fb0 100644 --- a/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr @@ -1,12 +1,15 @@ // A contract used along with `StaticChild` contract to test static calls. +use dep::aztec::macros::aztec; + +#[aztec] contract StaticParent { use dep::aztec::prelude::{AztecAddress, FunctionSelector}; - use dep::aztec::context::gas::GasOpts; + use dep::aztec::{context::gas::GasOpts, macros::functions::{private, public, view}}; use dep::static_child_contract::StaticChild; // Public function to directly call another public function to the target_contract using the selector and value provided - #[aztec(public)] + #[public] fn public_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -21,7 +24,7 @@ contract StaticParent { } // Private function to directly call another private function to the target_contract using the selector and args provided - #[aztec(private)] + #[private] fn private_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -31,7 +34,7 @@ contract StaticParent { } // Just like function above but with 3 args. - #[aztec(private)] + #[private] fn private_call_3_args( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -41,7 +44,7 @@ contract StaticParent { } // Private function to enqueue a call to a public function of another contract, passing the target arguments provided - #[aztec(private)] + #[private] fn enqueue_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -50,7 +53,7 @@ contract StaticParent { context.call_public_function(target_contract, target_selector, args); } - #[aztec(private)] + #[private] fn private_static_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -60,7 +63,7 @@ contract StaticParent { } // Private function to statically call another private function to the target_contract using the selector and values provided - #[aztec(private)] + #[private] fn private_static_call_3_args( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -70,7 +73,7 @@ contract StaticParent { } // Same as above but using a specific function from the interface - #[aztec(private)] + #[private] fn private_get_value_from_child( target_contract: AztecAddress, value: Field, @@ -80,7 +83,7 @@ contract StaticParent { } // Private function to set a static context and verify correct propagation for nested private calls - #[aztec(private)] + #[private] fn private_nested_static_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -90,7 +93,7 @@ contract StaticParent { } // Just like function above but with 3 args. - #[aztec(private)] + #[private] fn private_nested_static_call_3_args( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -100,7 +103,7 @@ contract StaticParent { } // Public function to statically call another public function to the target_contract using the selector and value provided - #[aztec(public)] + #[public] fn public_static_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -115,13 +118,13 @@ contract StaticParent { } // Same as above but using a specific function from the interface - #[aztec(public)] + #[public] fn public_get_value_from_child(target_contract: AztecAddress, value: Field) -> Field { StaticChild::at(target_contract).pub_get_value(value).view(&mut context) } // Public function to set a static context and verify correct propagation for nested public calls - #[aztec(public)] + #[public] fn public_nested_static_call( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -132,7 +135,7 @@ contract StaticParent { } // Private function to enqueue a static call to a public function of another contract, passing the target arguments provided - #[aztec(private)] + #[private] fn enqueue_static_call_to_pub_function( target_contract: AztecAddress, target_selector: FunctionSelector, @@ -142,13 +145,13 @@ contract StaticParent { } // Same as above but using a specific function from the interface - #[aztec(private)] + #[private] fn enqueue_public_get_value_from_child(target_contract: AztecAddress, value: Field) { StaticChild::at(target_contract).pub_get_value(value).enqueue_view(&mut context); } // Private function to set a static context and verify correct propagation of nested enqueuing of public calls - #[aztec(private)] + #[private] fn enqueue_static_nested_call_to_pub_function( target_contract: AztecAddress, target_selector: FunctionSelector, diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index bf982ad9048..41456a8b39e 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -1,6 +1,9 @@ mod test_note; // A contract used for testing a random hodgepodge of small features from simulator and end-to-end tests. +use dep::aztec::macros::aztec; + +#[aztec] contract Test { use dep::aztec::prelude::{ @@ -42,7 +45,7 @@ contract Test { use crate::test_note::TestNote; - #[aztec(event)] + #[event] struct ExampleEvent { value0: Field, value1: Field, @@ -51,18 +54,18 @@ contract Test { value4: Field, } - #[aztec(storage)] - struct Storage { - example_constant: PrivateImmutable, - example_set: PrivateSet, + #[storage] + struct Storage, + example_set: PrivateSet, } - #[aztec(private)] + #[private] fn get_ovsk_app(ovpk_m_hash: Field) -> Field { context.request_ovsk_app(ovpk_m_hash) } - #[aztec(private)] + #[private] fn get_master_incoming_viewing_public_key(address: AztecAddress) -> [Field; 2] { let ivpk_m = get_current_public_keys(&mut context, address).ivpk_m; @@ -70,12 +73,12 @@ contract Test { } // Get the address of this contract (taken from the input context) - #[aztec(private)] + #[private] fn get_this_address() -> AztecAddress { context.this_address() } - #[aztec(private)] + #[private] fn set_tx_max_block_number(max_block_number: u32, enqueue_public_call: bool) { context.set_tx_max_block_number(max_block_number); @@ -84,11 +87,11 @@ contract Test { } } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn dummy_public_call() {} - #[aztec(private)] + #[private] fn call_create_note( value: Field, owner: AztecAddress, @@ -105,7 +108,7 @@ contract Test { create_note(&mut context, storage_slot, &mut note).emit(encode_and_encrypt_note(&mut context, outgoing_viewer, owner)); } - #[aztec(private)] + #[private] fn call_get_notes(storage_slot: Field, active_or_nullified: bool) -> Field { assert( storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" @@ -121,7 +124,7 @@ contract Test { notes.get(0).value } - #[aztec(private)] + #[private] fn call_get_notes_many(storage_slot: Field, active_or_nullified: bool) -> [Field; 2] { assert( storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" @@ -167,7 +170,7 @@ contract Test { [notes.get(0).value, notes.get(1).value] } - #[aztec(private)] + #[private] fn call_destroy_note(storage_slot: Field) { assert( storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" @@ -182,7 +185,7 @@ contract Test { destroy_note_unsafe(&mut context, note, note_hash); } - #[aztec(private)] + #[private] fn test_code_gen( a_field: Field, a_bool: bool, @@ -209,7 +212,7 @@ contract Test { args.hash() } - #[aztec(private)] + #[private] fn test_setting_teardown() { context.set_public_teardown_function( context.this_address(), @@ -220,13 +223,13 @@ contract Test { ); } - #[aztec(private)] + #[private] fn test_setting_fee_payer() { context.set_as_fee_payer(); } // Purely exists for testing - #[aztec(public)] + #[public] fn create_l2_to_l1_message_public(amount: Field, secret_hash: Field, portal_address: EthAddress) { // Create a commitment to the amount let note = DummyNote::new(amount, secret_hash); @@ -235,32 +238,32 @@ contract Test { context.message_portal(portal_address, note.get_commitment()); } - #[aztec(public)] + #[public] fn create_l2_to_l1_message_arbitrary_recipient_public(content: Field, recipient: EthAddress) { // Public oracle call to emit new commitment. context.message_portal(recipient, content); } - #[aztec(private)] + #[private] fn create_l2_to_l1_message_arbitrary_recipient_private(content: Field, recipient: EthAddress) { // Public oracle call to emit new commitment. context.message_portal(recipient, content); } // Purely exists for testing - #[aztec(public)] + #[public] fn emit_nullifier_public(nullifier: Field) { context.push_nullifier(nullifier); } // Forcefully emits a nullifier (for testing purposes) - #[aztec(private)] + #[private] fn emit_nullifier(nullifier: Field) { context.push_nullifier(nullifier); } // For testing non-note encrypted logs - #[aztec(private)] + #[private] fn emit_array_as_encrypted_log( fields: [Field; 5], owner: AztecAddress, @@ -303,7 +306,7 @@ contract Test { } } - #[aztec(private)] + #[private] fn emit_encrypted_logs_nested(value: Field, owner: AztecAddress, outgoing_viewer: AztecAddress) { let mut storage_slot = storage.example_constant.get_storage_slot() + 1; Test::at(context.this_address()).call_create_note(value, owner, outgoing_viewer, storage_slot).call(&mut context); @@ -318,14 +321,14 @@ contract Test { } // docs:start:is-time-equal - #[aztec(public)] + #[public] fn is_time_equal(time: u64) -> u64 { assert(context.timestamp() == time); time } // docs:end:is-time-equal - #[aztec(public)] + #[public] fn emit_unencrypted(value: Field) { // docs:start:emit_unencrypted context.emit_unencrypted_log(/*message=*/ value); @@ -334,7 +337,7 @@ contract Test { // docs:end:emit_unencrypted } - #[aztec(public)] + #[public] fn consume_mint_public_message( to: AztecAddress, amount: Field, @@ -347,7 +350,7 @@ contract Test { context.consume_l1_to_l2_message(content_hash, secret, portal_address, message_leaf_index); } - #[aztec(private)] + #[private] fn consume_mint_private_message( secret_hash_for_redeeming_minted_notes: Field, amount: Field, @@ -363,7 +366,7 @@ contract Test { ); } - #[aztec(public)] + #[public] fn consume_message_from_arbitrary_sender_public( content: Field, secret: Field, @@ -374,7 +377,7 @@ contract Test { context.consume_l1_to_l2_message(content, secret, sender, message_leaf_index); } - #[aztec(private)] + #[private] fn consume_message_from_arbitrary_sender_private( content: Field, secret: Field, @@ -384,35 +387,35 @@ contract Test { context.consume_l1_to_l2_message(content, secret, sender); } - #[aztec(private)] + #[private] fn set_constant(value: Field) { let mut note = TestNote::new(value); storage.example_constant.initialize(&mut note).discard(); } - #[aztec(private)] + #[private] fn assert_private_global_vars(chain_id: Field, version: Field) { assert(context.chain_id() == chain_id, "Invalid chain id"); assert(context.version() == version, "Invalid version"); } - #[aztec(private)] + #[private] fn encrypt(input: [u8; 64], iv: [u8; 16], key: [u8; 16]) -> [u8; 80] { aes128_encrypt(input, iv, key) } - #[aztec(private)] + #[private] fn encrypt_with_padding(input: [u8; 65], iv: [u8; 16], key: [u8; 16]) -> [u8; 80] { aes128_encrypt(input, iv, key) } - #[aztec(private)] + #[private] fn compute_note_header_ciphertext(secret: Scalar, ivpk: IvpkM) -> [u8; 48] { EncryptedLogHeader::new(context.this_address()).compute_ciphertext(secret, ivpk) } // 64 bytes + 32 * #fields + 16 = 112 bytes - #[aztec(private)] + #[private] fn compute_incoming_log_body_ciphertext( secret: Scalar, ivpk: IvpkM, @@ -423,7 +426,7 @@ contract Test { EncryptedLogIncomingBody::from_note(note, storage_slot).compute_ciphertext(secret, ivpk).as_array() } - #[aztec(private)] + #[private] fn compute_outgoing_log_body_ciphertext( eph_sk: Scalar, recipient: AztecAddress, @@ -434,7 +437,7 @@ contract Test { EncryptedLogOutgoingBody::new(eph_sk, recipient, recipient_ivpk).compute_ciphertext(ovsk_app, eph_pk) } - #[aztec(public)] + #[public] fn assert_public_global_vars( chain_id: Field, version: Field, @@ -451,23 +454,23 @@ contract Test { assert(context.fee_per_l2_gas() == fee_per_l2_gas, "Invalid fee per l2 gas"); } - #[aztec(private)] + #[private] fn assert_header_private(header_hash: Field) { assert(context.historical_header.hash() == header_hash, "Invalid header hash"); } // TODO(4840): add AVM opcodes for getting header (members) - //#[aztec(public)] + //#[public] //fn assert_header_public(header_hash: Field) { // assert(context.historical_header.hash() == header_hash, "Invalid header hash"); //} - #[aztec(private)] + #[private] fn deploy_contract(target: AztecAddress) { aztec_deploy_contract(&mut context, target); } - #[aztec(private)] + #[private] // Adapted from TokenContract#redeem_shield but without an initcheck so it can be run in simulator/src/client/private_execution.test.ts fn consume_note_from_secret(secret: Field) { let notes_set = storage.example_set; @@ -484,7 +487,7 @@ contract Test { } // This function is used in the e2e_state_vars to test the SharedMutablePrivateGetter in isolation - #[aztec(private)] + #[private] fn test_shared_mutable_private_getter( contract_address_to_read: AztecAddress, storage_slot_of_shared_mutable: Field @@ -501,7 +504,7 @@ contract Test { ret.to_field() } - #[aztec(private)] + #[private] fn test_nullifier_key_freshness(address: AztecAddress, public_nullifying_key: Point) { assert_eq(get_current_public_keys(&mut context, address).npk_m.inner, public_nullifying_key); } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr index a2bc9c31bff..37f37648f5f 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr @@ -1,19 +1,15 @@ -use dep::aztec::{note::{note_header::NoteHeader, note_interface::NoteInterface}, context::PrivateContext}; - -global TEST_NOTE_LEN: Field = 1; -// TEST_NOTE_LENGTH * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global TEST_NOTE_BYTES_LENGTH: Field = 1 * 32 + 64; +use dep::aztec::{note::{note_header::NoteHeader, note_interface::NullifiableNote}, context::PrivateContext}; // A note which stores a field and is expected to be passed around using the `addNote` function. -// WARNING: This Note is not private as it does not contain randomness and hence it can be easy to perform +// WARNING: This Note is not private as it does not contain randomness and hence it can be easy to perform // serialized_note attack on it. This note has been developed purely for testing purposes so that it can easily be // manually added to PXE. Do not use for real applications. -#[aztec(note)] +#[note] struct TestNote { value: Field, } -impl NoteInterface for TestNote { +impl NullifiableNote for TestNote { fn compute_nullifier(self, _context: &mut PrivateContext, _note_hash_for_nullify: Field) -> Field { // This note is expected to be shared between users and for this reason can't be nullified using a secret. diff --git a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr index 55384dd4b57..9dba8913cca 100644 --- a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr @@ -1,3 +1,6 @@ +use dep::aztec::macros::aztec; + +#[aztec] contract TestLog { use dep::aztec::prelude::PrivateSet; use dep::aztec::protocol_types::{scalar::Scalar, address::AztecAddress}; @@ -6,28 +9,29 @@ contract TestLog { use dep::aztec::encrypted_logs::incoming_body::EncryptedLogIncomingBody; use dep::aztec::encrypted_logs::encrypted_event_emission::encode_and_encrypt_event_with_randomness; use dep::aztec::unencrypted_logs::unencrypted_event_emission::encode_event; + use dep::aztec::macros::{storage::storage, events::event, functions::{private, public}}; - #[aztec(event)] + #[event] struct ExampleEvent0 { value0: Field, value1: Field, } - #[aztec(event)] + #[event] struct ExampleEvent1 { value2: AztecAddress, value3: u8, } - #[aztec(storage)] - struct Storage { - example_set: PrivateSet, + #[storage] + struct Storage { + example_set: PrivateSet, } // EXAMPLE_EVENT_0_BYTES_LEN + 16 global EXAMPLE_EVENT_0_CIPHERTEXT_BYTES_LEN = 144; - #[aztec(private)] + #[private] fn compute_incoming_log_body_ciphertext( secret: Scalar, ivpk: IvpkM, @@ -41,7 +45,7 @@ contract TestLog { ).compute_ciphertext(secret, ivpk).as_array() } - #[aztec(private)] + #[private] fn emit_encrypted_events(other: AztecAddress, randomness: [Field; 2], preimages: [Field; 4]) { let event0 = ExampleEvent0 { value0: preimages[0], value1: preimages[1] }; @@ -79,7 +83,7 @@ contract TestLog { ); } - #[aztec(public)] + #[public] fn emit_unencrypted_events(preimages: [Field; 4]) { let event0 = ExampleEvent0 { value0: preimages[0], value1: preimages[1] }; diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 5ef31e0529d..58d421b2cce 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -8,12 +8,16 @@ mod types; // Including a nonce in the message hash ensures that the message can only be used once. // The SharedMutables are used for access control related to minters and blacklist. +use dep::aztec::macros::aztec; + +#[aztec] contract TokenBlacklist { // Libs use dep::aztec::{ hash::compute_secret_hash, prelude::{AztecAddress, Map, NoteGetterOptions, PrivateSet, PublicMutable, SharedMutable}, - encrypted_logs::encrypted_note_emission::encode_and_encrypt_note, utils::comparison::Comparator + encrypted_logs::encrypted_note_emission::encode_and_encrypt_note, utils::comparison::Comparator, + macros::{storage::storage, functions::{private, public, initializer, view, internal}} }; use dep::authwit::{auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public}}; @@ -23,7 +27,7 @@ contract TokenBlacklist { // Changing an address' roles has a certain block delay before it goes into effect. global CHANGE_ROLES_DELAY_BLOCKS = 2; - #[aztec(storage)] + #[storage] struct Storage { balances: BalancesMap, total_supply: PublicMutable, @@ -33,32 +37,32 @@ contract TokenBlacklist { } // docs:start:constructor - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(admin: AztecAddress) { let admin_roles = UserFlags { is_admin: true, is_minter: false, is_blacklisted: false }; storage.roles.at(admin).schedule_value_change(admin_roles); } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn total_supply() -> pub Field { storage.total_supply.read().to_field() } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn balance_of_public(owner: AztecAddress) -> pub Field { storage.public_balances.at(owner).read().to_field() } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_roles(user: AztecAddress) -> UserFlags { storage.roles.at(user).get_current_value_in_public() } - #[aztec(public)] + #[public] fn update_roles(user: AztecAddress, roles: UserFlags) { let caller_roles = storage.roles.at(context.msg_sender()).get_current_value_in_public(); assert(caller_roles.is_admin, "caller is not admin"); @@ -66,7 +70,7 @@ contract TokenBlacklist { storage.roles.at(user).schedule_value_change(roles); } - #[aztec(public)] + #[public] fn mint_public(to: AztecAddress, amount: Field) { let to_roles = storage.roles.at(to).get_current_value_in_public(); assert(!to_roles.is_blacklisted, "Blacklisted: Recipient"); @@ -82,7 +86,7 @@ contract TokenBlacklist { storage.total_supply.write(supply); } - #[aztec(public)] + #[public] fn mint_private(amount: Field, secret_hash: Field) { let caller_roles = storage.roles.at(context.msg_sender()).get_current_value_in_public(); assert(caller_roles.is_minter, "caller is not minter"); @@ -95,7 +99,7 @@ contract TokenBlacklist { pending_shields.insert_from_public(&mut note); } - #[aztec(public)] + #[public] fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) { let from_roles = storage.roles.at(from).get_current_value_in_public(); assert(!from_roles.is_blacklisted, "Blacklisted: Sender"); @@ -117,7 +121,7 @@ contract TokenBlacklist { pending_shields.insert_from_public(&mut note); } - #[aztec(public)] + #[public] fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { let from_roles = storage.roles.at(from).get_current_value_in_public(); assert(!from_roles.is_blacklisted, "Blacklisted: Sender"); @@ -138,7 +142,7 @@ contract TokenBlacklist { storage.public_balances.at(to).write(to_balance); } - #[aztec(public)] + #[public] fn burn_public(from: AztecAddress, amount: Field, nonce: Field) { let from_roles = storage.roles.at(from).get_current_value_in_public(); assert(!from_roles.is_blacklisted, "Blacklisted: Sender"); @@ -157,7 +161,7 @@ contract TokenBlacklist { storage.total_supply.write(new_supply); } - #[aztec(private)] + #[private] fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) { let to_roles = storage.roles.at(to).get_current_value_in_private(); assert(!to_roles.is_blacklisted, "Blacklisted: Recipient"); @@ -181,7 +185,7 @@ contract TokenBlacklist { storage.balances.add(to, U128::from_integer(amount)).emit(encode_and_encrypt_note(&mut context, caller, to)); } - #[aztec(private)] + #[private] fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { let from_roles = storage.roles.at(from).get_current_value_in_private(); assert(!from_roles.is_blacklisted, "Blacklisted: Sender"); @@ -200,7 +204,7 @@ contract TokenBlacklist { } // docs:start:transfer_private - #[aztec(private)] + #[private] fn transfer(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) { let from_roles = storage.roles.at(from).get_current_value_in_private(); assert(!from_roles.is_blacklisted, "Blacklisted: Sender"); @@ -218,7 +222,7 @@ contract TokenBlacklist { storage.balances.add(to, amount).emit(encode_and_encrypt_note(&mut context, from, to)); } - #[aztec(private)] + #[private] fn burn(from: AztecAddress, amount: Field, nonce: Field) { let from_roles = storage.roles.at(from).get_current_value_in_private(); assert(!from_roles.is_blacklisted, "Blacklisted: Sender"); @@ -236,15 +240,15 @@ contract TokenBlacklist { /// Internal /// - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _increase_public_balance(to: AztecAddress, amount: Field) { let new_balance = storage.public_balances.at(to).read().add(U128::from_integer(amount)); storage.public_balances.at(to).write(new_balance); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _reduce_total_supply(amount: Field) { // Only to be called from burn. let new_supply = storage.total_supply.read().sub(U128::from_integer(amount)); diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 21d1a365d03..b8ff087f3c1 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -1,5 +1,5 @@ use dep::aztec::{ - prelude::{NoteHeader, NoteInterface, PrivateContext}, + prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, note::utils::compute_note_hash_for_nullify, oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app @@ -10,11 +10,7 @@ trait OwnedNote { fn get_amount(self) -> U128; } -global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. -// TOKEN_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global TOKEN_NOTE_BYTES_LEN: Field = 3 * 32 + 64; - -#[aztec(note)] +#[note] struct TokenNote { // The amount of tokens in the note amount: U128, @@ -24,7 +20,7 @@ struct TokenNote { randomness: Field, } -impl NoteInterface for TokenNote { +impl NullifiableNote for TokenNote { // docs:start:nullifier fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index b3a5c8f3171..e8c6fe754b7 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -1,40 +1,23 @@ // docs:start:token_types_all use dep::aztec::{ note::{note_getter_options::PropertySelector, utils::compute_note_hash_for_nullify}, - prelude::{NoteHeader, NoteInterface, PrivateContext}, + prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; -global TRANSPARENT_NOTE_LEN: Field = 2; -// TRANSPARENT_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global TRANSPARENT_NOTE_BYTES_LEN: Field = 2 * 32 + 64; - // Transparent note represents a note that is created in the clear (public execution), but can only be spent by those // that know the preimage of the "secret_hash" (the secret). This is typically used when shielding a token balance. // Owner of the tokens provides a "secret_hash" as an argument to the public "shield" function and then the tokens // can be redeemed in private by presenting the preimage of the "secret_hash" (the secret). -#[aztec(note)] +#[note] struct TransparentNote { amount: Field, secret_hash: Field, } -struct TransparentNoteProperties { - amount: PropertySelector, - secret_hash: PropertySelector, -} - -impl NoteInterface for TransparentNote { - // Custom serialization to avoid disclosing the secret field - fn serialize_content(self) -> [Field; TRANSPARENT_NOTE_LEN] { - [self.amount, self.secret_hash] - } +impl NullifiableNote for TransparentNote { - // Custom deserialization since we don't have access to the secret plaintext - fn deserialize_content(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> Self { - TransparentNote { amount: serialized_note[0], secret_hash: serialized_note[1], header: NoteHeader::empty() } - } fn compute_nullifier(self, _context: &mut PrivateContext, _note_hash_for_nullify: Field) -> Field { self.compute_nullifier_without_context() @@ -46,7 +29,7 @@ impl NoteInterface for Transpa // 1) We pass the secret as an argument to the function and use it to compute a secret hash, // 2) we fetch a note via the "get_notes" oracle which accepts the secret hash as an argument, // 3) the "get_notes" oracle constrains that the secret hash in the returned note matches the one computed in - // circuit. + // circuit. // This achieves that the note can only be spent by the party that knows the secret. fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_nullify(self); @@ -63,14 +46,6 @@ impl TransparentNote { TransparentNote { amount, secret_hash, header: NoteHeader::empty() } } - // CUSTOM FUNCTIONS FOR THIS NOTE TYPE - // Custom serialization forces us to manually create the metadata struct and its getter - pub fn properties() -> TransparentNoteProperties { - TransparentNoteProperties { - amount: PropertySelector { index: 0, offset: 0, length: 32 }, - secret_hash: PropertySelector { index: 1, offset: 0, length: 32 } - } - } } impl Eq for TransparentNote { diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index 06de11e96cb..bf1d2a64b66 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -5,44 +5,49 @@ // And corresponds to a Token on L2 that uses the `AuthWit` accounts pattern. // Bridge has to be set as a minter on the token before it can be used +use dep::aztec::macros::aztec; + +#[aztec] contract TokenBridge { use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, PublicMutable, SharedImmutable}; use dep::token_portal_content_hash_lib::{get_mint_public_content_hash, get_mint_private_content_hash, get_withdraw_content_hash}; use dep::token::Token; + + use dep::aztec::macros::{storage::storage, functions::{public, initializer, private, internal}}; // docs:end:token_bridge_imports // docs:start:token_bridge_storage_and_constructor // Storage structure, containing all storage, and specifying what slots they use. - #[aztec(storage)] + #[storage] struct Storage { token: PublicMutable, portal_address: SharedImmutable, } // Constructs the contract. - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(token: AztecAddress, portal_address: EthAddress) { storage.token.write(token); storage.portal_address.initialize(portal_address); } // docs:end:token_bridge_storage_and_constructor - #[aztec(private)] + #[private] fn get_portal_address() -> EthAddress { storage.portal_address.read_private() } - #[aztec(public)] + #[public] fn get_portal_address_public() -> EthAddress { storage.portal_address.read_public() } // docs:start:claim_public // Consumes a L1->L2 message and calls the token contract to mint the appropriate amount publicly - #[aztec(public)] + #[public] fn claim_public(to: AztecAddress, amount: Field, secret: Field, message_leaf_index: Field) { let content_hash = get_mint_public_content_hash(to, amount); @@ -62,7 +67,7 @@ contract TokenBridge { // docs:start:exit_to_l1_public // Burns the appropriate amount of tokens and creates a L2 to L1 withdraw message publicly // Requires `msg.sender` to give approval to the bridge to burn tokens on their behalf using witness signatures - #[aztec(public)] + #[public] fn exit_to_l1_public( recipient: EthAddress, // ethereum address to withdraw to amount: Field, @@ -80,7 +85,7 @@ contract TokenBridge { // docs:start:claim_private // Consumes a L1->L2 message and calls the token contract to mint the appropriate amount in private assets // User needs to call token.redeem_shield() to get the private assets - #[aztec(private)] + #[private] fn claim_private( secret_hash_for_redeeming_minted_notes: Field, // secret hash used to redeem minted notes at a later time. This enables anyone to call this function and mint tokens to a user on their behalf amount: Field, @@ -105,7 +110,7 @@ contract TokenBridge { // docs:start:exit_to_l1_private // Burns the appropriate amount of tokens and creates a L2 to L1 withdraw message privately // Requires `msg.sender` (caller of the method) to give approval to the bridge to burn tokens on their behalf using witness signatures - #[aztec(private)] + #[private] fn exit_to_l1_private( token: AztecAddress, recipient: EthAddress, // ethereum address to withdraw to @@ -128,8 +133,8 @@ contract TokenBridge { /// docs:end:exit_to_l1_private // docs:start:get_token - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_token() -> AztecAddress { storage.token.read() } @@ -139,16 +144,16 @@ contract TokenBridge { // This is a public call as we need to read from public storage. // Also, note that user hashes their secret in private and only sends the hash in public // meaning only user can `redeem_shield` at a later time with their secret. - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _call_mint_on_token(amount: Field, secret_hash: Field) { Token::at(storage.token.read()).mint_private(amount, secret_hash).call(&mut context); } // docs:end:call_mint_on_token // docs:start:assert_token_is_same - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _assert_token_is_same(token: AztecAddress) { assert(storage.token.read().eq(token), "Token address is not the same as seen in storage"); } diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr index ed18788ebe0..66b5f4f60b9 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -4,6 +4,9 @@ mod util; // Demonstrates how to use portal contracts to swap on L1 Uniswap with funds on L2 // Has two separate flows for private and public respectively // Uses the token bridge contract, which tells which input token we need to talk to and handles the exit funds to L1 +use dep::aztec::macros::aztec; + +#[aztec] contract Uniswap { use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, SharedImmutable}; @@ -12,21 +15,22 @@ contract Uniswap { use dep::token::Token; use dep::token_bridge::TokenBridge; use crate::util::{compute_swap_private_content_hash, compute_swap_public_content_hash}; + use dep::aztec::macros::{storage::storage, functions::{public, initializer, view, internal, private}}; - #[aztec(storage)] - struct Storage { - portal_address: SharedImmutable, + #[storage] + struct Storage { + portal_address: SharedImmutable, } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(portal_address: EthAddress) { storage.portal_address.initialize(portal_address); } // docs:end:uniswap_setup // docs:start:swap_public - #[aztec(public)] + #[public] fn swap_public( sender: AztecAddress, input_asset_bridge: AztecAddress, @@ -87,7 +91,7 @@ contract Uniswap { // docs:end:swap_public // docs:start:swap_private - #[aztec(private)] + #[private] fn swap_private( input_asset: AztecAddress, // since private, we pass here and later assert that this is as expected by input_bridge input_asset_bridge: AztecAddress, @@ -150,8 +154,8 @@ contract Uniswap { // Assume `token` relates to `token_bridge` (ie token_bridge.token == token) // Note that private can't read public return values so created an internal public that handles everything // this method is used for both private and public swaps. - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _approve_bridge_and_exit_input_asset_to_L1( token: AztecAddress, token_bridge: AztecAddress, @@ -181,9 +185,9 @@ contract Uniswap { // docs:end:authwit_uniswap_set // docs:start:assert_token_is_same - #[aztec(public)] - #[aztec(internal)] - #[aztec(view)] + #[public] + #[internal] + #[view] fn _assert_token_is_same(token: AztecAddress, token_bridge: AztecAddress) { assert( token.eq(TokenBridge::at(token_bridge).get_token().view(&mut context)), "input_asset address is not the same as seen in the bridge contract" From 0087534be4d8cf3b3c7dd57c8651784e5a789056 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 16 Sep 2024 20:34:45 +0000 Subject: [PATCH 15/79] contract fixin' --- .../aztec-nr/aztec/src/generators.nr | 3 ++ .../aztec/src/macros/functions/mod.nr | 38 +++++++++----- .../aztec-nr/aztec/src/macros/mod.nr | 49 +++++++++++++------ .../aztec-nr/aztec/src/macros/notes/mod.nr | 25 +++++++--- .../aztec-nr/aztec/src/macros/storage/mod.nr | 14 ++++-- .../aztec-nr/aztec/src/macros/utils.nr | 8 +++ .../app_subscription_contract/src/main.nr | 4 +- .../src/subscription_note.nr | 10 ++-- .../contracts/router_contract/src/main.nr | 3 -- .../token_contract/src/test/minting.nr | 10 ++-- .../token_contract/src/test/refunds.nr | 4 +- .../token_contract/src/test/shielding.nr | 4 +- .../token_contract/src/test/utils.nr | 4 +- 13 files changed, 118 insertions(+), 58 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/generators.nr b/noir-projects/aztec-nr/aztec/src/generators.nr index d6318f2bec9..0894a4f9e5d 100644 --- a/noir-projects/aztec-nr/aztec/src/generators.nr +++ b/noir-projects/aztec-nr/aztec/src/generators.nr @@ -4,6 +4,9 @@ use dep::protocol_types::point::Point; global Ga1 = Point { x: 0x30426e64aee30e998c13c8ceecda3a77807dbead52bc2f3bf0eae851b4b710c1, y: 0x113156a068f603023240c96b4da5474667db3b8711c521c748212a15bc034ea6, is_infinite: false }; global Ga2 = Point { x: 0x2825c79cc6a5cbbeef7d6a8f1b6a12b312aa338440aefeb4396148c89147c049, y: 0x129bfd1da54b7062d6b544e7e36b90736350f6fba01228c41c72099509f5701e, is_infinite: false }; global Ga3 = Point { x: 0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357f, y: 0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35, is_infinite: false }; +// CREATE A NEW GENERATOR HERE +global Ga4 = Point { x: 0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357f, y: 0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35, is_infinite: false }; + // If you change this update `G_SLOT` in `yarn-project/simulator/src/client/test_utils.ts` as well global G_slot = Point { x: 0x041223147b680850dc82e8a55a952d4df20256fe0593d949a9541ca00f0abf15, y: 0x0a8c72e60d0e60f5d804549d48f3044d06140b98ed717a9b532af630c1530791, is_infinite: false }; diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 7e2149d5999..9e21301a444 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -1,12 +1,14 @@ -use std::meta::{unquote, type_of}; - +use std::{ + meta::{type_of, unquote}, collections::umap::UHashMap, + hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} +}; use super::utils::{ modify_fn_body, is_fn_private, get_fn_visibility, is_fn_view, is_fn_initializer, is_fn_internal, - fn_has_noinitcheck, compute_fn_selector, add_to_field_slice, add_to_hasher + fn_has_noinitcheck, compute_fn_selector, add_to_field_slice, add_to_hasher, is_fn_public, + module_has_storage, module_has_initializer }; -use super::utils::is_fn_public; -comptime mut global STUBS: [Quoted] = &[]; +comptime mut global STUBS: UHashMap> = UHashMap::default(); // Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] pub comptime fn internal(_f: FunctionDefinition) {} @@ -86,12 +88,24 @@ comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { result } +comptime fn register_stub(m: Module, stub: Quoted) { + let current_stubs = unsafe { + STUBS.get(m) + }; + let stubs_to_insert = if current_stubs.is_some() { + current_stubs.unwrap().push_back(stub) + } else { + &[stub] + }; + STUBS.insert(m, stubs_to_insert); +} + pub comptime fn private(f: FunctionDefinition) -> Quoted { let fn_abi = create_fn_abi_export(f); let fn_stub = stub_fn(f); - STUBS = STUBS.push_back(fn_stub); - let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| is_fn_initializer(f)); - let module_has_storage = f.module().structs().any(|s: StructDefinition| s.has_named_attribute("storage")); + register_stub(f.module(), fn_stub); + let module_has_initializer = module_has_initializer(f.module()); + let module_has_storage = module_has_storage(f.module()); let current_params = f.parameters(); f.set_parameters( @@ -196,9 +210,9 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { pub comptime fn public(f: FunctionDefinition) -> Quoted { let fn_abi = create_fn_abi_export(f); let fn_stub = stub_fn(f); - STUBS = STUBS.push_back(fn_stub); - let module_has_initializer = f.module().functions().any(|f: FunctionDefinition| is_fn_initializer(f)); - let module_has_storage = f.module().structs().any(|s: StructDefinition| s.has_named_attribute("storage")); + register_stub(f.module(), fn_stub); + let module_has_initializer = module_has_initializer(f.module()); + let module_has_storage = module_has_storage(f.module()); let current_params = f.parameters(); f.set_parameters( @@ -260,7 +274,7 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { pub comptime fn transform_unconstrained(f: FunctionDefinition) { let context_creation = quote { let mut context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); }; - let module_has_storage = f.module().structs().any(|s: StructDefinition| s.has_named_attribute("storage")); + let module_has_storage = module_has_storage(f.module()); let storage_init = if module_has_storage { quote { let storage = Storage::init(context); } diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 9f598398000..313e9b4a89b 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -9,16 +9,23 @@ use storage::STORAGE_LAYOUT_NAME; use notes::{NOTES, generate_note_export}; use functions::transform_unconstrained; +use utils::module_has_storage; pub comptime fn generate_contract_interface(m: Module) -> Quoted { let module_name = m.name(); - let fn_stubs_quote = STUBS.join(quote {}); + let contract_stubs = STUBS.get(m); + let fn_stubs_quote = if contract_stubs.is_some() { + contract_stubs.unwrap().join(quote {}) + } else { + quote {} + }; - let has_storage = STORAGE_LAYOUT_NAME != quote {}; + let has_storage = module_has_storage(m); let storage_layout_getter = if has_storage { + let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap(); quote { pub fn storage_layout() -> StorageLayout { - $STORAGE_LAYOUT_NAME + $storage_layout_name } } } else { @@ -72,18 +79,24 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { } } -pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { +pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier(m: Module) -> Quoted { + let contract_notes = NOTES.get(m); let mut max_note_length: u32 = 0; - let body = if NOTES.len() == 0 { - quote { + let empty_body = quote { assert(false, "This contract does not use private notes"); [0, 0, 0, 0] - } + }; + let body = if contract_notes.is_none() { + empty_body + } else if contract_notes.unwrap().len() == 0 { // no short circuiting :( + empty_body } else { - max_note_length = NOTES.fold(0, | acc, (_, len, _): (StructDefinition, u32, Field) | { + let notes = contract_notes.unwrap(); + + max_note_length = notes.fold(0, | acc, (_, len, _): (StructDefinition, u32, Field) | { acc + len }); - let if_statements = NOTES.map( + let if_statements = notes.map( | (note, _, _): (StructDefinition, u32, Field) | { let note_name = note.name(); quote { @@ -118,12 +131,18 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quote } } -pub comptime fn generate_note_exports() -> Quoted { - let note_exports = NOTES.map( - | (s, _, note_type_id): (StructDefinition, u32, Field) | { +pub comptime fn generate_note_exports(m: Module) -> Quoted { + let contract_notes = NOTES.get(m); + let note_exports = if contract_notes.is_some() { + let notes = contract_notes.unwrap(); + notes.map( + | (s, _, note_type_id): (StructDefinition, u32, Field) | { generate_note_export(s, note_type_id) } - ).join(quote {}); + ).join(quote {}) + } else { + quote {} + }; quote { $note_exports @@ -133,8 +152,8 @@ pub comptime fn generate_note_exports() -> Quoted { pub comptime fn aztec(m: Module) -> Quoted { let interface = generate_contract_interface(m); let unconstrained_functions = m.functions().filter(| f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute("test")); - let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); - let note_exports = generate_note_exports(); + let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(m); + let note_exports = generate_note_exports(m); for f in unconstrained_functions { transform_unconstrained(f); } diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 6353f2fe5a9..9463faf0b95 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -1,9 +1,12 @@ -use std::meta::{type_of, unquote}; +use std::{ + meta::{type_of, unquote}, collections::umap::UHashMap, + hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} +}; use protocol_types::{meta::flatten_to_fields, utils::field::field_from_bytes}; use crate::note::{note_header::NoteHeader, note_getter_options::PropertySelector}; use protocol_types::meta::pack_from_fields; -comptime mut global NOTES = &[]; +comptime mut global NOTES: UHashMap> = UHashMap::default(); comptime fn compute_note_type_id(name: Quoted) -> Field { let name_as_str_quote = name.as_str_quote(); @@ -298,6 +301,18 @@ comptime fn generate_partial_note_impl(s: StructDefinition, hiding_point_name: Q } } +comptime fn register_note(note: StructDefinition, note_serialized_len: u32, note_type_id: Field) { + let current_notes = unsafe { + NOTES.get(note.module()) + }; + let notes_to_insert = if current_notes.is_some() { + current_notes.unwrap().push_back((note, note_serialized_len, note_type_id)) + } else { + &[(note, note_serialized_len, note_type_id)] + }; + NOTES.insert(note.module(), notes_to_insert); +} + #[varargs] pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { // Automatically inject header if not present @@ -315,8 +330,7 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> let note_properties = generate_note_properties(s); let partial_note_impl = generate_partial_note_impl(s, hiding_point_name); - // Register note here - NOTES = NOTES.push_back((s, note_serialized_len, note_type_id)); + register_note(s, note_serialized_len, note_type_id); quote { $note_interface_impl @@ -340,8 +354,7 @@ pub comptime fn note(s: StructDefinition) -> Quoted { let (note_interface_impl, note_serialized_len, note_type_id) = generate_note_interface(s, hiding_point_name, fixed_fields, &[]); let note_properties = generate_note_properties(s); - // Register note here - NOTES = NOTES.push_back((s, note_serialized_len, note_type_id)); + register_note(s, note_serialized_len, note_type_id); quote { $note_interface_impl diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index fd0683c1e58..af5a70532c2 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -1,6 +1,11 @@ +use std::{ + collections::umap::UHashMap, + hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} +}; + use super::utils::get_serialized_size; -comptime mut global STORAGE_LAYOUT_NAME: Quoted = quote {}; +comptime mut global STORAGE_LAYOUT_NAME: UHashMap> = UHashMap::default(); pub comptime fn is_storage_map(typ: Type) -> bool { if typ.as_struct().is_some() { @@ -102,7 +107,10 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { let storage_layout_fields = storage_layout_fields.join(quote {,}); let storage_layout_constructors = storage_layout_constructors.join(quote {,}); - STORAGE_LAYOUT_NAME = quote { STORAGE_LAYOUT }; + let module = s.module(); + let module_name = module.name(); + let storage_layout_name = f"STORAGE_LAYOUT_{module_name}".quoted_contents(); + STORAGE_LAYOUT_NAME.insert(module, storage_layout_name); quote { impl Storage { @@ -118,7 +126,7 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { } #[abi(storage)] - global $STORAGE_LAYOUT_NAME = StorageLayout { + global $storage_layout_name = StorageLayout { $storage_layout_constructors }; } diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 3bc940ffa51..db34cd25af3 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -262,3 +262,11 @@ pub(crate) comptime fn get_serialized_size(typ: Type) -> u32 { let serialize_impl = maybe_serialize_impl.unwrap(); serialize_impl.trait_generic_args()[0].as_constant().unwrap() } + +pub(crate) comptime fn module_has_storage(m: Module) -> bool { + m.structs().any(|s: StructDefinition| s.has_named_attribute("storage")) +} + +pub(crate) comptime fn module_has_initializer(m: Module) -> bool { + m.functions().any(|f: FunctionDefinition| is_fn_initializer(f)) +} diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 5c484123d78..727165b69c6 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -10,7 +10,9 @@ contract AppSubscription { use aztec::{ prelude::{AztecAddress, Map, PrivateMutable, SharedImmutable}, keys::getters::get_current_public_keys, protocol_types::constants::MAX_FIELD_VALUE, - utils::comparison::Comparator, macros::{storage, functions::{public, initializer, private}} + utils::comparison::Comparator, + encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note, encode_and_encrypt_note_with_keys }; + macros::{storage::storage, functions::{public, initializer, private}} }; use authwit::auth::assert_current_call_valid_authwit; use token::Token; diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index d10a99b49b6..39b0c2d040f 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -1,14 +1,10 @@ use dep::aztec::{ hash::poseidon2_hash_with_separator, note::utils::compute_note_hash_for_nullify, keys::getters::get_nsk_app, oracle::unsafe_rand::unsafe_rand, - prelude::{PrivateContext, NoteHeader, NoteInterface}, - protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER + prelude::{PrivateContext, NoteHeader, NullifiableNote}, + protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER, macros::notes::note }; -global SUBSCRIPTION_NOTE_LEN: Field = 4; -// SUBSCRIPTION_NOTE_BYTES_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global SUBSCRIPTION_NOTE_BYTES_LEN: Field = SUBSCRIPTION_NOTE_LEN * 32 + 64; - #[note] struct SubscriptionNote { // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. @@ -19,7 +15,7 @@ struct SubscriptionNote { randomness: Field, } -impl NoteInterface for SubscriptionNote { +impl NullifiableNote for SubscriptionNote { fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); poseidon2_hash_with_separator( diff --git a/noir-projects/noir-contracts/contracts/router_contract/src/main.nr b/noir-projects/noir-contracts/contracts/router_contract/src/main.nr index 1bfe4f28242..914b3829f75 100644 --- a/noir-projects/noir-contracts/contracts/router_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/router_contract/src/main.nr @@ -6,9 +6,6 @@ use dep::aztec::macros::aztec; /// The purpose of this contract is to perform a check in public without revealing what contract enqued the public /// call. This is achieved by having a private function on this contract that enques the public call and hence /// the `msg_sender` in the public call is the address of this contract. -#[aztec] -use dep::aztec::macros::aztec; - #[aztec] contract Router { use aztec::{macros::functions::{private, public, view, internal}, utils::comparison::compare}; diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/test/minting.nr b/noir-projects/noir-contracts/contracts/token_contract/src/test/minting.nr index 159c4daf0fc..b9ac10979fb 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/test/minting.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/test/minting.nr @@ -77,7 +77,7 @@ unconstrained fn mint_private_success() { // Store a note in the cache so we can redeem it env.store_note_in_cache( &mut TransparentNote::new(mint_amount, secret_hash), - Token::storage().pending_shields.slot, + Token::storage_layout().pending_shields.slot, token_contract_address ); @@ -108,7 +108,7 @@ unconstrained fn mint_private_failure_double_spend() { // Store a note in the cache so we can redeem it env.store_note_in_cache( &mut TransparentNote::new(mint_amount, secret_hash), - Token::storage().pending_shields.slot, + Token::storage_layout().pending_shields.slot, token_contract_address ); @@ -167,7 +167,7 @@ unconstrained fn mint_private_failure_overflow_recipient() { // Store a note in the cache so we can redeem it env.store_note_in_cache( &mut TransparentNote::new(mint_amount, secret_hash), - Token::storage().pending_shields.slot, + Token::storage_layout().pending_shields.slot, token_contract_address ); @@ -207,12 +207,12 @@ unconstrained fn mint_private_failure_overflow_total_supply() { // Store 2 notes in the cache so we can redeem it for owner and recipient env.store_note_in_cache( &mut TransparentNote::new(mint_amount, secret_hash_owner), - Token::storage().pending_shields.slot, + Token::storage_layout().pending_shields.slot, token_contract_address ); env.store_note_in_cache( &mut TransparentNote::new(mint_amount, secret_hash_recipient), - Token::storage().pending_shields.slot, + Token::storage_layout().pending_shields.slot, token_contract_address ); diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/test/refunds.nr b/noir-projects/noir-contracts/contracts/token_contract/src/test/refunds.nr index 8bd9b5763b8..dd6de4b93d6 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/test/refunds.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/test/refunds.nr @@ -37,8 +37,8 @@ unconstrained fn setup_refund_success() { let user_npk_m_hash = get_current_public_keys(&mut context, user).npk_m.hash(); let fee_payer_npk_m_hash = get_current_public_keys(&mut context, fee_payer).npk_m.hash(); - let fee_payer_balances_slot = derive_storage_slot_in_map(Token::storage().balances.slot, fee_payer); - let user_balances_slot = derive_storage_slot_in_map(Token::storage().balances.slot, user); + let fee_payer_balances_slot = derive_storage_slot_in_map(Token::storage_layout().balances.slot, fee_payer); + let user_balances_slot = derive_storage_slot_in_map(Token::storage_layout().balances.slot, user); // When the refund was set up, we would've spent the note worth mint_amount, and inserted a note worth //`mint_amount - funded_amount`. When completing the refund, we would've constructed a hash corresponding to a note diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/test/shielding.nr b/noir-projects/noir-contracts/contracts/token_contract/src/test/shielding.nr index a1f9212d866..63ecbedf471 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/test/shielding.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/test/shielding.nr @@ -17,7 +17,7 @@ unconstrained fn shielding_on_behalf_of_self() { // Store a note in the cache so we can redeem it env.store_note_in_cache( &mut TransparentNote::new(shield_amount, secret_hash), - Token::storage().pending_shields.slot, + Token::storage_layout().pending_shields.slot, token_contract_address ); @@ -50,7 +50,7 @@ unconstrained fn shielding_on_behalf_of_other() { // Store a note in the cache so we can redeem it env.store_note_in_cache( &mut TransparentNote::new(shield_amount, secret_hash), - Token::storage().pending_shields.slot, + Token::storage_layout().pending_shields.slot, token_contract_address ); diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/test/utils.nr b/noir-projects/noir-contracts/contracts/token_contract/src/test/utils.nr index fde110352eb..8bda1a5f0ef 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/test/utils.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/test/utils.nr @@ -58,7 +58,7 @@ pub fn setup_and_mint(with_account_contracts: bool) -> (&mut TestEnvironment, Az // Store a note in the cache so we can redeem it env.store_note_in_cache( &mut TransparentNote::new(mint_amount, secret_hash), - Token::storage().pending_shields.slot, + Token::storage_layout().pending_shields.slot, token_contract_address ); // docs:end:txe_test_store_note @@ -76,7 +76,7 @@ pub fn check_public_balance(token_contract_address: AztecAddress, address: Aztec cheatcodes::set_contract_address(token_contract_address); let block_number = get_block_number(); - let balances_slot = Token::storage().public_balances.slot; + let balances_slot = Token::storage_layout().public_balances.slot; let address_slot = derive_storage_slot_in_map(balances_slot, address); let amount: U128 = storage_read(token_contract_address, address_slot, block_number); assert(amount.to_field() == address_amount, "Public balance is not correct"); From f033fcc64833b89eb6b99c0048ef1513902b866a Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 07:41:45 +0000 Subject: [PATCH 16/79] more fixin --- .../aztec/src/macros/functions/mod.nr | 17 +- .../aztec-nr/aztec/src/macros/mod.nr | 7 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 71 +++++---- .../aztec-nr/aztec/src/macros/storage/mod.nr | 21 +-- .../aztec-nr/aztec/src/macros/utils.nr | 15 +- .../aztec/src/state_vars/private_immutable.nr | 10 +- .../aztec/src/state_vars/private_mutable.nr | 8 +- .../app_subscription_contract/src/main.nr | 2 +- .../contracts/auth_contract/src/main.nr | 6 +- .../contracts/avm_test_contract/src/main.nr | 3 +- .../benchmarking_contract/src/main.nr | 8 +- .../contracts/card_game_contract/src/main.nr | 14 +- .../contracts/child_contract/src/main.nr | 8 +- .../contracts/claim_contract/src/main.nr | 2 +- .../src/main.nr | 2 +- .../contracts/counter_contract/src/main.nr | 3 - .../crowdfunding_contract/src/main.nr | 6 +- .../delegated_on_contract/src/main.nr | 7 +- .../contracts/delegator_contract/src/main.nr | 51 +++--- .../docs_example_contract/src/main.nr | 150 ++++++++---------- .../docs_example_contract/src/options.nr | 10 +- .../src/types/card_note.nr | 8 +- .../crates/types/src/meta/mod.nr | 2 +- 23 files changed, 201 insertions(+), 230 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 9e21301a444..0c47455206d 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -157,12 +157,12 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { quote {} }; - let return_value_type = f.return_type(); + let return_value_var_name = quote { macro__returned__values }; + let (body_without_return, last_body_expr) = body.pop_back(); + let return_value_type = f.return_type(); let return_value = if return_value_type != type_of(()) { - let (body_without_return, return_value) = body.pop_back(); - let return_value = return_value.quoted(); - let return_value_var_name = quote { macro__returned__values }; + let return_value = last_body_expr.quoted(); let return_value_assignment = quote { let $return_value_var_name = $return_value; }; let return_hasher_name = quote { return_hasher }; let return_value_into_hasher = add_to_hasher(return_hasher_name, return_value_var_name, return_value_type); @@ -176,6 +176,14 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { context.set_return_hash($return_hasher_name); } } else { + if !last_body_expr.has_semicolon() + & last_body_expr.as_for().is_none() + & last_body_expr.as_assert().is_none() + & last_body_expr.as_for_range().is_none() { + println("wtf"); + let unused_return_value_name = f"_{return_value_var_name}".quoted_contents(); + body = body.pop_back().0.push_back(quote { let $unused_return_value_name = $last_body_expr; }.as_expr().unwrap()); + } quote {} }; @@ -287,6 +295,7 @@ pub comptime fn transform_unconstrained(f: FunctionDefinition) { }; let body = f.body().as_block().unwrap(); let modified_body = modify_fn_body(body, to_prepend, quote {}); + f.set_return_public(true); f.set_body(modified_body); } diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 313e9b4a89b..7598ba953f5 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -151,12 +151,15 @@ pub comptime fn generate_note_exports(m: Module) -> Quoted { pub comptime fn aztec(m: Module) -> Quoted { let interface = generate_contract_interface(m); + let unconstrained_functions = m.functions().filter(| f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute("test")); - let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(m); - let note_exports = generate_note_exports(m); for f in unconstrained_functions { transform_unconstrained(f); } + + let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(m); + let note_exports = generate_note_exports(m); + quote { $interface $compute_note_hash_and_optionally_a_nullifier diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 9463faf0b95..f187bc80529 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -170,21 +170,42 @@ comptime fn generate_note_hiding_point( let name = s.name(); let hiding_point_name = f"{name}HidingPoint".quoted_contents(); - let mut new_args_list = &[]; let mut new_generators_list = &[]; let mut new_scalars_list = &[]; + let mut new_args_list = &[]; + let mut new_generics_list = &[]; + let mut new_trait_bounds_list = &[]; + for i in 0..fixed_fields.len() { - let (field_name, field_type) = fixed_fields[i]; + let (field_name, _) = fixed_fields[i]; + let arg_type = f"N{i}".quoted_contents(); let generator_index = i + 1; new_generators_list = new_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); new_scalars_list = new_scalars_list.push_back(quote { std::hash::from_field_unsafe($field_name.to_field()) }); - new_args_list = new_args_list.push_back(quote { $field_name: $field_type }); + new_args_list = new_args_list.push_back(quote { $field_name: $arg_type }); + new_generics_list = new_generics_list.push_back(quote { $arg_type }); + new_trait_bounds_list = new_trait_bounds_list.push_back(quote { $arg_type: aztec::protocol_types::traits::ToField }); } + new_args_list = new_args_list.push_back(quote { storage_slot: Field }); let new_generators = new_generators_list.push_back(quote { aztec::generators::G_slot }).join(quote {,}); let new_scalars = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(storage_slot) }).join(quote {,}); let new_args = new_args_list.join(quote {,}); + let new_generics = if new_generics_list.len() > 0 { + let generics = new_generics_list.join(quote {,}); + quote {<$generics>} + } else { + quote {} + }; + + let new_trait_bounds = if new_trait_bounds_list.len() > 0 { + let bounds = new_trait_bounds_list.join(quote {,}); + quote {where $bounds} + } else { + quote {} + }; + let mut finalize_generators_list = &[]; let mut finalize_scalars_list = &[]; let mut finalize_args_list = &[]; @@ -253,8 +274,7 @@ comptime fn generate_note_hiding_point( $hiding_point_name { inner: aztec::protocol_types::point::Point::empty() } } - fn new($new_args) -> $hiding_point_name { - let generators = [$new_generators]; + fn new$new_generics($new_args) -> $hiding_point_name $new_trait_bounds { let point = std::embedded_curve_ops::multi_scalar_mul( [$new_generators], [$new_scalars] @@ -267,8 +287,7 @@ comptime fn generate_note_hiding_point( self } - fn initialize($initialize_args) -> $hiding_point_name { - let generators = [$new_generators]; + fn initialize$new_generics($initialize_args) -> $hiding_point_name $new_trait_bounds { let point = std::embedded_curve_ops::multi_scalar_mul( [$new_generators], [$new_scalars] @@ -313,8 +332,7 @@ comptime fn register_note(note: StructDefinition, note_serialized_len: u32, note NOTES.insert(note.module(), notes_to_insert); } -#[varargs] -pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { +comptime fn common_note_annotation(s: StructDefinition, nullable_fields: [Quoted]) -> (Quoted, Quoted) { // Automatically inject header if not present let note_header_type = type_of(NoteHeader::empty()); let filtered_header = s.fields().filter(| (_, typ): (Quoted, Type) | typ == note_header_type); @@ -328,37 +346,28 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, fixed_fields, nullable_fields); let (note_interface_impl, note_serialized_len, note_type_id) = generate_note_interface(s, hiding_point_name, fixed_fields, nullable_fields); let note_properties = generate_note_properties(s); - let partial_note_impl = generate_partial_note_impl(s, hiding_point_name); register_note(s, note_serialized_len, note_type_id); - quote { + (quote { $note_interface_impl $note_properties $note_hiding_point - $partial_note_impl - } + }, hiding_point_name) } -pub comptime fn note(s: StructDefinition) -> Quoted { - // Automatically inject header if not present - let note_header_type = type_of(NoteHeader::empty()); - let filtered_header = s.fields().filter(| (_, typ): (Quoted, Type) | typ == note_header_type); - if (filtered_header.len() == 0) { - let new_fields = s.fields().push_back((quote { header }, note_header_type)); - s.set_fields(new_fields); - } - let fixed_fields = s.fields().filter(| (_, typ): (Quoted, Type) | typ != note_header_type); - - let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, fixed_fields, &[]); - let (note_interface_impl, note_serialized_len, note_type_id) = generate_note_interface(s, hiding_point_name, fixed_fields, &[]); - let note_properties = generate_note_properties(s); - - register_note(s, note_serialized_len, note_type_id); +#[varargs] +pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { + let (common, hiding_point_name) = common_note_annotation(s, nullable_fields); + let partial_note_impl = generate_partial_note_impl(s, hiding_point_name); quote { - $note_interface_impl - $note_properties - $note_hiding_point + $common + $partial_note_impl } } + +pub comptime fn note(s: StructDefinition) -> Quoted { + let (common, _) = common_note_annotation(s, &[]); + common +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index af5a70532c2..8da08e35a21 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -41,9 +41,6 @@ pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, pare let serialized_size = if parent_is_map { 1 } else { - assert( - container_struct_generics.len() == 2, f"Failed to process {container_struct_name}: Storable containers must be generic over a serializable type and Context" - ); let stored_struct = container_struct_generics[0]; let is_note = if stored_struct.as_struct().is_some() { let (def, _) = stored_struct.as_struct().unwrap(); @@ -104,6 +101,16 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { //s.set_fields(new_storage_fields); let storage_vars_constructors = storage_vars_constructors.join(quote {,}); + let storage_impl = quote { + impl Storage { + fn init(context: Context) -> Self { + Self { + $storage_vars_constructors + } + } + } + }; + let storage_layout_fields = storage_layout_fields.join(quote {,}); let storage_layout_constructors = storage_layout_constructors.join(quote {,}); @@ -113,13 +120,7 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { STORAGE_LAYOUT_NAME.insert(module, storage_layout_name); quote { - impl Storage { - fn init(context: Context) -> Self { - Self { - $storage_vars_constructors - } - } - } + $storage_impl struct StorageLayout { $storage_layout_fields diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index db34cd25af3..f4936a39d28 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -57,16 +57,6 @@ pub(crate) comptime fn expr_as_quoted_fixed(expr: Expr) -> Quoted { } else { quote { if $condition { $fixed_if } } } - } else if expr.as_for().is_some() { - // Fix the for body - let (variable, iterable, body) = expr.as_for().unwrap(); - let fixed_body = expr_as_quoted_fixed(body); - quote { for $variable in $iterable $fixed_body } - } else if expr.as_block().is_some() { - let fixed = expr_slice_as_quoted_fixed(expr.as_block().unwrap()); - quote { - { $fixed } - } } else { quote { $expr } } @@ -95,10 +85,7 @@ pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quo } }; let body_expr = body_quote.as_expr(); - if !body_expr.is_some() { - println(body_quote); - } - assert(body_expr.is_some(), "Body is not an expression"); + assert(body_expr.is_some(), f"Body is not an expression: {body_quote}"); body_expr.unwrap() } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 687a3e87153..681c6780c6d 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -3,8 +3,8 @@ use dep::protocol_types::{constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, use crate::context::{PrivateContext, UnconstrainedContext}; use crate::note::{ lifecycle::create_note, note_getter::{get_note, view_notes}, - note_interface::{NoteInterface, NullifiableNote}, - note_viewer_options::NoteViewerOptions, note_emission::NoteEmission + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, + note_emission::NoteEmission }; use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; @@ -42,7 +42,7 @@ impl PrivateImmutable { impl PrivateImmutable { // docs:start:initialize - pub fn initialize( + pub fn initialize( self, note: &mut Note ) -> NoteEmission where Note: NoteInterface + NullifiableNote { @@ -55,7 +55,7 @@ impl PrivateImmutable { // docs:end:initialize // docs:start:get_note - pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote { + pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote { let storage_slot = self.storage_slot; get_note(self.context, storage_slot).0 } @@ -72,7 +72,7 @@ impl PrivateImmutable { // view_note does not actually use the context, but it calls oracles that are only available in private // docs:start:view_note - unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote { + unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(0) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index aa634e6d103..68faf76f5a5 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -3,8 +3,8 @@ use dep::protocol_types::{constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, use crate::context::{PrivateContext, UnconstrainedContext}; use crate::note::{ lifecycle::{create_note, destroy_note_unsafe}, note_getter::{get_note, view_notes}, - note_interface::{NoteInterface, NullifiableNote}, - note_viewer_options::NoteViewerOptions, note_emission::NoteEmission + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, + note_emission::NoteEmission }; use crate::oracle::notes::check_nullifier_exists; use crate::state_vars::storage::Storage; @@ -44,7 +44,7 @@ impl PrivateMutable { } } -impl PrivateMutable where Note: NoteInterface + NullifiableNote { +impl PrivateMutable where Note: NoteInterface + NullifiableNote { // docs:start:initialize pub fn initialize(self, note: &mut Note) -> NoteEmission { // Nullify the storage slot. @@ -103,7 +103,7 @@ impl PrivateMutable where Note: NoteInter // docs:end:get_note } -impl PrivateMutable where Note: NoteInterface + NullifiableNote { +impl PrivateMutable where Note: NoteInterface + NullifiableNote { unconstrained pub fn is_initialized(self) -> bool { let nullifier = self.compute_initialization_nullifier(); check_nullifier_exists(nullifier) diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 727165b69c6..e83b0d63eee 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -11,7 +11,7 @@ contract AppSubscription { prelude::{AztecAddress, Map, PrivateMutable, SharedImmutable}, keys::getters::get_current_public_keys, protocol_types::constants::MAX_FIELD_VALUE, utils::comparison::Comparator, - encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note, encode_and_encrypt_note_with_keys }; + encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note, encode_and_encrypt_note_with_keys}, macros::{storage::storage, functions::{public, initializer, private}} }; use authwit::auth::assert_current_call_valid_authwit; diff --git a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr index 7149c6a162a..f5683d2b1bd 100644 --- a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr @@ -4,9 +4,9 @@ use dep::aztec::macros::aztec; #[aztec] contract Auth { - use dep::aztec::{protocol_types::address::AztecAddress, - state_vars::{PublicImmutable, SharedMutable }, - macros::{storage::storage, functions::{private, public, initializer, view }} + use dep::aztec::{ + protocol_types::address::AztecAddress, state_vars::{PublicImmutable, SharedMutable}, + macros::{storage::storage, functions::{private, public, initializer, view}} }; // Authorizing a new address has a certain block delay before it goes into effect. diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index b044038861d..ea74cc00ec6 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -36,7 +36,8 @@ contract AvmTest { use dep::aztec::oracle::get_contract_instance::{get_contract_instance_avm, get_contract_instance_internal_avm}; use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, storage::map::derive_storage_slot_in_map}; use dep::compressed_string::CompressedString; - use dep::aztec::macros::{storage::storage, functions::public}; + use dep::aztec::macros::{storage::storage, functions::{public, private}}; + use dep::aztec::context::gas::GasOpts; #[storage] diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr index a9c6e7daed3..2116a55fa3a 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -7,16 +7,14 @@ use dep::aztec::macros::aztec; #[aztec] contract Benchmarking { - use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, Map, PublicMutable, PrivateSet}; - use dep::value_note::{utils::{increment, decrement}, value_note::ValueNote}; + use dep::aztec::prelude::{AztecAddress, NoteGetterOptions, Map, PublicMutable, PrivateSet}; + use dep::value_note::{utils::increment, value_note::ValueNote}; - use dep::aztec::context::gas::GasOpts; use dep::aztec::macros::{storage::storage, functions::{private, public}}; - #[storage] struct Storage { - notes: Map, Context>, + notes: Map, Context>, balances: Map, Context>, } diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr index 83d4f70f6e5..095f870193b 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr @@ -5,21 +5,19 @@ use dep::aztec::macros::aztec; #[aztec] contract CardGame { - use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; + use dep::aztec::protocol_types::address::AztecAddress; use dep::aztec::{hash::pedersen_hash, state_vars::{Map, PublicMutable}}; - use dep::value_note::{balance_utils, value_note::{ValueNote, VALUE_NOTE_LEN}}; + use dep::aztec::note::constants::MAX_NOTES_PER_PAGE; - use dep::aztec::note::{note_header::NoteHeader, constants::MAX_NOTES_PER_PAGE}; - - use crate::cards::{PACK_CARDS, Deck, Card, get_pack_cards, compute_deck_strength}; - use crate::game::{NUMBER_OF_PLAYERS, NUMBER_OF_CARDS_DECK, PLAYABLE_CARDS, PlayerEntry, Game, GAME_SERIALIZED_LEN}; + use crate::cards::{Deck, Card, get_pack_cards, compute_deck_strength}; + use crate::game::{PLAYABLE_CARDS, PlayerEntry, Game}; use dep::aztec::macros::{storage::storage, functions::{private, public, internal}}; #[storage] struct Storage { - collections: Map, - game_decks: Map, Context>, + collections: Map, Context>, + game_decks: Map, Context>, Context>, games: Map, Context>, } diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index a2e8fecd9ed..2b56938fa25 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -3,15 +3,13 @@ use dep::aztec::macros::aztec; #[aztec] contract Child { - use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize, Map}; + use dep::aztec::prelude::{AztecAddress, PublicMutable, PrivateSet, Map}; use dep::aztec::{ - context::gas::GasOpts, protocol_types::{abis::call_context::CallContext}, - note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, + note::{note_getter_options::NoteGetterOptions}, encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, keys::getters::get_current_public_keys, utils::comparison::Comparator, - macros::{storage::storage, functions::{private, public, internal}}; - + macros::{storage::storage, functions::{private, public, internal}} }; use dep::value_note::value_note::ValueNote; diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index 9bc2f323d8f..3ba37a8698c 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -4,7 +4,7 @@ use dep::aztec::macros::aztec; contract Claim { use dep::aztec::{ note::utils::compute_note_hash_for_nullify, - protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}, + protocol_types::address::AztecAddress, state_vars::SharedImmutable, macros::{storage::storage, functions::{private, public, initializer}} }; diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 5f2ecb3ad6e..572a406c40f 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -13,7 +13,7 @@ contract ContractClassRegisterer { MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS }, - traits::Serialize, abis::log_hash::LogHash + abis::log_hash::LogHash }; use dep::aztec::{ diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index ab69a19b18c..c1b737beecb 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -7,9 +7,6 @@ contract Counter { use value_note::{balance_utils, value_note::ValueNote}; use easy_private_state::EasyPrivateUint; use aztec::macros::{storage::storage, functions::{initializer, private}}; - use aztec::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs; - use aztec::context::inputs::private_context_inputs::PrivateContextInputs; - // docs:end:imports // docs:start:storage_struct diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index f71fac6504b..0959c5df4f0 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -11,9 +11,10 @@ contract Crowdfunding { keys::getters::get_current_public_keys, prelude::{AztecAddress, PrivateSet, SharedImmutable}, utils::comparison::Comparator, unencrypted_logs::unencrypted_event_emission::encode_event, - macros::{storage::storage, events::event, functions::{public, initializer, private, internal}} + macros::{storage::storage, events::event, functions::{public, initializer, private, internal}}, + protocol_types::traits::Serialize }; - use dep::aztec:: + use std::meta::derive; // docs:start:import_valuenote use dep::value_note::value_note::ValueNote; // docs:end:import_valuenote @@ -22,6 +23,7 @@ contract Crowdfunding { // docs:end:all-deps #[event] + #[derive(Serialize)] struct WithdrawalProcessed { who: Field, amount: Field, diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr index ff84f8cf231..86153cdeb0a 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr @@ -3,10 +3,7 @@ use dep::aztec::macros::aztec; #[aztec] contract DelegatedOn { - use dep::aztec::prelude::{ - AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, NoteViewerOptions, PublicMutable, - PrivateSet, PrivateContext, Map - }; + use dep::aztec::prelude::{AztecAddress, NoteGetterOptions, PublicMutable, PrivateSet, Map}; use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note, keys::getters::get_current_public_keys, utils::comparison::Comparator, @@ -43,7 +40,7 @@ contract DelegatedOn { notes.get(0).value } - unconstrained fn view_public_value() -> pub Field { + unconstrained fn view_public_value() -> Field { storage.current_value.read() } } diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index 6e7acf7f8c0..1dc96018545 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -3,46 +3,41 @@ use dep::aztec::macros::aztec; #[aztec] contract Delegator { - use dep::aztec::prelude::{AztecAddress, NoteGetterOptions, PublicMutable, PrivateSet, Map}; + use dep::aztec::prelude::{AztecAddress, PublicMutable, PrivateSet, Map}; use dep::value_note::value_note::ValueNote; use dep::delegated_on::DelegatedOn; - use dep::aztec::{utils::comparison::Comparator, macros::{storage::storage, functions::{private, public}}}; + use dep::aztec::macros::{storage::storage, functions::private}; #[storage] struct Storage { current_value: PublicMutable, a_map_with_private_values: Map, Context>, } - - #[private] - fn private_delegate_set_value( - target_contract: AztecAddress, - value: Field, - owner: AztecAddress - ) -> Field { - // Call the target private function - DelegatedOn::at(target_contract).private_set_value(value, owner).delegate_call(&mut context) - } - + // #[private] + // fn private_delegate_set_value( + // target_contract: AztecAddress, + // value: Field, + // owner: AztecAddress + // ) -> Field { + // // Call the target private function + // DelegatedOn::at(target_contract).private_set_value(value, owner).delegate_call(&mut context) + // } #[private] fn enqueued_delegate_set_value(target_contract: AztecAddress, value: Field) { DelegatedOn::at(target_contract).public_set_value(value).delegate_enqueue(&mut context) } - - #[public] - fn public_delegate_set_value(target_contract: AztecAddress, value: Field) -> Field { - DelegatedOn::at(target_contract).public_set_value(value).delegate_call(&mut context) - } - - #[private] - fn get_private_value(amount: Field, owner: AztecAddress) -> pub Field { - let mut options = NoteGetterOptions::new(); - options = options.select(ValueNote::properties().value, Comparator.EQ, amount).set_limit(1); - let notes = storage.a_map_with_private_values.at(owner).get_notes(options); - notes.get_unchecked(0).value - } - - unconstrained fn view_public_value() -> pub Field { + // #[public] + // fn public_delegate_set_value(target_contract: AztecAddress, value: Field) -> Field { + // DelegatedOn::at(target_contract).public_set_value(value).delegate_call(&mut context) + // } + // #[private] + // fn get_private_value(amount: Field, owner: AztecAddress) -> pub Field { + // let mut options = NoteGetterOptions::new(); + // options = options.select(ValueNote::properties().value, Comparator.EQ, amount).set_limit(1); + // let notes = storage.a_map_with_private_values.at(owner).get_notes(options); + // notes.get_unchecked(0).value + // } + unconstrained fn view_public_value() -> Field { storage.current_value.read() } } diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index 598d161f0c9..7ab2c232c47 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -20,8 +20,12 @@ contract DocsExample { AztecAddress, NoteViewerOptions, PrivateContext, Map, PublicMutable, PublicImmutable, PrivateMutable, PrivateImmutable, PrivateSet, SharedImmutable }; - use dep::aztec::encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note, encode_and_encrypt_note_with_keys}; - use dep::aztec::keys::getters::get_current_public_keys; + use dep::aztec::{ + encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note, encode_and_encrypt_note_with_keys}, + keys::getters::get_current_public_keys, + macros::{storage::storage, functions::{public, private, internal, view}} + }; + // how to import methods from other files/folders within your workspace use crate::types::{card_note::CardNote, leader::Leader}; @@ -37,62 +41,62 @@ contract DocsExample { // just used for docs example to show how to create a private mutable map. profiles: Map, Context>, // docs:start:storage-set-declaration - set: PrivateSet, + set: PrivateSet, // docs:end:storage-set-declaration // docs:start:storage-private-immutable-declaration - private_immutable: PrivateImmutable, + private_immutable: PrivateImmutable, // docs:end:storage-private-immutable-declaration // docs:start:storage-shared-immutable-declaration - shared_immutable: SharedImmutable, + shared_immutable: SharedImmutable, // docs:end:storage-shared-immutable-declaration // docs:start:storage-minters-declaration - minters: Map>, + minters: Map, Context>, // docs:end:storage-minters-declaration // docs:start:storage-public-immutable-declaration - public_immutable: PublicImmutable, + public_immutable: PublicImmutable, // docs:end:storage-public-immutable-declaration } // Note: The following is no longer necessary to implement manually as our macros do this for us. It is left here // for documentation purposes only. - impl Storage { - fn init(context: Context) -> Self { - Storage { - // docs:start:storage-leader-init - leader: PublicMutable::new(context, 1), - // docs:end:storage-leader-init - // docs:start:start_vars_private_mutable - legendary_card: PrivateMutable::new(context, 3), - // docs:end:start_vars_private_mutable - // just used for docs example (not for game play): - // docs:start:state_vars-MapPrivateMutable - profiles: Map::new( - context, - 4, - |context, slot| { - PrivateMutable::new(context, slot) - } - ), - // docs:end:state_vars-MapPrivateMutable - // docs:start:storage-set-init - set: PrivateSet::new(context, 5), - // docs:end:storage-set-init - private_immutable: PrivateImmutable::new(context, 6), - shared_immutable: SharedImmutable::new(context, 7), - // docs:start:storage-minters-init - minters: Map::new( - context, - 8, - |context, slot| { - PublicMutable::new(context, slot) - } - ), - // docs:end:storage-minters-init - // docs:start:storage-public-immutable - public_immutable: PublicImmutable::new(context, 9)// docs:end:storage-public-immutable - } - } - } + // impl Storage { + // fn init(context: Context) -> Self { + // Storage { + // // docs:start:storage-leader-init + // leader: PublicMutable::new(context, 1), + // // docs:end:storage-leader-init + // // docs:start:start_vars_private_mutable + // legendary_card: PrivateMutable::new(context, 3), + // // docs:end:start_vars_private_mutable + // // just used for docs example (not for game play): + // // docs:start:state_vars-MapPrivateMutable + // profiles: Map::new( + // context, + // 4, + // |context, slot| { + // PrivateMutable::new(context, slot) + // } + // ), + // // docs:end:state_vars-MapPrivateMutable + // // docs:start:storage-set-init + // set: PrivateSet::new(context, 5), + // // docs:end:storage-set-init + // private_immutable: PrivateImmutable::new(context, 6), + // shared_immutable: SharedImmutable::new(context, 7), + // // docs:start:storage-minters-init + // minters: Map::new( + // context, + // 8, + // |context, slot| { + // PublicMutable::new(context, slot) + // } + // ), + // // docs:end:storage-minters-init + // // docs:start:storage-public-immutable + // public_immutable: PublicImmutable::new(context, 9)// docs:end:storage-public-immutable + // } + // } + // } #[public] fn initialize_shared_immutable(points: u8) { @@ -110,7 +114,7 @@ contract DocsExample { } #[private] - fn get_shared_immutable_constrained_private_indirect() -> pub Leader { + fn get_shared_immutable_constrained_private_indirect() -> Leader { // This is a private function that calls another private function // and returns the response. // Used to test that we can retrieve values through calls and @@ -121,7 +125,7 @@ contract DocsExample { } #[public] - fn get_shared_immutable_constrained_public_indirect() -> pub Leader { + fn get_shared_immutable_constrained_public_indirect() -> Leader { // This is a public function that calls another public function // and returns the response. // Used to test that we can retrieve values through calls and @@ -133,23 +137,23 @@ contract DocsExample { #[public] #[view] - fn get_shared_immutable_constrained_public() -> pub Leader { + fn get_shared_immutable_constrained_public() -> Leader { storage.shared_immutable.read_public() } #[public] - fn get_shared_immutable_constrained_public_multiple() -> pub [Leader; 5] { + fn get_shared_immutable_constrained_public_multiple() -> [Leader; 5] { let a = storage.shared_immutable.read_public(); [a, a, a, a, a] } #[private] #[view] - fn get_shared_immutable_constrained_private() -> pub Leader { + fn get_shared_immutable_constrained_private() -> Leader { storage.shared_immutable.read_private() } - unconstrained fn get_shared_immutable() -> pub Leader { + unconstrained fn get_shared_immutable() -> Leader { storage.shared_immutable.read_public() } @@ -161,7 +165,7 @@ contract DocsExample { // docs:end:initialize_public_immutable } - unconstrained fn get_public_immutable() -> pub Leader { + unconstrained fn get_public_immutable() -> Leader { // docs:start:read_public_immutable storage.public_immutable.read() // docs:end:read_public_immutable @@ -204,111 +208,87 @@ contract DocsExample { ); } } - #[private] fn insert_note(amount: u8, randomness: Field) { let sender_npk_m_hash = get_current_public_keys(&mut context, context.msg_sender()).npk_m.hash(); - let mut note = CardNote::new(amount, randomness, sender_npk_m_hash); storage.set.insert(&mut note).emit(encode_and_encrypt_note(&mut context, context.msg_sender(), context.msg_sender())); } - // docs:start:state_vars-NoteGetterOptionsComparatorExampleNoir - unconstrained fn read_note(comparator: u8, amount: Field) -> pub BoundedVec { + unconstrained fn read_note(comparator: u8, amount: Field) -> BoundedVec { let mut options = NoteViewerOptions::new(); storage.set.view_notes(options.select(CardNote::properties().points, comparator, amount)) } // docs:end:state_vars-NoteGetterOptionsComparatorExampleNoir - #[private] fn update_legendary_card(randomness: Field, points: u8) { let sender_npk_m_hash = get_current_public_keys(&mut context, context.msg_sender()).npk_m.hash(); - let mut new_card = CardNote::new(points, randomness, sender_npk_m_hash); storage.legendary_card.replace(&mut new_card).emit(encode_and_encrypt_note(&mut context, context.msg_sender(), context.msg_sender())); DocsExample::at(context.this_address()).update_leader(context.msg_sender(), points).enqueue(&mut context); } - #[private] fn increase_legendary_points() { // Ensure `points` > current value // Also serves as a e2e test that you can `get_note()` and then `replace()` - let sender_npk_m_hash = get_current_public_keys(&mut context, context.msg_sender()).npk_m.hash(); - // docs:start:state_vars-PrivateMutableGet let card = storage.legendary_card.get_note().note; - // docs:end:state_vars-PrivateMutableGet - let points = card.points + 1; - let mut new_card = CardNote::new(points, card.randomness, sender_npk_m_hash); // docs:start:state_vars-PrivateMutableReplace storage.legendary_card.replace(&mut new_card).emit(encode_and_encrypt_note(&mut context, context.msg_sender(), context.msg_sender())); // docs:end:state_vars-PrivateMutableReplace - DocsExample::at(context.this_address()).update_leader(context.msg_sender(), points).enqueue(&mut context); } - #[private] #[view] fn verify_private_authwit(inner_hash: Field) -> Field { 1 } - #[public] fn spend_public_authwit(inner_hash: Field) -> Field { 1 } - #[public] #[internal] fn update_leader(account: AztecAddress, points: u8) { let new_leader = Leader { account, points }; storage.leader.write(new_leader); } - - unconstrained fn get_leader() -> pub Leader { + unconstrained fn get_leader() -> Leader { storage.leader.read() } - - unconstrained fn get_legendary_card() -> pub CardNote { + unconstrained fn get_legendary_card() -> CardNote { storage.legendary_card.view_note() } - // docs:start:private_mutable_is_initialized - unconstrained fn is_legendary_initialized() -> pub bool { + unconstrained fn is_legendary_initialized() -> bool { storage.legendary_card.is_initialized() } // docs:end:private_mutable_is_initialized - // docs:start:get_note-private-immutable #[private] fn get_imm_card() -> CardNote { storage.private_immutable.get_note() } // docs:end:get_note-private-immutable - - unconstrained fn view_imm_card() -> pub CardNote { + unconstrained fn view_imm_card() -> CardNote { storage.private_immutable.view_note() } - - unconstrained fn is_priv_imm_initialized() -> pub bool { + unconstrained fn is_priv_imm_initialized() -> bool { storage.private_immutable.is_initialized() } - /// Macro equivalence section use dep::aztec::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs; use dep::aztec::context::inputs::PrivateContextInputs; - // docs:start:simple_macro_example #[private] fn simple_macro_example(a: Field, b: Field) -> Field { a + b } // docs:end:simple_macro_example - // docs:start:simple_macro_example_expanded fn simple_macro_example_expanded( // ************************************************************ @@ -317,7 +297,6 @@ contract DocsExample { inputs: PrivateContextInputs, // docs:end:context-example-inputs // ************************************************************ - // Our original inputs! a: Field, b: Field // The actual return type of our circuit is the PrivateCircuitPublicInputs struct, this will be the @@ -332,20 +311,16 @@ contract DocsExample { args_hasher.add(a); args_hasher.add(b); // docs:end:context-example-hasher - // The context object is created with the inputs and the hash of the inputs // docs:start:context-example-context let mut context = PrivateContext::new(inputs, args_hasher.hash()); // docs:end:context-example-context - // docs:start:storage-example-context let mut storage = Storage::init(&mut context); // docs:end:storage-example-context // ************************************************************ - // Our actual program let result = a + b; - // ************************************************************ // Return values are pushed into the context // docs:start:context-example-context-return @@ -353,7 +328,6 @@ contract DocsExample { return_hasher.add(result); context.set_return_hash(return_hasher); // docs:end:context-example-context-return - // The context is returned to be consumed by the kernel circuit! // docs:start:context-example-finish context.finish() diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr index b3a56d2cbdf..b0216a98b51 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr @@ -1,4 +1,4 @@ -use crate::types::card_note::{CardNote, CARD_NOTE_LEN, CARD_NOTE_BYTES_LEN}; +use crate::types::card_note::{CARD_NOTE_LEN, CardNote}; use dep::aztec::prelude::NoteGetterOptions; use dep::aztec::protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL; @@ -10,7 +10,7 @@ use dep::aztec::{note::note_getter_options::SortOrder, utils::comparison::Compar pub fn create_npk_card_getter_options( account_npk_m_hash: Field, offset: u32 -) -> NoteGetterOptions { +) -> NoteGetterOptions { let mut options = NoteGetterOptions::new(); options.select( CardNote::properties().npk_m_hash, @@ -25,7 +25,7 @@ pub fn create_exact_card_getter_options( points: u8, secret: Field, account_npk_m_hash: Field -) -> NoteGetterOptions { +) -> NoteGetterOptions { let mut options = NoteGetterOptions::new(); options.select(CardNote::properties().points, Comparator.EQ, points as Field).select(CardNote::properties().randomness, Comparator.EQ, secret).select( CardNote::properties().npk_m_hash, @@ -53,13 +53,13 @@ pub fn filter_min_points( // docs:end:state_vars-OptionFilter // docs:start:state_vars-NoteGetterOptionsFilter -pub fn create_cards_with_min_points_getter_options(min_points: u8) -> NoteGetterOptions { +pub fn create_cards_with_min_points_getter_options(min_points: u8) -> NoteGetterOptions { NoteGetterOptions::with_filter(filter_min_points, min_points).sort(CardNote::properties().points, SortOrder.ASC) } // docs:end:state_vars-NoteGetterOptionsFilter // docs:start:state_vars-NoteGetterOptionsPickOne -pub fn create_largest_card_getter_options() -> NoteGetterOptions { +pub fn create_largest_card_getter_options() -> NoteGetterOptions { let mut options = NoteGetterOptions::new(); options.sort(CardNote::properties().points, SortOrder.DESC).set_limit(1) } diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 18ddb819354..14a11bf4d87 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -1,11 +1,13 @@ -use dep::aztec::prelude::{NullifiableNote, PrivateContext}; +use dep::aztec::prelude::{NullifiableNote, PrivateContext, NoteHeader}; use dep::aztec::{ note::{utils::compute_note_hash_for_nullify}, keys::getters::get_nsk_app, - protocol_types::{traits::Serialize, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} + protocol_types::{traits::Serialize, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, + macros::notes::note }; - // docs:start:state_vars-CardNote +global CARD_NOTE_LEN: u64 = 3; // 3 plus a header. + #[note] struct CardNote { points: u8, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index fd63fd0070c..74d50c89c16 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -21,7 +21,7 @@ pub comptime fn pack_from_fields( if replacement == quote {} { if typ.is_field() | typ.as_integer().is_some() { - result = quote { $buffer[$consumed] as Field }; + result = quote { $buffer[$consumed] as $typ }; consumed = 1; } else if typ.as_struct().is_some() { let (nested_def, _) = typ.as_struct().unwrap(); From e0853f7cb50c12546f61857f0f8865c78ea15382 Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 10:03:59 +0000 Subject: [PATCH 17/79] we have liftoff --- .../aztec-nr/address-note/src/address_note.nr | 16 +--- .../aztec-nr/aztec/src/generators.nr | 4 +- .../aztec/src/macros/functions/interfaces.nr | 51 ++++++++++ .../aztec/src/macros/functions/mod.nr | 84 ++++------------ .../aztec-nr/aztec/src/macros/mod.nr | 4 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 85 +++++++++++----- .../aztec-nr/aztec/src/macros/storage/mod.nr | 13 ++- .../aztec-nr/aztec/src/macros/utils.nr | 17 +++- .../src/main.nr | 8 +- .../docs_example_contract/src/main.nr | 78 +++++++-------- .../ecdsa_k_account_contract/src/main.nr | 2 +- .../ecdsa_public_key_note/src/lib.nr | 96 ++++++++++++++++--- .../ecdsa_r_account_contract/src/main.nr | 2 +- .../contracts/escrow_contract/src/main.nr | 2 +- .../inclusion_proofs_contract/src/main.nr | 5 +- .../key_registry_contract/src/main.nr | 3 +- .../contracts/lending_contract/src/main.nr | 2 +- .../contracts/parent_contract/src/main.nr | 24 +---- .../pending_note_hashes_contract/src/main.nr | 2 +- .../contracts/price_feed_contract/src/main.nr | 2 +- .../private_fpc_contract/src/main.nr | 6 +- .../src/public_key_note.nr | 3 +- .../src/main.nr | 2 +- .../stateful_test_contract/src/main.nr | 5 +- .../static_child_contract/src/main.nr | 5 +- .../contracts/test_contract/src/main.nr | 16 ++-- .../contracts/test_contract/src/test_note.nr | 5 +- .../contracts/test_log_contract/src/main.nr | 7 +- .../token_blacklist_contract/src/main.nr | 12 +-- .../src/types/balances_map.nr | 22 ++--- .../src/types/token_note.nr | 4 +- .../src/types/transparent_note.nr | 3 +- .../token_bridge_contract/src/main.nr | 8 +- 33 files changed, 361 insertions(+), 237 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index f83e1ef20bc..e8724d50e14 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -1,16 +1,10 @@ use dep::aztec::{ - protocol_types::{ - address::AztecAddress, traits::Empty, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator -}, - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_nullify}, - oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext + protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, + note::{note_header::NoteHeader, note_interface::NullifiableNote, utils::compute_note_hash_for_nullify}, + oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext, + macros::notes::note }; -global ADDRESS_NOTE_LEN: Field = 3; -// ADDRESS_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global ADDRESS_NOTE_BYTES_LEN: Field = 3 * 32 + 64; - // docs:start:address_note_def // docs:start:address_note_struct // Stores an address @@ -23,7 +17,7 @@ struct AddressNote { } // docs:end:address_note_struct -impl NoteInterface for AddressNote { +impl NullifiableNote for AddressNote { fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); diff --git a/noir-projects/aztec-nr/aztec/src/generators.nr b/noir-projects/aztec-nr/aztec/src/generators.nr index 0894a4f9e5d..f8cd5e08dc0 100644 --- a/noir-projects/aztec-nr/aztec/src/generators.nr +++ b/noir-projects/aztec-nr/aztec/src/generators.nr @@ -4,9 +4,9 @@ use dep::protocol_types::point::Point; global Ga1 = Point { x: 0x30426e64aee30e998c13c8ceecda3a77807dbead52bc2f3bf0eae851b4b710c1, y: 0x113156a068f603023240c96b4da5474667db3b8711c521c748212a15bc034ea6, is_infinite: false }; global Ga2 = Point { x: 0x2825c79cc6a5cbbeef7d6a8f1b6a12b312aa338440aefeb4396148c89147c049, y: 0x129bfd1da54b7062d6b544e7e36b90736350f6fba01228c41c72099509f5701e, is_infinite: false }; global Ga3 = Point { x: 0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357f, y: 0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35, is_infinite: false }; -// CREATE A NEW GENERATOR HERE +// CREATE NEW GENERATORS HERE global Ga4 = Point { x: 0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357f, y: 0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35, is_infinite: false }; - +global Ga5 = Point { x: 0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357f, y: 0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35, is_infinite: false }; // If you change this update `G_SLOT` in `yarn-project/simulator/src/client/test_utils.ts` as well global G_slot = Point { x: 0x041223147b680850dc82e8a55a952d4df20256fe0593d949a9541ca00f0abf15, y: 0x0a8c72e60d0e60f5d804549d48f3044d06140b98ed717a9b532af630c1530791, is_infinite: false }; diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr new file mode 100644 index 00000000000..f87f2e3da5d --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr @@ -0,0 +1,51 @@ +use std::{meta::type_of, collections::umap::UHashMap, hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher}}; + +comptime mut global STUBS: UHashMap> = UHashMap::default(); + +pub(crate) comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { + let name = f.name(); + // Remove first arg (inputs) + let mut parameters = f.parameters().map( + | (name, typ): (Quoted, Type) | { + quote { $name: $typ } + } + ).join(quote{,}); + + let parameters_struct_name = f"{name}_parameters".quoted_contents(); + let parameters = quote { + struct $parameters_struct_name { + $parameters + } + }; + + let return_value_type = f.return_type(); + let return_type = if return_value_type != type_of(()) { + quote { return_type: $return_value_type } + } else { + quote {} + }; + + let abi_struct_name = f"{name}_abi".quoted_contents(); + + let result = quote { + + $parameters + + #[abi(functions)] + struct $abi_struct_name { + parameters: $parameters_struct_name, + $return_type + } + }; + result +} + +pub(crate) comptime fn register_stub(m: Module, stub: Quoted) { + let current_stubs = STUBS.get(m); + let stubs_to_insert = if current_stubs.is_some() { + current_stubs.unwrap().push_back(stub) + } else { + &[stub] + }; + STUBS.insert(m, stubs_to_insert); +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 0c47455206d..c7f889c8d51 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -1,16 +1,15 @@ -use std::{ - meta::{type_of, unquote}, collections::umap::UHashMap, - hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} -}; +mod interfaces; + +use std::meta::{type_of, unquote}; use super::utils::{ modify_fn_body, is_fn_private, get_fn_visibility, is_fn_view, is_fn_initializer, is_fn_internal, fn_has_noinitcheck, compute_fn_selector, add_to_field_slice, add_to_hasher, is_fn_public, module_has_storage, module_has_initializer }; -comptime mut global STUBS: UHashMap> = UHashMap::default(); +use interfaces::{create_fn_abi_export, register_stub}; -// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] +// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] pub comptime fn internal(_f: FunctionDefinition) {} comptime fn create_internal_check(f: FunctionDefinition) -> Quoted { @@ -19,7 +18,7 @@ comptime fn create_internal_check(f: FunctionDefinition) -> Quoted { quote { assert(context.msg_sender() == context.this_address(), $assertion_message); } } -// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] +// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] pub comptime fn view(_f: FunctionDefinition) {} comptime fn create_view_check(f: FunctionDefinition) -> Quoted { @@ -32,9 +31,12 @@ comptime fn create_view_check(f: FunctionDefinition) -> Quoted { } } -// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] +// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] pub comptime fn initializer(_f: FunctionDefinition) {} +// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] +pub comptime fn noinitcheck(_f: FunctionDefinition) {} + comptime fn create_assert_initializer(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); f"dep::aztec::initializer::assert_initialization_matches_address_preimage_{fn_visibility}(context);".quoted_contents() @@ -50,56 +52,6 @@ comptime fn create_mark_as_initialized(f: FunctionDefinition) -> Quoted { f"dep::aztec::initializer::mark_as_initialized_{fn_visibility}(&mut context);".quoted_contents() } -comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { - let name = f.name(); - // Remove first arg (inputs) - let mut parameters = f.parameters().map( - | (name, typ): (Quoted, Type) | { - quote { $name: $typ } - } - ).join(quote{,}); - - let parameters_struct_name = f"{name}_parameters".quoted_contents(); - let parameters = quote { - struct $parameters_struct_name { - $parameters - } - }; - - let return_value_type = f.return_type(); - let return_type = if return_value_type != type_of(()) { - quote { return_type: $return_value_type } - } else { - quote {} - }; - - let abi_struct_name = f"{name}_abi".quoted_contents(); - - let result = quote { - - $parameters - - #[abi(functions)] - struct $abi_struct_name { - parameters: $parameters_struct_name, - $return_type - } - }; - result -} - -comptime fn register_stub(m: Module, stub: Quoted) { - let current_stubs = unsafe { - STUBS.get(m) - }; - let stubs_to_insert = if current_stubs.is_some() { - current_stubs.unwrap().push_back(stub) - } else { - &[stub] - }; - STUBS.insert(m, stubs_to_insert); -} - pub comptime fn private(f: FunctionDefinition) -> Quoted { let fn_abi = create_fn_abi_export(f); let fn_stub = stub_fn(f); @@ -158,12 +110,14 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { }; let return_value_var_name = quote { macro__returned__values }; - let (body_without_return, last_body_expr) = body.pop_back(); let return_value_type = f.return_type(); - let return_value = if return_value_type != type_of(()) { + let return_value = if body.len() == 0 { + quote {} + } else if return_value_type != type_of(()) { + let (body_without_return, last_body_expr) = body.pop_back(); let return_value = last_body_expr.quoted(); - let return_value_assignment = quote { let $return_value_var_name = $return_value; }; + let return_value_assignment = quote { let $return_value_var_name: $return_value_type = $return_value; }; let return_hasher_name = quote { return_hasher }; let return_value_into_hasher = add_to_hasher(return_hasher_name, return_value_var_name, return_value_type); @@ -176,13 +130,15 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { context.set_return_hash($return_hasher_name); } } else { + let (body_without_return, last_body_expr) = body.pop_back(); if !last_body_expr.has_semicolon() & last_body_expr.as_for().is_none() & last_body_expr.as_assert().is_none() - & last_body_expr.as_for_range().is_none() { - println("wtf"); + & last_body_expr.as_for_range().is_none() + & last_body_expr.as_assert_eq().is_none() + & last_body_expr.as_let().is_none() { let unused_return_value_name = f"_{return_value_var_name}".quoted_contents(); - body = body.pop_back().0.push_back(quote { let $unused_return_value_name = $last_body_expr; }.as_expr().unwrap()); + body = body_without_return.push_back(quote { let $unused_return_value_name = $last_body_expr; }.as_expr().unwrap()); } quote {} }; diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 7598ba953f5..833c8c892bb 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -4,7 +4,7 @@ mod notes; mod storage; mod events; -use functions::STUBS; +use functions::interfaces::STUBS; use storage::STORAGE_LAYOUT_NAME; use notes::{NOTES, generate_note_export}; @@ -21,7 +21,7 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { }; let has_storage = module_has_storage(m); - let storage_layout_getter = if has_storage { + let storage_layout_getter = if has_storage & STORAGE_LAYOUT_NAME.get(m).is_some() { let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap(); quote { pub fn storage_layout() -> StorageLayout { diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index f187bc80529..ec32991c4c8 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -3,8 +3,11 @@ use std::{ hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} }; use protocol_types::{meta::flatten_to_fields, utils::field::field_from_bytes}; -use crate::note::{note_header::NoteHeader, note_getter_options::PropertySelector}; +use crate::note::{note_header::NoteHeader, note_getter_options::PropertySelector, note_interface::NoteInterface}; use protocol_types::meta::pack_from_fields; +use std::meta::typ::fresh_type_variable; + +comptime global NOTE_HEADER_TYPE = type_of(NoteHeader::empty()); comptime mut global NOTES: UHashMap> = UHashMap::default(); @@ -28,10 +31,11 @@ comptime fn compute_note_type_id(name: Quoted) -> Field { comptime fn generate_note_interface( s: StructDefinition, + note_type_id: Field, hiding_point_name: Quoted, fixed_fields: [(Quoted, Type)], nullable_fields: [Quoted] -) -> (Quoted, u32, Field) { +) -> (Quoted, u32) { let name = s.name(); let typ = s.as_type(); let (fields, aux_vars) = flatten_to_fields(quote { self }, typ, &[quote {self.header}]); @@ -44,8 +48,6 @@ comptime fn generate_note_interface( let serialized_fields = fields.join(quote {,}); let content_len = fields.len(); - let note_header_type = quote { crate::note::note_header::NoteHeader}.as_type(); - let (deserialized_content, _) = pack_from_fields( quote { self }, typ, @@ -54,7 +56,6 @@ comptime fn generate_note_interface( &[(quote {header}, quote { NoteHeader::empty() })] ); - let note_type_id = compute_note_type_id(name); let fixed_fields_args = fixed_fields.map(| (name, _): (Quoted, Type) | quote{self.$name}).push_back(quote {self.get_header().storage_slot}).join(quote {,}); let nullable_fields_args = nullable_fields.map(|field| quote { self.$field }).join(quote {,}); @@ -95,11 +96,11 @@ comptime fn generate_note_interface( $note_type_id } - fn set_header(&mut self, header: $note_header_type) { + fn set_header(&mut self, header: $NOTE_HEADER_TYPE) { self.header = header; } - fn get_header(self) -> $note_header_type { + fn get_header(self) -> $NOTE_HEADER_TYPE { self.header } @@ -107,7 +108,7 @@ comptime fn generate_note_interface( $hiding_point_name::new($fixed_fields_args).finalize($nullable_fields_args) } } - }, content_len, note_type_id) + }, content_len) } comptime fn generate_note_properties(s: StructDefinition) -> Quoted { @@ -332,42 +333,80 @@ comptime fn register_note(note: StructDefinition, note_serialized_len: u32, note NOTES.insert(note.module(), notes_to_insert); } -comptime fn common_note_annotation(s: StructDefinition, nullable_fields: [Quoted]) -> (Quoted, Quoted) { +comptime fn extract_fixed_fields(s: StructDefinition, nullable_fields: [Quoted]) -> [(Quoted, Type)] { + s.fields().filter( + | (name, typ): (Quoted, Type) | (typ != NOTE_HEADER_TYPE) & nullable_fields.all(| field | field != name) + ) +} + +comptime fn common_note_annotation( + s: StructDefinition, + fixed_fields: [(Quoted, Type)], + nullable_fields: [Quoted] +) -> (Quoted, Quoted, Field) { // Automatically inject header if not present - let note_header_type = type_of(NoteHeader::empty()); - let filtered_header = s.fields().filter(| (_, typ): (Quoted, Type) | typ == note_header_type); + let filtered_header = s.fields().filter(| (_, typ): (Quoted, Type) | typ == NOTE_HEADER_TYPE); if (filtered_header.len() == 0) { - let new_fields = s.fields().push_back((quote { header }, note_header_type)); + let new_fields = s.fields().push_back((quote { header }, NOTE_HEADER_TYPE)); s.set_fields(new_fields); } - let fixed_fields = s.fields().filter( - | (name, typ): (Quoted, Type) | (typ != note_header_type) & nullable_fields.all(| field | field != name) - ); let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, fixed_fields, nullable_fields); - let (note_interface_impl, note_serialized_len, note_type_id) = generate_note_interface(s, hiding_point_name, fixed_fields, nullable_fields); let note_properties = generate_note_properties(s); - - register_note(s, note_serialized_len, note_type_id); + let note_type_id = compute_note_type_id(s.name()); (quote { - $note_interface_impl $note_properties $note_hiding_point - }, hiding_point_name) + }, hiding_point_name, note_type_id) } #[varargs] pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { - let (common, hiding_point_name) = common_note_annotation(s, nullable_fields); + let fixed_fields = extract_fixed_fields(s, nullable_fields); + let (common, hiding_point_name, note_type_id) = common_note_annotation(s, fixed_fields, nullable_fields); + let (note_interface_impl, note_serialized_len) = generate_note_interface( + s, + note_type_id, + hiding_point_name, + fixed_fields, + nullable_fields + ); let partial_note_impl = generate_partial_note_impl(s, hiding_point_name); + register_note(s, note_serialized_len, note_type_id); quote { $common + $note_interface_impl $partial_note_impl } } pub comptime fn note(s: StructDefinition) -> Quoted { - let (common, _) = common_note_annotation(s, &[]); - common + let fixed_fields = extract_fixed_fields(s, &[]); + let (common, hiding_point_name, note_type_id) = common_note_annotation(s, fixed_fields, &[]); + let (note_interface_impl, note_serialized_len) = generate_note_interface(s, note_type_id, hiding_point_name, fixed_fields, &[]); + register_note(s, note_serialized_len, note_type_id); + + quote { + $common + $note_interface_impl + } +} + +pub comptime fn note_custom_interface(s: StructDefinition) -> Quoted { + let fixed_fields = extract_fixed_fields(s, &[]); + let (common, _, note_type_id) = common_note_annotation(s, fixed_fields, &[]); + + let serialized_len_type = fresh_type_variable(); + let note_interface_impl = s.as_type().get_trait_impl(quote { NoteInterface<$serialized_len_type> }.as_trait_constraint()); + let name = s.name(); + assert(note_interface_impl.is_some(), f"Note {name} must implement NoteInterface trait"); + + let note_serialized_len = note_interface_impl.unwrap().trait_generic_args()[0].as_constant().unwrap(); + + register_note(s, note_serialized_len, note_type_id); + + quote { + $common + } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index 8da08e35a21..d8975588dff 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -4,6 +4,7 @@ use std::{ }; use super::utils::get_serialized_size; +use super::utils::is_note; comptime mut global STORAGE_LAYOUT_NAME: UHashMap> = UHashMap::default(); @@ -42,14 +43,8 @@ pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, pare 1 } else { let stored_struct = container_struct_generics[0]; - let is_note = if stored_struct.as_struct().is_some() { - let (def, _) = stored_struct.as_struct().unwrap(); - def.has_named_attribute("note") - } else { - false - }; // Private notes always occupy a single slot. Someone could store a Note in PublicMutable for whatever reason though. - if is_note & (container_struct_name != quote { PublicMutable }) { + if is_note(stored_struct) & (container_struct_name != quote { PublicMutable }) { 1 } else { get_serialized_size(stored_struct) @@ -79,6 +74,9 @@ comptime fn add_context_generic(typ: Type, context_generic: Type) -> Type { } } +// Just to make sure the contract is marked as having storage +pub comptime fn storage_no_init(_s: StructDefinition) {} + pub comptime fn storage(s: StructDefinition) -> Quoted { let mut slot: u32 = 1; let mut storage_vars_constructors = &[]; @@ -132,3 +130,4 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { }; } } + diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index f4936a39d28..13d270f3b09 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -86,6 +86,7 @@ pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quo }; let body_expr = body_quote.as_expr(); assert(body_expr.is_some(), f"Body is not an expression: {body_quote}"); + println(body_expr.unwrap()); body_expr.unwrap() } @@ -251,9 +252,23 @@ pub(crate) comptime fn get_serialized_size(typ: Type) -> u32 { } pub(crate) comptime fn module_has_storage(m: Module) -> bool { - m.structs().any(|s: StructDefinition| s.has_named_attribute("storage")) + m.structs().any( + |s: StructDefinition| s.has_named_attribute("storage") | s.has_named_attribute("storage_no_init") + ) } pub(crate) comptime fn module_has_initializer(m: Module) -> bool { m.functions().any(|f: FunctionDefinition| is_fn_initializer(f)) } + +pub(crate) comptime fn is_note(typ: Type) -> bool { + typ.as_struct().map_or( + false, + | struc: (StructDefinition, [Type]) | { + let (def, _) = struc; + def.has_named_attribute("note") + | def.has_named_attribute("partial_note") + | def.has_named_attribute("note_custom_interface") + } + ) +} diff --git a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr index ce4c3641daf..b14d4188713 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -4,9 +4,13 @@ use dep::aztec::macros::aztec; contract ContractInstanceDeployer { use dep::aztec::protocol_types::{ address::{AztecAddress, PublicKeysHash, PartialAddress}, contract_class_id::ContractClassId, - constants::DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE, abis::log_hash::LogHash, traits::Serialize + constants::DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE, abis::log_hash::LogHash, + traits::Serialize + }; + use dep::aztec::{ + hash::compute_unencrypted_log_hash, oracle::logs::emit_unencrypted_log_private_internal, + macros::{events::event, functions::private} }; - use dep::aztec::{hash::compute_unencrypted_log_hash, oracle::logs::emit_unencrypted_log_private_internal, macros::{events::event, functions::private }}; use std::meta::derive; #[event] diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index 7ab2c232c47..b63920f658e 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -29,7 +29,7 @@ contract DocsExample { // how to import methods from other files/folders within your workspace use crate::types::{card_note::CardNote, leader::Leader}; - #[storage] + #[storage_no_init] struct Storage { // Shows how to create a custom struct in PublicMutable // docs:start:storage-leader-declaration @@ -59,44 +59,44 @@ contract DocsExample { // Note: The following is no longer necessary to implement manually as our macros do this for us. It is left here // for documentation purposes only. - // impl Storage { - // fn init(context: Context) -> Self { - // Storage { - // // docs:start:storage-leader-init - // leader: PublicMutable::new(context, 1), - // // docs:end:storage-leader-init - // // docs:start:start_vars_private_mutable - // legendary_card: PrivateMutable::new(context, 3), - // // docs:end:start_vars_private_mutable - // // just used for docs example (not for game play): - // // docs:start:state_vars-MapPrivateMutable - // profiles: Map::new( - // context, - // 4, - // |context, slot| { - // PrivateMutable::new(context, slot) - // } - // ), - // // docs:end:state_vars-MapPrivateMutable - // // docs:start:storage-set-init - // set: PrivateSet::new(context, 5), - // // docs:end:storage-set-init - // private_immutable: PrivateImmutable::new(context, 6), - // shared_immutable: SharedImmutable::new(context, 7), - // // docs:start:storage-minters-init - // minters: Map::new( - // context, - // 8, - // |context, slot| { - // PublicMutable::new(context, slot) - // } - // ), - // // docs:end:storage-minters-init - // // docs:start:storage-public-immutable - // public_immutable: PublicImmutable::new(context, 9)// docs:end:storage-public-immutable - // } - // } - // } + impl Storage { + fn init(context: Context) -> Self { + Storage { + // docs:start:storage-leader-init + leader: PublicMutable::new(context, 1), + // docs:end:storage-leader-init + // docs:start:start_vars_private_mutable + legendary_card: PrivateMutable::new(context, 3), + // docs:end:start_vars_private_mutable + // just used for docs example (not for game play): + // docs:start:state_vars-MapPrivateMutable + profiles: Map::new( + context, + 4, + |context, slot| { + PrivateMutable::new(context, slot) + } + ), + // docs:end:state_vars-MapPrivateMutable + // docs:start:storage-set-init + set: PrivateSet::new(context, 5), + // docs:end:storage-set-init + private_immutable: PrivateImmutable::new(context, 6), + shared_immutable: SharedImmutable::new(context, 7), + // docs:start:storage-minters-init + minters: Map::new( + context, + 8, + |context, slot| { + PublicMutable::new(context, slot) + } + ), + // docs:end:storage-minters-init + // docs:start:storage-public-immutable + public_immutable: PublicImmutable::new(context, 9)// docs:end:storage-public-immutable + } + } + } #[public] fn initialize_shared_immutable(points: u8) { diff --git a/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr index 920f5a5303f..7b12098a5be 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr @@ -8,7 +8,7 @@ contract EcdsaKAccount { use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, keys::getters::get_current_public_keys, - macros::{storage::storage, functions::{private, initializer, view, noinitcheck}}, + macros::{storage::storage, functions::{private, initializer, view, noinitcheck}} }; use dep::authwit::{ diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index 0d2c577f677..19270ec8846 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -1,17 +1,21 @@ -use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteInterface, NoteGetterOptions, PrivateContext}; +use dep::aztec::prelude::{NoteHeader, NoteInterface, NullifiableNote, PrivateContext}; use dep::aztec::{ note::utils::compute_note_hash_for_nullify, keys::getters::get_nsk_app, - protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} + protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, + macros::notes::note_custom_interface, generators::Ga1 as Gx_1, generators::Ga2 as Gx_2, + generators::Ga3 as Gy_1, generators::Ga4 as Gy_2, generators::Ga5 as Gnpk_m_hash, generators::G_slot }; +use std::hash::from_field_unsafe; + global ECDSA_PUBLIC_KEY_NOTE_LEN: Field = 5; // ECDSA_PUBLIC_KEY_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) global ECDSA_PUBLIC_KEY_NOTE_BYTES_LEN: Field = 5 * 32 + 64; // Stores an ECDSA public key composed of two 32-byte elements // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? -#[note] +#[note_custom_interface] struct EcdsaPublicKeyNote { x: [u8; 32], y: [u8; 32], @@ -19,7 +23,7 @@ struct EcdsaPublicKeyNote { npk_m_hash: Field, } -impl NullifiableNote for EcdsaPublicKeyNote { +impl NoteInterface for EcdsaPublicKeyNote { // Cannot use the automatic serialization since x and y don't fit. Serialize the note as 5 fields where: // [0] = x[0..31] (upper bound excluded) // [1] = x[31] @@ -32,11 +36,11 @@ impl NullifiableNote for EcdsaPublicKeyNote { let mut mul: Field = 1; for i in 1..32 { - let byte_x: Field = self.x[31 - i] as Field; - x = x + (byte_x * mul); - let byte_y: Field = self.y[31 - i] as Field; - y = y + (byte_y * mul); - mul *= 256; + let byte_x: Field = self.x[31 - i] as Field; + x = x + (byte_x * mul); + let byte_y: Field = self.y[31 - i] as Field; + y = y + (byte_y * mul); + mul *= 256; } let last_x = self.x[31] as Field; @@ -65,24 +69,88 @@ impl NullifiableNote for EcdsaPublicKeyNote { EcdsaPublicKeyNote { x, y, npk_m_hash: serialized_note[4], header: NoteHeader::empty() } } + fn to_be_bytes(self, storage_slot: Field) -> [u8; ECDSA_PUBLIC_KEY_NOTE_LEN * 32 + 64] { + let serialized_note = self.serialize_content(); + + let mut buffer: [u8; ECDSA_PUBLIC_KEY_NOTE_LEN * 32 + 64] = [0; ECDSA_PUBLIC_KEY_NOTE_LEN * 32 + 64]; + + let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); + let note_type_id_bytes: [u8; 32] = EcdsaPublicKeyNote::get_note_type_id().to_be_bytes(); + + for i in 0..32 { + buffer[i] = storage_slot_bytes[i]; + buffer[32 + i] = note_type_id_bytes[i]; + } + + for i in 0..serialized_note.len() { + let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); + for j in 0..32 { + buffer[64 + i * 32 + j] = bytes[j]; + } + } + buffer + } + + fn get_note_type_id() -> Field { + comptime + { + let bytes = "EcdsaPublicKeyNote".as_bytes(); + let hash = std::hash::keccak256(bytes, bytes.len() as u32); + let mut selector_be_bytes = [0; 4]; + for i in 0..4 { + selector_be_bytes[i] = hash[i]; + } + + aztec::protocol_types::utils::field::field_from_bytes(selector_be_bytes, true) + } + } + + fn get_header(self) -> NoteHeader { + self.header + } + + fn set_header(&mut self, header: NoteHeader) { + self.header = header; + } + + fn compute_note_hash(self) -> Field { + let serialized = self.serialize_content(); + std::embedded_curve_ops::multi_scalar_mul( + [Gx_1, Gx_2, Gy_1, Gy_2, Gnpk_m_hash, G_slot], + [ + from_field_unsafe(serialized[0]), + from_field_unsafe(serialized[1]), + from_field_unsafe(serialized[2]), + from_field_unsafe(serialized[3]), + from_field_unsafe(serialized[4]), + from_field_unsafe(self.get_header().storage_slot) + ] + ).x + } +} + +impl NullifiableNote for EcdsaPublicKeyNote { + fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash_with_separator([ + poseidon2_hash_with_separator( + [ note_hash_for_nullify, secret ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, + GENERATOR_INDEX__NOTE_NULLIFIER as Field ) } fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_nullify(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash_with_separator([ + poseidon2_hash_with_separator( + [ note_hash_for_nullify, - secret, + secret ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, + GENERATOR_INDEX__NOTE_NULLIFIER as Field ) } } diff --git a/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr index 307a9ca506b..9b2d185f600 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr @@ -7,7 +7,7 @@ contract EcdsaRAccount { use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, keys::getters::get_current_public_keys, - macros::{storage::storage, functions::{private, initializer, view, noinitcheck}}, + macros::{storage::storage, functions::{private, initializer, view, noinitcheck}} }; use dep::authwit::{ diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index c283dd12237..91becd58ad1 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -7,7 +7,7 @@ contract Escrow { use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, keys::getters::get_current_public_keys, - macros::{storage::storage, functions::{private, initializer}}, + macros::{storage::storage, functions::{private, initializer}} }; // docs:start:addressnote_import diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index adcbd993abf..713e77b9cea 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -9,7 +9,10 @@ contract InclusionProofs { keys::getters::get_current_public_keys }; - use dep::aztec::{note::note_getter_options::NoteStatus, macros::{storage::storage, functions::{private, public, initializer}}}; + use dep::aztec::{ + note::note_getter_options::NoteStatus, + macros::{storage::storage, functions::{private, public, initializer}} + }; // docs:start:value_note_imports use dep::value_note::value_note::ValueNote; // docs:end:value_note_imports diff --git a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr index 911aa1d5522..8824fd8ac5b 100644 --- a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr @@ -9,8 +9,9 @@ contract KeyRegistry { state_vars::{PublicMutable, Map}, protocol_types::address::{AztecAddress, PartialAddress}, macros::{storage::storage, functions::public} }; + use aztec::macros::storage::storage_no_init; - #[storage] + #[storage_no_init] struct Storage { current_keys: Map, Context>, } diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index b0e0469acee..66d2af3a916 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -271,7 +271,7 @@ contract Lending { #[public] #[view] - fn get_asset(asset_id: Field) -> pub Asset { + fn get_asset(asset_id: Field) -> Asset { storage.assets.at(asset_id).read() } diff --git a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr index b5df22e44c2..ac1526eca14 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr @@ -12,7 +12,6 @@ contract Parent { // Call the target private function context.call_private_function(target_contract, target_selector, [0]).unpack_into() } - // Public function to directly call another public function to the target_contract using the selector and value provided #[public] fn pub_entry_point( @@ -27,7 +26,6 @@ contract Parent { GasOpts::default() ).deserialize_into() } - // Same as pub_entry_point, but calls the target contract twice, using the return value from the first invocation as the argument for the second. #[public] fn pub_entry_point_twice( @@ -48,7 +46,6 @@ contract Parent { GasOpts::default() ).deserialize_into() } - // Private function to enqueue a call to the target_contract address using the selector and argument provided #[private] fn enqueue_call_to_child( @@ -58,7 +55,6 @@ contract Parent { ) { context.call_public_function(target_contract, target_selector, [target_value]); } - // Private function that enqueues two calls to a child contract: // - one through a nested call to enqueue_call_to_child with value 10, // - followed by one issued directly from this function with value 20. @@ -77,7 +73,6 @@ contract Parent { ); context.call_public_function(target_contract, target_selector, [20]); } - // Private function that enqueues two calls to a child contract: // - one issued directly from this function with value 20, // - followed by one through a nested call to enqueue_call_to_child with value 10. @@ -96,7 +91,6 @@ contract Parent { [target_contract.to_field(), target_selector.to_field(), 10] ); } - // Private function to enqueue a call to the target_contract address using the selector and argument provided #[private] fn enqueue_call_to_child_twice( @@ -109,7 +103,6 @@ contract Parent { // Enqueue the second public call context.call_public_function(target_contract, target_selector, [target_value + 1]); } - // Private function to enqueue a call to the pub_entry_point function of this same contract, passing the target arguments provided #[private] fn enqueue_call_to_pub_entry_point( @@ -127,7 +120,6 @@ contract Parent { [target_contract.to_field(), target_selector.to_field(), target_value] ); } - // Private function to enqueue two calls to the pub_entry_point function of this same contract, passing the target arguments provided #[private] fn enqueue_calls_to_pub_entry_point( @@ -139,20 +131,17 @@ contract Parent { FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)") }; let this_address = context.this_address(); - context.call_public_function( this_address, pub_entry_point_selector, [target_contract.to_field(), target_selector.to_field(), target_value] ); - context.call_public_function( this_address, pub_entry_point_selector, [target_contract.to_field(), target_selector.to_field(), target_value + 1] ); } - #[private] fn private_static_call( target_contract: AztecAddress, @@ -162,7 +151,6 @@ contract Parent { // Call the target private function context.static_call_private_function(target_contract, target_selector, args).unpack_into() } - #[private] fn private_call( target_contract: AztecAddress, @@ -172,7 +160,6 @@ contract Parent { // Call the target private function context.call_private_function(target_contract, target_selector, args).unpack_into() } - // Private function to set a static context and verify correct propagation for nested private calls #[private] fn private_nested_static_call( @@ -188,11 +175,9 @@ contract Parent { private_call_selector, [target_contract.to_field(), target_selector.to_field(), args[0], args[1]] ).unpack_into(); - // Copy the return value from the call to this function's return values return_value } - // Public function to directly call another public function to the target_contract using the selector and value provided #[public] fn public_static_call( @@ -207,7 +192,6 @@ contract Parent { GasOpts::default() ).deserialize_into() } - // Public function to set a static context and verify correct propagation for nested public calls #[public] fn public_nested_static_call( @@ -225,7 +209,6 @@ contract Parent { GasOpts::default() ).deserialize_into() } - // Private function to enqueue a static call to the pub_entry_point function of another contract, passing the target arguments provided #[private] fn enqueue_static_nested_call_to_pub_function( @@ -242,7 +225,6 @@ contract Parent { [target_contract.to_field(), target_selector.to_field(), args[0]] ); } - // Private function to enqueue a static call to the pub_entry_point function of another contract, passing the target arguments provided #[private] fn enqueue_static_call_to_pub_function( @@ -253,25 +235,21 @@ contract Parent { // Call the target private function context.static_call_public_function(target_contract, target_selector, args); } - use dep::aztec::test::{helpers::{cheatcodes, test_environment::TestEnvironment}}; use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map; use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes}; use dep::aztec::note::note_viewer_options::NoteViewerOptions; use dep::child_contract::Child; use dep::value_note::value_note::ValueNote; - #[test] fn test_private_call() { // Setup env, generate keys let mut env = TestEnvironment::new(); let owner = env.create_account(); - // Deploy child contract let child_contract = env.deploy("./@child_contract", "Child").without_initializer(); let child_contract_address = child_contract.to_address(); cheatcodes::advance_blocks_by(1); - // Set value in child through parent let value_to_set = 7; let parent_private_set_call_interface = Parent::interface().private_call( @@ -285,7 +263,7 @@ contract Parent { assert(result == value_to_set); // Read the stored value in the note. We have to change the contract address to the child contract in order to read its notes env.impersonate(child_contract_address); - let counter_slot = Child::storage().a_map_with_private_values.slot; + let counter_slot = Child::storage_layout().a_map_with_private_values.slot; let owner_slot = derive_storage_slot_in_map(counter_slot, owner); let mut options = NoteViewerOptions::new(); let notes: BoundedVec = view_notes(owner_slot, options); diff --git a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr index e1b87cf1715..2ccadae7199 100644 --- a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr @@ -16,7 +16,7 @@ contract PendingNoteHashes { use dep::aztec::macros::{storage::storage, functions::private}; #[storage] - struct Storage { balances: Map, Context>, } diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index 40485f87919..f360c87ad74 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -4,7 +4,7 @@ use dep::aztec::macros::aztec; #[aztec] contract PriceFeed { - use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext, Map, PublicMutable}; + use dep::aztec::prelude::{Map, PublicMutable}; use crate::asset::Asset; use dep::aztec::macros::{storage::storage, functions::{public, view}}; diff --git a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr index 80234d2c04f..8a5a42f0a20 100644 --- a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr @@ -4,7 +4,11 @@ use dep::aztec::macros::aztec; #[aztec] contract PrivateFPC { - use dep::aztec::{protocol_types::{address::AztecAddress, hash::compute_siloed_nullifier}, state_vars::SharedImmutable, macros::{storage::storage, functions::{private, initializer, public}}}; + use dep::aztec::{ + protocol_types::{address::AztecAddress, hash::compute_siloed_nullifier}, + state_vars::SharedImmutable, + macros::{storage::storage, functions::{private, initializer, public}} + }; use dep::token::Token; use crate::settings::Settings; diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index d070b413b6b..49e4a1f3916 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -1,7 +1,8 @@ use dep::aztec::prelude::{NoteHeader, NullifiableNote, PrivateContext}; use dep::aztec::{ note::utils::compute_note_hash_for_nullify, keys::getters::get_nsk_app, - protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} + protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, + macros::notes::note }; // Stores a public key composed of two fields diff --git a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index cfe370fba5f..f61dea42972 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -10,7 +10,7 @@ contract SchnorrHardcodedAccount { auth_witness::get_auth_witness }; - use dep::aztec::macros::{functions::{private, initializer, view}}; + use dep::aztec::macros::{functions::{private, view}}; global public_key_x: Field = 0x16b93f4afae55cab8507baeb8e7ab4de80f5ab1e9e1f5149bf8cd0d375451d90; global public_key_y: Field = 0x208d44b36eb6e73b254921134d002da1a90b41131024e3b1d721259182106205; diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index 2a99ac707c7..fd229a997d6 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -5,7 +5,10 @@ use dep::aztec::macros::aztec; contract StatefulTest { use dep::aztec::prelude::{Map, PublicMutable, PrivateSet, AztecAddress, FunctionSelector}; use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::ValueNote}; - use dep::aztec::{initializer::assert_is_initialized_private, macros::{storage::storage, functions::{private, public, initializer, noinitcheck, view}}; + use dep::aztec::{ + initializer::assert_is_initialized_private, + macros::{storage::storage, functions::{private, public, initializer, noinitcheck, view}} + }; #[storage] struct Storage { diff --git a/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr index 00ab4557fd2..f2cbf66bd91 100644 --- a/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr @@ -3,11 +3,10 @@ use dep::aztec::macros::aztec; #[aztec] contract StaticChild { - use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize}; + use dep::aztec::prelude::{AztecAddress, PublicMutable, PrivateSet}; use dep::aztec::{ - context::{PublicContext, gas::GasOpts}, protocol_types::{abis::{call_context::CallContext}}, - note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, + note::{note_getter_options::NoteGetterOptions}, encrypted_logs::encrypted_note_emission::encode_and_encrypt_note, keys::getters::get_current_public_keys, utils::comparison::Comparator, macros::{storage::storage, functions::{private, public, view}} diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 41456a8b39e..4f0e789dd63 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -37,15 +37,19 @@ contract Test { note_getter_options::NoteStatus }, deploy::deploy_contract as aztec_deploy_contract, - oracle::{encryption::aes128_encrypt, unsafe_rand::unsafe_rand}, utils::comparison::Comparator + oracle::{encryption::aes128_encrypt, unsafe_rand::unsafe_rand}, utils::comparison::Comparator, + macros::{storage::storage, events::event, functions::{private, public, internal}} }; use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash}; use dep::value_note::value_note::ValueNote; - use std::embedded_curve_ops::fixed_base_scalar_mul as derive_public_key; + // TODO investigate why the macros require EmbeddableCurvePoint and EmbeddableCurveScalar + use std::embedded_curve_ops::{EmbeddedCurveScalar, EmbeddedCurvePoint, fixed_base_scalar_mul as derive_public_key}; + use std::meta::derive; use crate::test_note::TestNote; #[event] + #[derive(Serialize)] struct ExampleEvent { value0: Field, value1: Field, @@ -55,7 +59,7 @@ contract Test { } #[storage] - struct Storage { example_constant: PrivateImmutable, example_set: PrivateSet, } @@ -378,11 +382,7 @@ contract Test { } #[private] - fn consume_message_from_arbitrary_sender_private( - content: Field, - secret: Field, - sender: EthAddress - ) { + fn consume_message_from_arbitrary_sender_private(content: Field, secret: Field, sender: EthAddress) { // Consume message and emit nullifier context.consume_l1_to_l2_message(content, secret, sender); } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr index 37f37648f5f..2adc5bf355a 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr @@ -1,4 +1,7 @@ -use dep::aztec::{note::{note_header::NoteHeader, note_interface::NullifiableNote}, context::PrivateContext}; +use dep::aztec::{ + note::{note_header::NoteHeader, note_interface::NullifiableNote}, context::PrivateContext, + macros::notes::note +}; // A note which stores a field and is expected to be passed around using the `addNote` function. // WARNING: This Note is not private as it does not contain randomness and hence it can be easy to perform diff --git a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr index 9dba8913cca..d3c6e29746d 100644 --- a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr @@ -2,8 +2,9 @@ use dep::aztec::macros::aztec; #[aztec] contract TestLog { + use std::meta::derive; use dep::aztec::prelude::PrivateSet; - use dep::aztec::protocol_types::{scalar::Scalar, address::AztecAddress}; + use dep::aztec::protocol_types::{scalar::Scalar, address::AztecAddress, traits::Serialize}; use dep::aztec::keys::public_keys::IvpkM; use dep::value_note::value_note::ValueNote; use dep::aztec::encrypted_logs::incoming_body::EncryptedLogIncomingBody; @@ -11,13 +12,17 @@ contract TestLog { use dep::aztec::unencrypted_logs::unencrypted_event_emission::encode_event; use dep::aztec::macros::{storage::storage, events::event, functions::{private, public}}; + use std::embedded_curve_ops::EmbeddedCurveScalar; + #[event] + #[derive(Serialize)] struct ExampleEvent0 { value0: Field, value1: Field, } #[event] + #[derive(Serialize)] struct ExampleEvent1 { value2: AztecAddress, value3: u8, diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 58d421b2cce..4926b3803cf 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -28,12 +28,12 @@ contract TokenBlacklist { global CHANGE_ROLES_DELAY_BLOCKS = 2; #[storage] - struct Storage { - balances: BalancesMap, - total_supply: PublicMutable, - pending_shields: PrivateSet, - public_balances: Map>, - roles: Map>, + struct Storage { + balances: BalancesMap, + total_supply: PublicMutable, + pending_shields: PrivateSet, + public_balances: Map, Context>, + roles: Map, Context>, } // docs:start:constructor diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index d0aeac1b7cf..f0649e364b7 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -1,4 +1,4 @@ -use dep::aztec::prelude::{AztecAddress, NoteGetterOptions, NoteViewerOptions, NoteInterface, PrivateSet, Map}; +use dep::aztec::prelude::{AztecAddress, NoteGetterOptions, NoteViewerOptions, NoteInterface, NullifiableNote, PrivateSet, Map}; use dep::aztec::{ context::{PrivateContext, UnconstrainedContext}, protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, @@ -24,18 +24,18 @@ impl BalancesMap { } impl BalancesMap { - unconstrained pub fn balance_of( + unconstrained pub fn balance_of( self: Self, owner: AztecAddress - ) -> U128 where T: NoteInterface + OwnedNote { + ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { self.balance_of_with_offset(owner, 0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, owner: AztecAddress, offset: u32 - ) -> U128 where T: NoteInterface + OwnedNote { + ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { let mut balance = U128::from_integer(0); // docs:start:view_notes let mut options = NoteViewerOptions::new(); @@ -55,11 +55,11 @@ impl BalancesMap { } impl BalancesMap { - pub fn add( + pub fn add( self: Self, owner: AztecAddress, addend: U128 - ) -> OuterNoteEmission where T: NoteInterface + OwnedNote + Eq { + ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + OwnedNote + Eq { if addend == U128::from_integer(0) { OuterNoteEmission::new(Option::none()) } else { @@ -75,11 +75,11 @@ impl BalancesMap { } } - pub fn sub( + pub fn sub( self: Self, owner: AztecAddress, subtrahend: U128 - ) -> OuterNoteEmission where T: NoteInterface + OwnedNote + Eq { + ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + OwnedNote + Eq { let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend); let notes = self.map.at(owner).pop_notes(options); @@ -100,10 +100,10 @@ impl BalancesMap { } } -pub fn filter_notes_min_sum( +pub fn filter_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 -) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(0); for i in 0..notes.len() { diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index b8ff087f3c1..c51c49ed4a4 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, note::utils::compute_note_hash_for_nullify, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app + keys::getters::get_nsk_app, macros::notes::partial_note }; trait OwnedNote { @@ -10,7 +10,7 @@ trait OwnedNote { fn get_amount(self) -> U128; } -#[note] +#[partial_note(quote {amount})] struct TokenNote { // The amount of tokens in the note amount: U128, diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index e8c6fe754b7..12af4d24966 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -2,7 +2,8 @@ use dep::aztec::{ note::{note_getter_options::PropertySelector, utils::compute_note_hash_for_nullify}, prelude::{NoteHeader, NullifiableNote, PrivateContext}, - protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} + protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, + macros::notes::note }; // Transparent note represents a note that is created in the clear (public execution), but can only be spent by those diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index bf1d2a64b66..0e19f1e3265 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -9,7 +9,7 @@ use dep::aztec::macros::aztec; #[aztec] contract TokenBridge { - use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, PublicMutable, SharedImmutable}; + use dep::aztec::prelude::{AztecAddress, EthAddress, PublicMutable, SharedImmutable}; use dep::token_portal_content_hash_lib::{get_mint_public_content_hash, get_mint_private_content_hash, get_withdraw_content_hash}; @@ -21,9 +21,9 @@ contract TokenBridge { // docs:start:token_bridge_storage_and_constructor // Storage structure, containing all storage, and specifying what slots they use. #[storage] - struct Storage { - token: PublicMutable, - portal_address: SharedImmutable, + struct Storage { + token: PublicMutable, + portal_address: SharedImmutable, } // Constructs the contract. From b8e5d80cbfdfa51bd8f2bcd4063ffab52c1f9ada Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 10:04:58 +0000 Subject: [PATCH 18/79] fmt --- .../noir-contracts/contracts/uniswap_contract/src/main.nr | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr index 66b5f4f60b9..0b1aeb7cd55 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -156,11 +156,7 @@ contract Uniswap { // this method is used for both private and public swaps. #[public] #[internal] - fn _approve_bridge_and_exit_input_asset_to_L1( - token: AztecAddress, - token_bridge: AztecAddress, - amount: Field - ) { + fn _approve_bridge_and_exit_input_asset_to_L1(token: AztecAddress, token_bridge: AztecAddress, amount: Field) { // Since we will authorize and instantly spend the funds, all in public, we can use the same nonce // every interaction. In practice, the authwit should be squashed, so this is also cheap! let nonce = 0xdeadbeef; From 5cff536cadc4cbb37560dbb0e2779b2117c50455 Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 10:12:40 +0000 Subject: [PATCH 19/79] removed log line --- noir-projects/aztec-nr/aztec/src/macros/utils.nr | 1 - 1 file changed, 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 13d270f3b09..1afa4cdbfff 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -86,7 +86,6 @@ pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quo }; let body_expr = body_quote.as_expr(); assert(body_expr.is_some(), f"Body is not an expression: {body_quote}"); - println(body_expr.unwrap()); body_expr.unwrap() } From 8424bfb5993ea81baab7f3920396a705e832ad7c Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 11:35:02 +0000 Subject: [PATCH 20/79] macro intensifies --- .../aztec/src/history/note_inclusion.nr | 4 +- .../aztec/src/history/note_validity.nr | 4 +- .../src/history/nullifier_non_inclusion.nr | 4 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 45 +++---- .../contracts/nft_contract/src/main.nr | 113 ++++++++++-------- .../src/test/transfer_to_private.nr | 2 +- .../contracts/nft_contract/src/test/utils.nr | 4 +- .../nft_contract/src/types/nft_note.nr | 83 +------------ .../contracts/spam_contract/src/main.nr | 20 ++-- .../spam_contract/src/types/balance_set.nr | 24 ++-- .../spam_contract/src/types/token_note.nr | 77 +----------- .../contracts/token_contract/src/main.nr | 4 +- 12 files changed, 129 insertions(+), 255 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index 3a0564e088a..2fc06caf198 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -7,11 +7,11 @@ use crate::{ }; trait ProveNoteInclusion { - fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote; + fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote; } impl ProveNoteInclusion for Header { - fn prove_note_inclusion( + fn prove_note_inclusion( self, note: Note ) where Note: NoteInterface + NullifiableNote { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr index d3d820510f1..48461295d67 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr @@ -3,11 +3,11 @@ use crate::{context::PrivateContext, note::note_interface::{NoteInterface, Nulli use dep::protocol_types::header::Header; trait ProveNoteValidity { - fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; + fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteValidity for Header { - fn prove_note_validity( + fn prove_note_validity( self, note: Note, context: &mut PrivateContext diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index d4d378f716a..70ba7c44caf 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -42,12 +42,12 @@ impl ProveNullifierNonInclusion for Header { } trait ProveNoteNotNullified { - fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; + fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteNotNullified for Header { // docs:start:prove_note_not_nullified - fn prove_note_not_nullified( + fn prove_note_not_nullified( self, note: Note, context: &mut PrivateContext diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index ec32991c4c8..42932749d99 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -105,7 +105,7 @@ comptime fn generate_note_interface( } fn compute_note_hash(self) -> Field { - $hiding_point_name::new($fixed_fields_args).finalize($nullable_fields_args) + $hiding_point_name::empty().new($fixed_fields_args).finalize($nullable_fields_args) } } }, content_len) @@ -173,7 +173,7 @@ comptime fn generate_note_hiding_point( let mut new_generators_list = &[]; let mut new_scalars_list = &[]; - let mut new_args_list = &[]; + let mut new_args_list = &[quote {mut self}]; let mut new_generics_list = &[]; let mut new_trait_bounds_list = &[]; @@ -258,45 +258,27 @@ comptime fn generate_note_hiding_point( quote {} }; - let initialize_args = if new_args_list.len() > 0 { - &[quote {mut self}].append(new_args_list).join(quote {,}) - } else { - quote {mut self} - }; - (quote { struct $hiding_point_name { inner: aztec::protocol_types::point::Point } impl $hiding_point_name { - - fn empty() -> $hiding_point_name { - $hiding_point_name { inner: aztec::protocol_types::point::Point::empty() } - } - fn new$new_generics($new_args) -> $hiding_point_name $new_trait_bounds { let point = std::embedded_curve_ops::multi_scalar_mul( [$new_generators], [$new_scalars] ); - $hiding_point_name { inner: point } - } - - fn from_point(mut self, point: aztec::protocol_types::point::Point) -> $hiding_point_name { self.inner = point; self } - fn initialize$new_generics($initialize_args) -> $hiding_point_name $new_trait_bounds { - let point = std::embedded_curve_ops::multi_scalar_mul( - [$new_generators], - [$new_scalars] - ); + fn from_point(mut self, point: aztec::protocol_types::point::Point) -> $hiding_point_name { self.inner = point; self } + fn $finalize_name($finalize_args) -> Field $finalize_trait_bounds { $finalize_body } @@ -307,6 +289,25 @@ comptime fn generate_note_hiding_point( self.inner.serialize() } } + + impl aztec::protocol_types::traits::Deserialize for $hiding_point_name { + fn deserialize(serialized: [Field; aztec::protocol_types::point::POINT_LENGTH]) -> $hiding_point_name { + $hiding_point_name { inner: aztec::protocol_types::point::Point::deserialize(serialized) } + } + } + + impl aztec::protocol_types::traits::Empty for $hiding_point_name { + fn empty() -> Self { + Self { inner: aztec::protocol_types::point::Point::empty() } + } + } + + impl Eq for $hiding_point_name { + fn eq(self, other: Self) -> bool { + self.inner == other.inner + } + } + }, hiding_point_name) } diff --git a/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr b/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr index dc11a6861c4..2cc53f8dd63 100644 --- a/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr @@ -1,8 +1,11 @@ mod types; mod test; +use dep::aztec::macros::aztec; + // Minimal NFT implementation with `AuthWit` support that allows minting in public-only and transfers in both public // and private. +#[aztec] contract NFT { use dep::compressed_string::FieldCompressedString; use dep::aztec::{ @@ -10,42 +13,45 @@ contract NFT { encrypted_logs::{encrypted_note_emission::encode_and_encrypt_note_with_keys}, hash::pedersen_hash, keys::getters::get_current_public_keys, note::constants::MAX_NOTES_PER_PAGE, protocol_types::traits::is_empty, - utils::comparison::Comparator + utils::comparison::Comparator, protocol_types::{point::Point, traits::Serialize}, + macros::{storage::storage, events::event, functions::{private, public, view, internal, initializer}} }; use dep::authwit::auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public, compute_authwit_nullifier}; - use crate::types::nft_note::{NFTNote, NFTNoteHidingPoint}; + use std::{embedded_curve_ops::EmbeddedCurvePoint, meta::derive}; + use crate::types::nft_note::NFTNote; global TRANSIENT_STORAGE_SLOT_PEDERSEN_INDEX = 3; // TODO(#8467): Rename this to Transfer - calling this NFTTransfer to avoid export conflict with the Transfer event // in the Token contract. - #[aztec(event)] + #[event] + #[derive(Serialize)] struct NFTTransfer { from: AztecAddress, to: AztecAddress, token_id: Field, } - #[aztec(storage)] - struct Storage { + #[storage] + struct Storage { // The symbol of the NFT - symbol: SharedImmutable, + symbol: SharedImmutable, // The name of the NFT - name: SharedImmutable, + name: SharedImmutable, // The admin of the contract - admin: PublicMutable, + admin: PublicMutable, // Addresses that can mint - minters: Map>, + minters: Map, Context>, // Contains the NFTs owned by each address in private. - private_nfts: Map>, + private_nfts: Map, Context>, // A map from token ID to a boolean indicating if the NFT exists. - nft_exists: Map>, + nft_exists: Map, Context>, // A map from token ID to the public owner of the NFT. - public_owners: Map>, + public_owners: Map, Context>, } - #[aztec(public)] - #[aztec(initializer)] + #[public] + #[initializer] fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>) { assert(!admin.is_zero(), "invalid admin"); storage.admin.write(admin); @@ -54,19 +60,19 @@ contract NFT { storage.symbol.initialize(FieldCompressedString::from_string(symbol)); } - #[aztec(public)] + #[public] fn set_admin(new_admin: AztecAddress) { assert(storage.admin.read().eq(context.msg_sender()), "caller is not an admin"); storage.admin.write(new_admin); } - #[aztec(public)] + #[public] fn set_minter(minter: AztecAddress, approve: bool) { assert(storage.admin.read().eq(context.msg_sender()), "caller is not an admin"); storage.minters.at(minter).write(approve); } - #[aztec(public)] + #[public] fn mint(to: AztecAddress, token_id: Field) { assert(token_id != 0, "zero token ID not supported"); assert(storage.minters.at(context.msg_sender()).read(), "caller is not a minter"); @@ -77,43 +83,43 @@ contract NFT { storage.public_owners.at(token_id).write(to); } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn public_get_name() -> pub FieldCompressedString { storage.name.read_public() } - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn private_get_name() -> pub FieldCompressedString { storage.name.read_private() } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn public_get_symbol() -> pub FieldCompressedString { storage.symbol.read_public() } - #[aztec(private)] - #[aztec(view)] + #[private] + #[view] fn private_get_symbol() -> pub FieldCompressedString { storage.symbol.read_private() } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn get_admin() -> Field { storage.admin.read().to_field() } - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn is_minter(minter: AztecAddress) -> bool { storage.minters.at(minter).read() } - #[aztec(public)] + #[public] fn transfer_in_public(from: AztecAddress, to: AztecAddress, token_id: Field, nonce: Field) { if (!from.eq(context.msg_sender())) { assert_current_call_valid_authwit_public(&mut context, from); @@ -133,7 +139,7 @@ contract NFT { /// as an argument to the followup call to `finalize_transfer_to_private`. // TODO(#8238): Remove the `note_randomness` argument below once we have partial notes delivery (then we can just // fetch the randomness from oracle). - #[aztec(private)] + #[private] fn prepare_transfer_to_private( from: AztecAddress, to: AztecAddress, @@ -143,7 +149,7 @@ contract NFT { // We create a partial NFT note hiding point with unpopulated/zero token id for 'to' let to_npk_m_hash = get_current_public_keys(&mut context, to).npk_m.hash(); let to_note_slot = storage.private_nfts.at(to).storage_slot; - let hiding_point = NFTNoteHidingPoint::new(to_npk_m_hash, to_note_slot, note_randomness); + let hiding_point = NFTNote::hiding_point().new(to_npk_m_hash, note_randomness, to_note_slot); // We make the msg_sender/transfer_preparer part of the slot preimage to ensure he cannot interfere with // non-sender's slots @@ -158,12 +164,12 @@ contract NFT { TRANSIENT_STORAGE_SLOT_PEDERSEN_INDEX ); - NFT::at(context.this_address())._store_point_in_transient_storage(hiding_point, slot).enqueue(&mut context); + NFT::at(context.this_address())._store_point_in_transient_storage(hiding_point.inner, slot).enqueue(&mut context); } - #[aztec(public)] - #[aztec(internal)] - fn _store_point_in_transient_storage(point: NFTNoteHidingPoint, slot: Field) { + #[public] + #[internal] + fn _store_point_in_transient_storage(point: Point, slot: Field) { // We don't perform check for the overwritten value to be non-zero because the slots are siloed to `to` // and hence `to` can interfere only with his own execution. context.storage_write(slot, point); @@ -173,8 +179,11 @@ contract NFT { /// The transfer must be prepared by calling `prepare_transfer_to_private` first. /// The `transfer_preparer_storage_slot_commitment` has to be computed off-chain the same way as was done /// in the preparation call. - #[aztec(public)] - fn finalize_transfer_to_private(token_id: Field, transfer_preparer_storage_slot_commitment: Field) { + #[public] + fn finalize_transfer_to_private( + token_id: Field, + transfer_preparer_storage_slot_commitment: Field + ) { // We don't need to support authwit here because `prepare_transfer_to_private` allows us to set arbitrary // `from` and `from` will always be the msg sender here. let from = context.msg_sender(); @@ -189,7 +198,7 @@ contract NFT { ); // Read the hiding point from "transient" storage and check it's not empty to ensure the transfer was prepared - let mut hiding_point: NFTNoteHidingPoint = context.storage_read(hiding_point_slot); + let mut hiding_point = NFTNote::hiding_point().from_point(context.storage_read(hiding_point_slot)); assert(!is_empty(hiding_point), "transfer not prepared"); // Set the public NFT owner to zero @@ -201,21 +210,24 @@ contract NFT { // At last we reset public storage to zero to achieve the effect of transient storage - kernels will squash // the writes - context.storage_write(hiding_point_slot, NFTNoteHidingPoint::empty()); + context.storage_write( + hiding_point_slot, + NFTNote::hiding_point().from_point(Point::empty()) + ); } /** * Cancel a private authentication witness. * @param inner_hash The inner hash of the authwit to cancel. */ - #[aztec(private)] + #[private] fn cancel_authwit(inner_hash: Field) { let on_behalf_of = context.msg_sender(); let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash); context.push_nullifier(nullifier); } - #[aztec(private)] + #[private] fn transfer_in_private(from: AztecAddress, to: AztecAddress, token_id: Field, nonce: Field) { if (!from.eq(context.msg_sender())) { assert_current_call_valid_authwit(&mut context, from); @@ -233,11 +245,11 @@ contract NFT { let from_ovpk_m = get_current_public_keys(&mut context, from).ovpk_m; let to_keys = get_current_public_keys(&mut context, to); - let new_note = NFTNote::new(token_id, to_keys.npk_m.hash()); + let mut new_note = NFTNote::new(token_id, to_keys.npk_m.hash()); nfts.at(to).insert(&mut new_note).emit(encode_and_encrypt_note_with_keys(&mut context, from_ovpk_m, to_keys.ivpk_m, to)); } - #[aztec(private)] + #[private] fn transfer_to_public(from: AztecAddress, to: AztecAddress, token_id: Field, nonce: Field) { if (!from.eq(context.msg_sender())) { assert_current_call_valid_authwit(&mut context, from); @@ -253,15 +265,15 @@ contract NFT { NFT::at(context.this_address())._finish_transfer_to_public(to, token_id).enqueue(&mut context); } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn _finish_transfer_to_public(to: AztecAddress, token_id: Field) { storage.public_owners.at(token_id).write(to); } // Returns zero address when the token does not have a public owner. Reverts if the token does not exist. - #[aztec(public)] - #[aztec(view)] + #[public] + #[view] fn owner_of(token_id: Field) -> AztecAddress { assert(storage.nft_exists.at(token_id).read(), "token does not exist"); storage.public_owners.at(token_id).read() @@ -270,10 +282,7 @@ contract NFT { /// Returns an array of token IDs owned by `owner` in private and a flag indicating whether a page limit was /// reached. Starts getting the notes from page with index `page_index`. Zero values in the array are placeholder /// values for non-existing notes. - unconstrained fn get_private_nfts( - owner: AztecAddress, - page_index: u32 - ) -> pub ([Field; MAX_NOTES_PER_PAGE], bool) { + unconstrained fn get_private_nfts(owner: AztecAddress, page_index: u32) -> pub ([Field; MAX_NOTES_PER_PAGE], bool) { let offset = page_index * MAX_NOTES_PER_PAGE; let mut options = NoteViewerOptions::new(); let notes = storage.private_nfts.at(owner).view_notes(options.set_offset(offset)); diff --git a/noir-projects/noir-contracts/contracts/nft_contract/src/test/transfer_to_private.nr b/noir-projects/noir-contracts/contracts/nft_contract/src/test/transfer_to_private.nr index 6b1db2c5f68..4e1f42f4fba 100644 --- a/noir-projects/noir-contracts/contracts/nft_contract/src/test/transfer_to_private.nr +++ b/noir-projects/noir-contracts/contracts/nft_contract/src/test/transfer_to_private.nr @@ -51,7 +51,7 @@ unconstrained fn transfer_to_private_to_a_different_account() { // Store the finalized note in the cache let mut context = env.private(); let recipient_npk_m_hash = get_current_public_keys(&mut context, recipient).npk_m.hash(); - let private_nfts_recipient_slot = derive_storage_slot_in_map(NFT::storage().private_nfts.slot, recipient); + let private_nfts_recipient_slot = derive_storage_slot_in_map(NFT::storage_layout().private_nfts.slot, recipient); env.add_note( &mut NFTNote { token_id, npk_m_hash: recipient_npk_m_hash, randomness: note_randomness, header: NoteHeader::empty() }, diff --git a/noir-projects/noir-contracts/contracts/nft_contract/src/test/utils.nr b/noir-projects/noir-contracts/contracts/nft_contract/src/test/utils.nr index 48487f1179f..c8a79bbb33c 100644 --- a/noir-projects/noir-contracts/contracts/nft_contract/src/test/utils.nr +++ b/noir-projects/noir-contracts/contracts/nft_contract/src/test/utils.nr @@ -73,7 +73,7 @@ pub fn setup_mint_and_transfer_to_private(with_account_contracts: bool) -> (&mut // Store the finalized note in the cache let mut context = env.private(); let owner_npk_m_hash = get_current_public_keys(&mut context, owner).npk_m.hash(); - let private_nfts_owner_slot = derive_storage_slot_in_map(NFT::storage().private_nfts.slot, owner); + let private_nfts_owner_slot = derive_storage_slot_in_map(NFT::storage_layout().private_nfts.slot, owner); env.add_note( &mut NFTNote { @@ -94,7 +94,7 @@ pub fn get_nft_exists(nft_contract_address: AztecAddress, token_id: Field) -> bo cheatcodes::set_contract_address(nft_contract_address); let block_number = get_block_number(); - let nft_exists_slot = NFT::storage().nft_exists.slot; + let nft_exists_slot = NFT::storage_layout().nft_exists.slot; let nft_slot = derive_storage_slot_in_map(nft_exists_slot, token_id); let exists: bool = storage_read(nft_contract_address, nft_slot, block_number); cheatcodes::set_contract_address(current_contract_address); diff --git a/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr b/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr index cce6812150b..2d982a55ea7 100644 --- a/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr +++ b/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr @@ -1,20 +1,11 @@ use dep::aztec::{ - generators::{Ga1 as G_tid, Ga2 as G_npk, Ga3 as G_rnd, G_slot}, note::utils::compute_note_hash_for_nullify, keys::getters::get_nsk_app, - oracle::unsafe_rand::unsafe_rand, - prelude::{AztecAddress, NoteInterface, NoteHeader, PrivateContext}, - protocol_types::{ - constants::GENERATOR_INDEX__NOTE_NULLIFIER, point::{Point, POINT_LENGTH}, - hash::poseidon2_hash_with_separator, traits::{Empty, Eq, Deserialize, Serialize} -} + oracle::unsafe_rand::unsafe_rand, prelude::{NullifiableNote, NoteHeader, PrivateContext}, + protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator, traits::{Empty, Eq}}, + macros::notes::partial_note }; -use std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; - -global NFT_NOTE_LEN: Field = 3; -// NFT_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global NFT_NOTE_BYTES_LEN: Field = 3 * 32 + 64; -#[aztec(note)] +#[partial_note(quote { token_id})] struct NFTNote { // ID of the token token_id: Field, @@ -24,7 +15,7 @@ struct NFTNote { randomness: Field, } -impl NoteInterface for NFTNote { +impl NullifiableNote for NFTNote { fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); poseidon2_hash_with_separator( @@ -47,19 +38,6 @@ impl NoteInterface for NFTNote { GENERATOR_INDEX__NOTE_NULLIFIER as Field ) } - - fn compute_note_hiding_point(self) -> Point { - // We use the unsafe version because `multi_scalar_mul` will constrain the scalars. - let token_id_scalar = from_field_unsafe(self.token_id); - let npk_m_hash_scalar = from_field_unsafe(self.npk_m_hash); - let randomness_scalar = from_field_unsafe(self.randomness); - let slot_scalar = from_field_unsafe(self.header.storage_slot); - - multi_scalar_mul( - [G_tid, G_npk, G_rnd, G_slot], - [token_id_scalar, npk_m_hash_scalar, randomness_scalar, slot_scalar] - ) - } } impl NFTNote { @@ -78,54 +56,3 @@ impl Eq for NFTNote { & (self.randomness == other.randomness) } } - -// TODO(#8290): Auto-generate this -struct NFTNoteHidingPoint { - inner: Point -} - -impl NFTNoteHidingPoint { - // TODO(#8238): Remove the randomness argument below - fn new(npk_m_hash: Field, storage_slot: Field, randomness: Field) -> Self { - // TODO(#8238): And uncomment this - // let randomness = unsafe { - // unsafe_rand() - // }; - let note = NFTNote { - header: NoteHeader { contract_address: AztecAddress::zero(), nonce: 0, storage_slot, note_hash_counter: 0 }, - token_id: 0, - npk_m_hash, - randomness - }; - Self { inner: note.compute_note_hiding_point() } - } - - fn finalize(self, token_id: Field) -> Field { - let finalized_hiding_point = multi_scalar_mul([G_tid], [from_field_unsafe(token_id)]) + self.inner; - finalized_hiding_point.x - } -} - -impl Serialize for NFTNoteHidingPoint { - fn serialize(self) -> [Field; POINT_LENGTH] { - self.inner.serialize() - } -} - -impl Deserialize for NFTNoteHidingPoint { - fn deserialize(serialized: [Field; POINT_LENGTH]) -> NFTNoteHidingPoint { - NFTNoteHidingPoint { inner: Point::deserialize(serialized) } - } -} - -impl Empty for NFTNoteHidingPoint { - fn empty() -> Self { - Self { inner: Point::empty() } - } -} - -impl Eq for NFTNoteHidingPoint { - fn eq(self, other: Self) -> bool { - self.inner == other.inner - } -} diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/main.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/main.nr index 9ee7bb6502c..259c65f1c6c 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/main.nr @@ -1,6 +1,9 @@ mod types; +use dep::aztec::macros::aztec; + // A contract used for testing a random hodgepodge of small features from simulator and end-to-end tests. +#[aztec] contract Spam { use dep::aztec::{ @@ -13,18 +16,19 @@ contract Spam { MAX_NOTE_HASHES_PER_CALL, MAX_NULLIFIERS_PER_CALL, GENERATOR_INDEX__NOTE_NULLIFIER, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL } - } + }, + macros::{storage::storage, functions::{private, public, internal}} }; use crate::types::{token_note::TokenNote, balance_set::BalanceSet}; - #[aztec(storage)] - struct Storage { - balances: Map>, - public_balances: Map>, + #[storage] + struct Storage { + balances: Map, Context>, + public_balances: Map, Context>, } - #[aztec(private)] + #[private] fn spam(nullifier_seed: Field, nullifier_count: u32, call_public: bool) { let caller = context.msg_sender(); let caller_keys = get_current_public_keys(&mut context, caller); @@ -56,8 +60,8 @@ contract Spam { } } - #[aztec(public)] - #[aztec(internal)] + #[public] + #[internal] fn public_spam(start: u32, end: u32) { let one = U128::from_integer(1); for i in start..end { diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr index a513efc713c..69cb4a14334 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr @@ -1,5 +1,5 @@ // This file is copied from the token contract. -use dep::aztec::prelude::{NoteGetterOptions, NoteViewerOptions, NoteInterface, PrivateSet}; +use dep::aztec::prelude::{NoteGetterOptions, NoteViewerOptions, NoteInterface, NullifiableNote, PrivateSet}; use dep::aztec::{ context::{PrivateContext, UnconstrainedContext}, protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, @@ -19,14 +19,14 @@ impl BalanceSet { } impl BalanceSet { - unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { self.balance_of_with_offset(0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, offset: u32 - ) -> U128 where T: NoteInterface + OwnedNote { + ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { let mut balance = U128::from_integer(0); // docs:start:view_notes let mut options = NoteViewerOptions::new(); @@ -46,11 +46,11 @@ impl BalanceSet { } impl BalanceSet { - pub fn add( + pub fn add( self: Self, owner_npk_m: NpkM, addend: U128 - ) -> OuterNoteEmission where T: NoteInterface + OwnedNote + Eq { + ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + OwnedNote + Eq { if addend == U128::from_integer(0) { OuterNoteEmission::new(Option::none()) } else { @@ -63,11 +63,11 @@ impl BalanceSet { } } - pub fn sub( + pub fn sub( self: Self, owner_npk_m: NpkM, amount: U128 - ) -> OuterNoteEmission where T: NoteInterface + OwnedNote + Eq { + ) -> OuterNoteEmission where T: NoteInterface + NullifiableNote + OwnedNote + Eq { let subtracted = self.try_sub(amount, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL); // try_sub may have substracted more or less than amount. We must ensure that we subtracted at least as much as @@ -85,11 +85,11 @@ impl BalanceSet { // The `max_notes` parameter is used to fine-tune the number of constraints created by this function. The gate count // scales relatively linearly with `max_notes`, but a lower `max_notes` parameter increases the likelihood of // `try_sub` subtracting an amount smaller than `target_amount`. - pub fn try_sub( + pub fn try_sub( self: Self, target_amount: U128, max_notes: u32 - ) -> U128 where T: NoteInterface + OwnedNote + Eq { + ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote + Eq { // We are using a preprocessor here (filter applied in an unconstrained context) instead of a filter because // we do not need to prove correct execution of the preprocessor. // Because the `min_sum` notes is not constrained, users could choose to e.g. not call it. However, all this @@ -115,10 +115,10 @@ impl BalanceSet { // The preprocessor (a filter applied in an unconstrained context) does not check if total sum is larger or equal to // 'min_sum' - all it does is remove extra notes if it does reach that value. // Note that proper usage of this preprocessor requires for notes to be sorted in descending order. -pub fn preprocess_notes_min_sum( +pub fn preprocess_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 -) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + NullifiableNote + OwnedNote { let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(0); for i in 0..notes.len() { diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr index 8840d245b5d..8badd035cd9 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr @@ -1,25 +1,20 @@ use dep::aztec::{ - generators::{Ga1 as G_amt, Ga2 as G_npk, Ga3 as G_rnd, G_slot}, - prelude::{NoteHeader, NoteInterface, PrivateContext}, + prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{ constants::GENERATOR_INDEX__NOTE_NULLIFIER, point::{Point, POINT_LENGTH}, hash::poseidon2_hash_with_separator, traits::Serialize }, note::utils::compute_note_hash_for_nullify, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app + keys::getters::get_nsk_app, + macros::notes::partial_note }; -use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; trait OwnedNote { fn new(amount: U128, owner_npk_m_hash: Field) -> Self; fn get_amount(self) -> U128; } - -global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. -global TOKEN_NOTE_BYTES_LEN: Field = 3 * 32 + 64; - // docs:start:TokenNote -#[aztec(note)] +#[partial_note(quote { amount })] struct TokenNote { // The amount of tokens in the note amount: U128, @@ -30,7 +25,7 @@ struct TokenNote { } // docs:end:TokenNote -impl NoteInterface for TokenNote { +impl NullifiableNote for TokenNote { // docs:start:nullifier fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); @@ -52,68 +47,6 @@ impl NoteInterface for TokenNote { GENERATOR_INDEX__NOTE_NULLIFIER ) } - - // docs:start:compute_note_hiding_point - fn compute_note_hiding_point(self) -> Point { - // We use the unsafe version because the multi_scalar_mul will constrain the scalars. - let amount_scalar = from_field_unsafe(self.amount.to_integer()); - let npk_m_hash_scalar = from_field_unsafe(self.npk_m_hash); - let randomness_scalar = from_field_unsafe(self.randomness); - let slot_scalar = from_field_unsafe(self.header.storage_slot); - // We compute the note hiding point as: - // `G_amt * amount + G_npk * npk_m_hash + G_rnd * randomness + G_slot * slot` - // instead of using pedersen or poseidon2 because it allows us to privately add and subtract from amount - // in public by leveraging homomorphism. - multi_scalar_mul( - [G_amt, G_npk, G_rnd, G_slot], - [amount_scalar, npk_m_hash_scalar, randomness_scalar, slot_scalar] - ) - } - // docs:end:compute_note_hiding_point -} - -impl TokenNote { - // TODO: Merge this func with `compute_note_hiding_point`. I (benesjan) didn't do it in the initial PR to not have - // to modify macros and all the related funcs in it. - fn to_note_hiding_point(self) -> TokenNoteHidingPoint { - TokenNoteHidingPoint::new(self.compute_note_hiding_point()) - } -} - -struct TokenNoteHidingPoint { - inner: Point -} - -impl TokenNoteHidingPoint { - fn new(point: Point) -> Self { - Self { inner: point } - } - - fn add_amount(&mut self, amount: U128) { - self.inner = multi_scalar_mul([G_amt], [from_field_unsafe(amount.to_integer())]) + self.inner; - } - - fn add_npk_m_hash(&mut self, npk_m_hash: Field) { - self.inner = multi_scalar_mul([G_npk], [from_field_unsafe(npk_m_hash)]) + self.inner; - } - - fn add_randomness(&mut self, randomness: Field) { - self.inner = multi_scalar_mul([G_rnd], [from_field_unsafe(randomness)]) + self.inner; - } - - fn add_slot(&mut self, slot: Field) { - self.inner = multi_scalar_mul([G_slot], [from_field_unsafe(slot)]) + self.inner; - } - - fn finalize(self) -> Field { - self.inner.x - } -} - -impl Serialize for TokenNoteHidingPoint { - fn serialize(self) -> [Field; POINT_LENGTH] { - self.inner.serialize() - } } impl Eq for TokenNote { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 91d539e6f2e..16d8097470f 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -485,12 +485,12 @@ contract Token { encode_and_encrypt_note_with_keys_unconstrained(&mut context, user_keys.ovpk_m, user_keys.ivpk_m, user) ); // 4. Now we get the note hiding points. - let mut fee_payer_point = TokenNote::hiding_point().initialize( + let mut fee_payer_point = TokenNote::hiding_point().new( fee_payer_npk_m_hash, fee_payer_randomness, storage.balances.at(fee_payer).set.storage_slot ); - let mut user_point = TokenNote::hiding_point().initialize( + let mut user_point = TokenNote::hiding_point().new( user_npk_m_hash, user_randomness, storage.balances.at(user).set.storage_slot From 450bb83eb1c39cfcebd41e50caf8f3d3665a93a4 Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 14:44:41 +0000 Subject: [PATCH 21/79] bootstrapin --- .../aztec/src/macros/functions/mod.nr | 1 + .../aztec-nr/aztec/src/macros/mod.nr | 48 +++++++++---------- .../aztec-nr/aztec/src/macros/notes/mod.nr | 12 +---- .../spam_contract/src/types/token_note.nr | 3 +- .../types/src/abi/contract_artifact.ts | 12 +---- yarn-project/types/src/noir/index.ts | 12 ++--- 6 files changed, 33 insertions(+), 55 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index c7f889c8d51..04eb2aa20c4 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -68,6 +68,7 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { ].append(current_params) ); let mut body = f.body().as_block().unwrap(); + // TODO: Optimize args_hasher for small number of arguments let args_hasher_name = quote { args_hasher }; let args_hasher = current_params.fold( quote { diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 833c8c892bb..6be7ad39763 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -80,19 +80,17 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { } pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier(m: Module) -> Quoted { - let contract_notes = NOTES.get(m); let mut max_note_length: u32 = 0; - let empty_body = quote { - assert(false, "This contract does not use private notes"); - [0, 0, 0, 0] - }; - let body = if contract_notes.is_none() { - empty_body - } else if contract_notes.unwrap().len() == 0 { // no short circuiting :( - empty_body - } else { - let notes = contract_notes.unwrap(); - + let note_types = NOTES.keys(); + let use_statements = note_types.map( + | typ: Type | { + quote { + use $typ; + } + } + ).join(quote {}); + let notes = NOTES.values(); + let body = if notes.len() > 0 { max_note_length = notes.fold(0, | acc, (_, len, _): (StructDefinition, u32, Field) | { acc + len }); @@ -100,7 +98,7 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier(m: Module) | (note, _, _): (StructDefinition, u32, Field) | { let note_name = note.name(); quote { - if note_type_id == $note_name::get_note_type_id() { + if note_type_id == $note_name::get_note_type_id(); { aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($note_name::deserialize_content, note_header, compute_nullifier, serialized_note) } } @@ -115,9 +113,16 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier(m: Module) [0, 0, 0, 0] } } + } else { + quote { + assert(false, "No notes defined"); + [0, 0, 0, 0] + } }; quote { + $use_statements + unconstrained fn compute_note_hash_and_optionally_a_nullifier( contract_address: aztec::protocol_types::address::AztecAddress, nonce: Field, @@ -132,21 +137,12 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier(m: Module) } pub comptime fn generate_note_exports(m: Module) -> Quoted { - let contract_notes = NOTES.get(m); - let note_exports = if contract_notes.is_some() { - let notes = contract_notes.unwrap(); - notes.map( - | (s, _, note_type_id): (StructDefinition, u32, Field) | { + let notes = NOTES.values(); + notes.map( + | (s, _, note_type_id): (StructDefinition, u32, Field) | { generate_note_export(s, note_type_id) } - ).join(quote {}) - } else { - quote {} - }; - - quote { - $note_exports - } + ).join(quote {}) } pub comptime fn aztec(m: Module) -> Quoted { diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 42932749d99..ca6af8fdfd3 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -9,7 +9,7 @@ use std::meta::typ::fresh_type_variable; comptime global NOTE_HEADER_TYPE = type_of(NoteHeader::empty()); -comptime mut global NOTES: UHashMap> = UHashMap::default(); +comptime mut global NOTES: UHashMap> = UHashMap::default(); comptime fn compute_note_type_id(name: Quoted) -> Field { let name_as_str_quote = name.as_str_quote(); @@ -323,15 +323,7 @@ comptime fn generate_partial_note_impl(s: StructDefinition, hiding_point_name: Q } comptime fn register_note(note: StructDefinition, note_serialized_len: u32, note_type_id: Field) { - let current_notes = unsafe { - NOTES.get(note.module()) - }; - let notes_to_insert = if current_notes.is_some() { - current_notes.unwrap().push_back((note, note_serialized_len, note_type_id)) - } else { - &[(note, note_serialized_len, note_type_id)] - }; - NOTES.insert(note.module(), notes_to_insert); + NOTES.insert(note.as_type(), (note, note_serialized_len, note_type_id)); } comptime fn extract_fixed_fields(s: StructDefinition, nullable_fields: [Quoted]) -> [(Quoted, Type)] { diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr index 8badd035cd9..c4c46da8e3f 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr @@ -5,8 +5,7 @@ use dep::aztec::{ hash::poseidon2_hash_with_separator, traits::Serialize }, note::utils::compute_note_hash_for_nullify, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app, - macros::notes::partial_note + keys::getters::get_nsk_app, macros::notes::partial_note }; trait OwnedNote { diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 4b1bb8dd689..c06a4d3a7b3 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -17,10 +17,8 @@ import { Fr } from '@aztec/foundation/fields'; import { AZTEC_INITIALIZER_ATTRIBUTE, AZTEC_INTERNAL_ATTRIBUTE, - AZTEC_META_PRIVATE_ATTRIBUTE, AZTEC_PRIVATE_ATTRIBUTE, AZTEC_PUBLIC_ATTRIBUTE, - AZTEC_PUBLIC_VM_ATTRIBUTE, AZTEC_VIEW_ATTRIBUTE, type NoirCompiledContract, } from '../noir/index.js'; @@ -188,15 +186,9 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: No } function getFunctionType(fn: NoirCompiledContractFunction): FunctionType { - if ( - fn.custom_attributes.includes(AZTEC_PRIVATE_ATTRIBUTE) || - fn.custom_attributes.includes(AZTEC_META_PRIVATE_ATTRIBUTE) - ) { + if (fn.custom_attributes.includes(AZTEC_PRIVATE_ATTRIBUTE)) { return FunctionType.PRIVATE; - } else if ( - fn.custom_attributes.includes(AZTEC_PUBLIC_ATTRIBUTE) || - fn.custom_attributes.includes(AZTEC_PUBLIC_VM_ATTRIBUTE) - ) { + } else if (fn.custom_attributes.includes(AZTEC_PUBLIC_ATTRIBUTE)) { return FunctionType.PUBLIC; } else if (fn.is_unconstrained) { return FunctionType.UNCONSTRAINED; diff --git a/yarn-project/types/src/noir/index.ts b/yarn-project/types/src/noir/index.ts index 5a449b9a4c1..ca8d028bc22 100644 --- a/yarn-project/types/src/noir/index.ts +++ b/yarn-project/types/src/noir/index.ts @@ -7,13 +7,11 @@ import { type DebugInfo, } from '@aztec/foundation/abi'; -export const AZTEC_PRIVATE_ATTRIBUTE = 'aztec(private)'; -export const AZTEC_META_PRIVATE_ATTRIBUTE = 'aztec_private'; -export const AZTEC_PUBLIC_ATTRIBUTE = 'aztec(public)'; -export const AZTEC_PUBLIC_VM_ATTRIBUTE = 'aztec(public-vm)'; -export const AZTEC_INTERNAL_ATTRIBUTE = 'aztec(internal)'; -export const AZTEC_INITIALIZER_ATTRIBUTE = 'aztec(initializer)'; -export const AZTEC_VIEW_ATTRIBUTE = 'aztec(view)'; +export const AZTEC_PRIVATE_ATTRIBUTE = 'private'; +export const AZTEC_PUBLIC_ATTRIBUTE = 'public'; +export const AZTEC_INTERNAL_ATTRIBUTE = 'internal'; +export const AZTEC_INITIALIZER_ATTRIBUTE = 'initializer'; +export const AZTEC_VIEW_ATTRIBUTE = 'view'; /** * An error could be a custom error of any regular type or a formatted string error. From a7d74b0d32ba3091d97ab995ce1636ca5ec65654 Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 16:15:06 +0000 Subject: [PATCH 22/79] unhack --- noir-projects/aztec-nr/aztec/src/macros/mod.nr | 8 ++++---- noir-projects/aztec-nr/aztec/src/macros/utils.nr | 10 +--------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 6be7ad39763..52faf041b36 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -79,7 +79,7 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { } } -pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier(m: Module) -> Quoted { +pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { let mut max_note_length: u32 = 0; let note_types = NOTES.keys(); let use_statements = note_types.map( @@ -136,7 +136,7 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier(m: Module) } } -pub comptime fn generate_note_exports(m: Module) -> Quoted { +pub comptime fn generate_note_exports() -> Quoted { let notes = NOTES.values(); notes.map( | (s, _, note_type_id): (StructDefinition, u32, Field) | { @@ -153,8 +153,8 @@ pub comptime fn aztec(m: Module) -> Quoted { transform_unconstrained(f); } - let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(m); - let note_exports = generate_note_exports(m); + let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); + let note_exports = generate_note_exports(); quote { $interface diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 1afa4cdbfff..9360dbab995 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -34,15 +34,7 @@ pub(crate) comptime fn fn_has_noinitcheck(f: FunctionDefinition) -> bool { // This is probably a terrible hack pub(crate) comptime fn expr_as_quoted_fixed(expr: Expr) -> Quoted { - if expr.as_let().is_some() { - let quoted = expr.quoted(); - // Let statements lose semicolons - quote { $quoted; } - } else if expr.as_assert().is_some() { - let (assertion, _message) = expr.as_assert().unwrap(); - // Assertions with messages bork the compiler at compiler/noirc_frontend/src/node_interner.rs:1145 - quote { assert($assertion); } - } else if expr.as_unsafe().is_some() { + if expr.as_unsafe().is_some() { // Unsafe blocks require semicolons for some reason? Not if I write them manually let unsafe_expr = expr.as_unsafe().unwrap(); let unsafe_quote = expr_slice_as_quoted_fixed(unsafe_expr); From 393449ac4df4434ca1537b3bf94f64e48d0bebcd Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 18:29:29 +0000 Subject: [PATCH 23/79] woooooo --- .../aztec/src/macros/functions/mod.nr | 2 +- .../aztec-nr/aztec/src/macros/mod.nr | 2 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 3 +- .../src/test/helpers/test_environment.nr | 2 +- .../contracts/delegator_contract/src/main.nr | 44 +++++++++---------- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 04eb2aa20c4..7e0dba2bf62 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -208,7 +208,7 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { } else { quote {} }; - let init_check = if module_has_initializer & !fn_has_noinitcheck(f) { + let init_check = if module_has_initializer & !fn_has_noinitcheck(f) & !is_fn_initializer(f) { create_init_check(f) } else { quote {} diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 52faf041b36..f61eccfb58d 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -157,8 +157,8 @@ pub comptime fn aztec(m: Module) -> Quoted { let note_exports = generate_note_exports(); quote { + $note_exports $interface $compute_note_hash_and_optionally_a_nullifier - $note_exports } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index ca6af8fdfd3..6d97776c2a3 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -156,10 +156,9 @@ pub(crate) comptime fn generate_note_export(s: StructDefinition, note_type_id: F let global_export_name = f"{name}_EXPORTS".quoted_contents(); let note_name_as_str = name.as_str_quote(); let note_name_str_len = unquote!(quote { $note_name_as_str.as_bytes().len() }); - let note_type_id_hex = f"0x{note_type_id}".quoted_contents(); quote { #[abi(notes)] - global $global_export_name: (Field, str<$note_name_str_len>) = ($note_type_id_hex,$note_name_as_str); + global $global_export_name: (Field, str<$note_name_str_len>) = ($note_type_id,$note_name_as_str); } } diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index aaca5874d3c..92a6fe8cc91 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -209,7 +209,7 @@ impl TestEnvironment { /// Manually adds a note to TXE. This needs to be called if you want to work with a note in your test with the note /// not having an encrypted log emitted. TXE alternative to `PXE.addNote(...)`. - pub fn add_note( + pub fn add_note( _self: Self, note: &mut Note, storage_slot: Field, diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index 1dc96018545..80e095d0e43 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -3,40 +3,40 @@ use dep::aztec::macros::aztec; #[aztec] contract Delegator { - use dep::aztec::prelude::{AztecAddress, PublicMutable, PrivateSet, Map}; + use dep::aztec::prelude::{AztecAddress, PublicMutable, PrivateSet, Map, NoteGetterOptions}; use dep::value_note::value_note::ValueNote; use dep::delegated_on::DelegatedOn; - use dep::aztec::macros::{storage::storage, functions::private}; + use dep::aztec::{utils::comparison::Comparator, macros::{storage::storage, functions::{private, public}}}; #[storage] struct Storage { current_value: PublicMutable, a_map_with_private_values: Map, Context>, } - // #[private] - // fn private_delegate_set_value( - // target_contract: AztecAddress, - // value: Field, - // owner: AztecAddress - // ) -> Field { - // // Call the target private function - // DelegatedOn::at(target_contract).private_set_value(value, owner).delegate_call(&mut context) - // } + #[private] + fn private_delegate_set_value( + target_contract: AztecAddress, + value: Field, + owner: AztecAddress + ) -> Field { + // Call the target private function + DelegatedOn::at(target_contract).private_set_value(value, owner).delegate_call(&mut context) + } #[private] fn enqueued_delegate_set_value(target_contract: AztecAddress, value: Field) { DelegatedOn::at(target_contract).public_set_value(value).delegate_enqueue(&mut context) } - // #[public] - // fn public_delegate_set_value(target_contract: AztecAddress, value: Field) -> Field { - // DelegatedOn::at(target_contract).public_set_value(value).delegate_call(&mut context) - // } - // #[private] - // fn get_private_value(amount: Field, owner: AztecAddress) -> pub Field { - // let mut options = NoteGetterOptions::new(); - // options = options.select(ValueNote::properties().value, Comparator.EQ, amount).set_limit(1); - // let notes = storage.a_map_with_private_values.at(owner).get_notes(options); - // notes.get_unchecked(0).value - // } + #[public] + fn public_delegate_set_value(target_contract: AztecAddress, value: Field) -> Field { + DelegatedOn::at(target_contract).public_set_value(value).delegate_call(&mut context) + } + #[private] + fn get_private_value(amount: Field, owner: AztecAddress) -> Field { + let mut options = NoteGetterOptions::new(); + options = options.select(ValueNote::properties().value, Comparator.EQ, amount).set_limit(1); + let notes = storage.a_map_with_private_values.at(owner).get_notes(options); + notes.get_unchecked(0).value + } unconstrained fn view_public_value() -> Field { storage.current_value.read() } From 35dfdb28093019a0909c7a70265016c490b95e43 Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 17 Sep 2024 19:57:03 +0000 Subject: [PATCH 24/79] fix transpiler --- avm-transpiler/src/transpile_contract.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm-transpiler/src/transpile_contract.rs b/avm-transpiler/src/transpile_contract.rs index fff7ad27522..975f8a117ca 100644 --- a/avm-transpiler/src/transpile_contract.rs +++ b/avm-transpiler/src/transpile_contract.rs @@ -94,7 +94,7 @@ impl From for TranspiledContractArtifact { for function in contract.functions { // TODO(4269): once functions are tagged for transpilation to AVM, check tag - if function.custom_attributes.contains(&"aztec(public)".to_string()) { + if function.custom_attributes.contains(&"public".to_string()) { info!("Transpiling AVM function {} on contract {}", function.name, contract.name); // Extract Brillig Opcodes from acir let acir_program = function.bytecode; From e0ed976ee4b2e99861510237bf96aceacfe60220 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 06:47:46 +0000 Subject: [PATCH 25/79] removed hacks --- .../aztec-nr/authwit/src/cheatcodes.nr | 4 +- .../aztec-nr/authwit/src/entrypoint/app.nr | 6 +- .../aztec-nr/authwit/src/entrypoint/fee.nr | 6 +- .../authwit/src/entrypoint/function_call.nr | 4 +- .../aztec/src/context/private_context.nr | 2 +- .../aztec/src/encrypted_logs/incoming_body.nr | 6 +- .../aztec/src/history/note_inclusion.nr | 4 +- .../aztec/src/history/note_validity.nr | 4 +- .../aztec/src/history/nullifier_inclusion.nr | 4 +- .../src/history/nullifier_non_inclusion.nr | 4 +- .../aztec-nr/aztec/src/macros/mod.nr | 12 +-- .../aztec-nr/aztec/src/macros/utils.nr | 34 +------- .../aztec-nr/aztec/src/note/lifecycle.nr | 8 +- .../aztec-nr/aztec/src/note/note_header.nr | 2 +- .../aztec-nr/aztec/src/note/note_interface.nr | 8 +- .../aztec/src/state_vars/private_immutable.nr | 6 +- .../aztec/src/state_vars/private_mutable.nr | 4 +- .../aztec/src/state_vars/public_immutable.nr | 4 +- .../aztec/src/state_vars/public_mutable.nr | 4 +- .../aztec/src/state_vars/shared_immutable.nr | 6 +- .../shared_mutable/scheduled_delay_change.nr | 6 +- .../scheduled_delay_change/test.nr | 14 ++-- .../shared_mutable_private_getter.nr | 6 +- .../aztec-nr/aztec/src/state_vars/storage.nr | 6 +- .../src/test/helpers/test_environment.nr | 6 +- .../aztec/src/test/mocks/mock_note.nr | 2 +- .../aztec-nr/value-note/src/value_note.nr | 4 +- noir-projects/noir-contracts/bootstrap.sh | 2 +- .../contracts/auth_contract/src/main.nr | 2 +- .../contracts/counter_contract/src/main.nr | 1 + .../contracts/token_contract/src/main.nr | 4 +- .../token_contract/src/types/balance_set.nr | 12 +-- .../noir-protocol-circuits/bootstrap.sh | 2 +- .../crates/types/src/abis/event_selector.nr | 2 +- .../types/src/abis/function_selector.nr | 2 +- .../types/src/abis/note_hash_leaf_preimage.nr | 2 +- .../src/abis/private_circuit_public_inputs.nr | 2 +- .../types/src/address/partial_address.nr | 2 +- .../crates/types/src/constants.nr | 82 +++++++++---------- .../types/src/merkle_tree/membership.nr | 12 ++- .../crates/types/src/point.nr | 2 +- .../crates/types/src/scalar.nr | 2 +- .../types/src/tests/fixtures/vk_tree.nr | 2 +- .../crates/types/src/traits.nr | 10 +-- .../crates/types/src/type_serialization.nr | 12 +-- .../assert_split_transformed_value_arrays.nr | 2 +- 46 files changed, 150 insertions(+), 183 deletions(-) diff --git a/noir-projects/aztec-nr/authwit/src/cheatcodes.nr b/noir-projects/aztec-nr/authwit/src/cheatcodes.nr index 74e8b3621de..bb770da9866 100644 --- a/noir-projects/aztec-nr/authwit/src/cheatcodes.nr +++ b/noir-projects/aztec-nr/authwit/src/cheatcodes.nr @@ -6,7 +6,7 @@ use dep::aztec::{ use crate::auth::{compute_inner_authwit_hash, compute_authwit_message_hash, set_authorized}; -pub fn add_private_authwit_from_call_interface( +pub fn add_private_authwit_from_call_interface( on_behalf_of: AztecAddress, caller: AztecAddress, call_interface: C @@ -22,7 +22,7 @@ pub fn add_private_authwit_from_call_interface( cheatcodes::add_authwit(on_behalf_of, message_hash); } -pub fn add_public_authwit_from_call_interface( +pub fn add_public_authwit_from_call_interface( on_behalf_of: AztecAddress, caller: AztecAddress, call_interface: C diff --git a/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr b/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr index c658539a306..b74d6637f9b 100644 --- a/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr +++ b/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr @@ -7,11 +7,11 @@ use dep::aztec::protocol_types::{ use crate::entrypoint::function_call::{FunctionCall, FUNCTION_CALL_SIZE_IN_BYTES}; // FUNCTION_CALL_SIZE * ACCOUNT_MAX_CALLS + 1 -global APP_PAYLOAD_SIZE: u64 = 21; +global APP_PAYLOAD_SIZE: u32 = 21; // FUNCTION_CALL_SIZE_IN_BYTES * ACCOUNT_MAX_CALLS + 32 -global APP_PAYLOAD_SIZE_IN_BYTES: u64 = 424; +global APP_PAYLOAD_SIZE_IN_BYTES: u32 = 424; -global ACCOUNT_MAX_CALLS: u64 = 4; +global ACCOUNT_MAX_CALLS: u32 = 4; // Note: If you change the following struct you have to update default_entrypoint.ts // docs:start:app-payload-struct diff --git a/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr b/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr index f2cf7a76eaf..6465584f56b 100644 --- a/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr +++ b/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr @@ -6,12 +6,12 @@ use dep::aztec::protocol_types::{ use crate::entrypoint::function_call::FunctionCall; // 2 * 5 (FUNCTION_CALL_SIZE) + 2 -global FEE_PAYLOAD_SIZE: Field = 12; +global FEE_PAYLOAD_SIZE: u32 = 12; // 2 * 98 (FUNCTION_CALL_SIZE_IN_BYTES) + 32 -global FEE_PAYLOAD_SIZE_IN_BYTES: Field = 228; +global FEE_PAYLOAD_SIZE_IN_BYTES: u32 = 228; -global MAX_FEE_FUNCTION_CALLS = 2; +global MAX_FEE_FUNCTION_CALLS: u32 = 2; // docs:start:fee-payload-struct struct FeePayload { diff --git a/noir-projects/aztec-nr/authwit/src/entrypoint/function_call.nr b/noir-projects/aztec-nr/authwit/src/entrypoint/function_call.nr index 5ba2bf836b5..4ff0dd2c8f2 100644 --- a/noir-projects/aztec-nr/authwit/src/entrypoint/function_call.nr +++ b/noir-projects/aztec-nr/authwit/src/entrypoint/function_call.nr @@ -1,9 +1,9 @@ use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, traits::Serialize}; // 1 (ARGS_HASH) + 1 (FUNCTION_SELECTOR) + 1 (TARGET_ADDRESS) + 1 (IS_PUBLIC) + 1 (IS_STATIC) -global FUNCTION_CALL_SIZE: Field = 5; +global FUNCTION_CALL_SIZE: u32 = 5; // 3 * 32 + 2 -global FUNCTION_CALL_SIZE_IN_BYTES: Field = 98; +global FUNCTION_CALL_SIZE_IN_BYTES: u32 = 98; struct FunctionCall { args_hash: Field, diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index bb415cacd0d..18840c511a0 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -34,7 +34,7 @@ use dep::protocol_types::{ }; // When finished, one can call .finish() to convert back to the abi -struct PrivateContext { +pub struct PrivateContext { // docs:start:private-context inputs: PrivateContextInputs, side_effect_counter: u32, diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr index 72bac692afd..99f84f33bf8 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr @@ -52,7 +52,7 @@ mod test { header: NoteHeader, } - global ADDRESS_NOTE_LEN: Field = 3; + global ADDRESS_NOTE_LEN: u32 = 3; impl NullifiableNote for AddressNote { fn compute_nullifier( @@ -189,9 +189,7 @@ mod test { } } - global TEST_EVENT_LEN: Field = 3; - global TEST_EVENT_BYTES_LEN = 32 * 3 + 64; - global TEST_EVENT_BYTES_LEN_WITHOUT_RANDOMNESS = 32 * 3 + 32; + global TEST_EVENT_LEN: u32 = 3; impl EventInterface for TestEvent { fn get_event_type_id() -> EventSelector { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index 2fc06caf198..4e245febc9f 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -7,11 +7,11 @@ use crate::{ }; trait ProveNoteInclusion { - fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote; + fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface + NullifiableNote; } impl ProveNoteInclusion for Header { - fn prove_note_inclusion( + fn prove_note_inclusion( self, note: Note ) where Note: NoteInterface + NullifiableNote { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr index 48461295d67..eba2cfc2d05 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr @@ -3,11 +3,11 @@ use crate::{context::PrivateContext, note::note_interface::{NoteInterface, Nulli use dep::protocol_types::header::Header; trait ProveNoteValidity { - fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; + fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteValidity for Header { - fn prove_note_validity( + fn prove_note_validity( self, note: Note, context: &mut PrivateContext diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index ab000a248a1..81aee809ebc 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -32,12 +32,12 @@ impl ProveNullifierInclusion for Header { } trait ProveNoteIsNullified { - fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; + fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteIsNullified for Header { // docs:start:prove_note_is_nullified - fn prove_note_is_nullified( + fn prove_note_is_nullified( self, note: Note, context: &mut PrivateContext diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index 70ba7c44caf..977a5477547 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -42,12 +42,12 @@ impl ProveNullifierNonInclusion for Header { } trait ProveNoteNotNullified { - fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; + fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface + NullifiableNote; } impl ProveNoteNotNullified for Header { // docs:start:prove_note_not_nullified - fn prove_note_not_nullified( + fn prove_note_not_nullified( self, note: Note, context: &mut PrivateContext diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index f61eccfb58d..54c5c193147 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -81,14 +81,6 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { let mut max_note_length: u32 = 0; - let note_types = NOTES.keys(); - let use_statements = note_types.map( - | typ: Type | { - quote { - use $typ; - } - } - ).join(quote {}); let notes = NOTES.values(); let body = if notes.len() > 0 { max_note_length = notes.fold(0, | acc, (_, len, _): (StructDefinition, u32, Field) | { @@ -98,7 +90,7 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quote | (note, _, _): (StructDefinition, u32, Field) | { let note_name = note.name(); quote { - if note_type_id == $note_name::get_note_type_id(); { + if note_type_id == $note_name::get_note_type_id() { aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($note_name::deserialize_content, note_header, compute_nullifier, serialized_note) } } @@ -121,8 +113,6 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quote }; quote { - $use_statements - unconstrained fn compute_note_hash_and_optionally_a_nullifier( contract_address: aztec::protocol_types::address::AztecAddress, nonce: Field, diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 9360dbab995..b9231be36cf 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -32,43 +32,17 @@ pub(crate) comptime fn fn_has_noinitcheck(f: FunctionDefinition) -> bool { f.has_named_attribute("noinitcheck") } -// This is probably a terrible hack -pub(crate) comptime fn expr_as_quoted_fixed(expr: Expr) -> Quoted { - if expr.as_unsafe().is_some() { - // Unsafe blocks require semicolons for some reason? Not if I write them manually - let unsafe_expr = expr.as_unsafe().unwrap(); - let unsafe_quote = expr_slice_as_quoted_fixed(unsafe_expr); - quote { unsafe { $unsafe_quote }; } - } else if expr.as_if().is_some() { - let (condition, if_branch, else_branch) = expr.as_if().unwrap(); - let fixed_if = expr_as_quoted_fixed(if_branch); - // Fix the branches - if else_branch.is_some() { - let fixed_else = expr_as_quoted_fixed(else_branch.unwrap()); - quote { if $condition { $fixed_if } else { $fixed_else } } - } else { - quote { if $condition { $fixed_if } } - } - } else { - quote { $expr } - } -} - -pub(crate) comptime fn expr_slice_as_quoted_fixed(exprs: [Expr]) -> Quoted { - exprs.fold( +pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quoted) -> Expr { + let mut body_quote = body.fold( quote {}, |full_quote: Quoted, expr: Expr| { - let expr_quote = expr_as_quoted_fixed(expr); + let expr_quote = expr.quoted(); quote { $full_quote $expr_quote } } - ) -} - -pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quoted) -> Expr { - let mut body_quote = expr_slice_as_quoted_fixed(body); + ); body_quote = quote { { $prepend diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index 3eb09e9bd78..58321fff061 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -6,7 +6,7 @@ use crate::note::{ }; use crate::oracle::notes::{notify_created_note, notify_nullified_note}; -pub fn create_note( +pub fn create_note( context: &mut PrivateContext, storage_slot: Field, note: &mut Note @@ -35,7 +35,7 @@ pub fn create_note( NoteEmission::new(*note) } -pub fn create_note_hash_from_public( +pub fn create_note_hash_from_public( context: &mut PublicContext, storage_slot: Field, note: &mut Note @@ -50,7 +50,7 @@ pub fn create_note_hash_from_public( } // Note: This function is currently totally unused. -pub fn destroy_note( +pub fn destroy_note( context: &mut PrivateContext, note: Note ) where Note: NoteInterface + NullifiableNote { @@ -59,7 +59,7 @@ pub fn destroy_note( destroy_note_unsafe(context, note, note_hash_for_read_request) } -pub fn destroy_note_unsafe( +pub fn destroy_note_unsafe( context: &mut PrivateContext, note: Note, note_hash_for_read_request: Field diff --git a/noir-projects/aztec-nr/aztec/src/note/note_header.nr b/noir-projects/aztec-nr/aztec/src/note/note_header.nr index 2c20777fd4d..bf71981024e 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_header.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_header.nr @@ -1,6 +1,6 @@ use dep::protocol_types::{address::AztecAddress, traits::{Empty, Serialize}}; -global NOTE_HEADER_LENGTH: Field = 4; +global NOTE_HEADER_LENGTH: u32 = 4; struct NoteHeader { contract_address: AztecAddress, diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index 9ebfb8a8827..c7ecc774ad4 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -1,15 +1,15 @@ use crate::context::PrivateContext; use crate::note::note_header::NoteHeader; -trait NoteProperties { +pub trait NoteProperties { fn properties() -> T; } -trait PartialNote { +pub trait PartialNote { fn hiding_point() -> T; } -trait NullifiableNote { +pub trait NullifiableNote { // This function MUST be called with the correct note hash for consumption! It will otherwise silently fail and // compute an incorrect value. // The reason why we receive this as an argument instead of computing it ourselves directly is because the @@ -25,7 +25,7 @@ trait NullifiableNote { // docs:start:note_interface // Autogenerated by the #[note] macro -trait NoteInterface { +pub trait NoteInterface { // Autogenerated by the #[note] macro fn serialize_content(self) -> [Field; N]; diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 681c6780c6d..798d3dc4205 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -42,7 +42,7 @@ impl PrivateImmutable { impl PrivateImmutable { // docs:start:initialize - pub fn initialize( + pub fn initialize( self, note: &mut Note ) -> NoteEmission where Note: NoteInterface + NullifiableNote { @@ -55,7 +55,7 @@ impl PrivateImmutable { // docs:end:initialize // docs:start:get_note - pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote { + pub fn get_note(self) -> Note where Note: NoteInterface + NullifiableNote { let storage_slot = self.storage_slot; get_note(self.context, storage_slot).0 } @@ -72,7 +72,7 @@ impl PrivateImmutable { // view_note does not actually use the context, but it calls oracles that are only available in private // docs:start:view_note - unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote { + unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + NullifiableNote { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(0) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index 68faf76f5a5..c41dbbaaa68 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -44,7 +44,7 @@ impl PrivateMutable { } } -impl PrivateMutable where Note: NoteInterface + NullifiableNote { +impl PrivateMutable where Note: NoteInterface + NullifiableNote { // docs:start:initialize pub fn initialize(self, note: &mut Note) -> NoteEmission { // Nullify the storage slot. @@ -103,7 +103,7 @@ impl PrivateMutable where Note: NoteInterfac // docs:end:get_note } -impl PrivateMutable where Note: NoteInterface + NullifiableNote { +impl PrivateMutable where Note: NoteInterface + NullifiableNote { unconstrained pub fn is_initialized(self) -> bool { let nullifier = self.compute_initialization_nullifier(); check_nullifier_exists(nullifier) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr index 78d077be7ab..9c7b82231b9 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr @@ -24,7 +24,7 @@ impl PublicImmutable { // docs:end:public_immutable_struct_new } -impl PublicImmutable where T: Serialize + Deserialize { +impl PublicImmutable where T: Serialize + Deserialize { // docs:start:public_immutable_struct_write pub fn initialize(self, value: T) { // We check that the struct is not yet initialized by checking if the initialization slot is 0 @@ -46,7 +46,7 @@ impl PublicImmutable where T: Seria // docs:end:public_immutable_struct_read } -impl PublicImmutablewhere T: Deserialize { +impl PublicImmutablewhere T: Deserialize { unconstrained pub fn read(self) -> T { self.context.storage_read(self.storage_slot) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr index 72fce5d0b59..5cb02b44635 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr @@ -24,7 +24,7 @@ impl PublicMutable { // docs:end:public_mutable_struct_new } -impl PublicMutable where T: Serialize + Deserialize { +impl PublicMutable where T: Serialize + Deserialize { // docs:start:public_mutable_struct_read pub fn read(self) -> T { self.context.storage_read(self.storage_slot) @@ -38,7 +38,7 @@ impl PublicMutable where T: Serializ // docs:end:public_mutable_struct_write } -impl PublicMutable where T: Deserialize { +impl PublicMutable where T: Deserialize { unconstrained pub fn read(self) -> T { self.context.storage_read(self.storage_slot) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr index 97db8c5de5f..16d7a77bf5c 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr @@ -20,7 +20,7 @@ impl SharedImmutable { } } -impl SharedImmutable where T: Serialize + Deserialize { +impl SharedImmutable where T: Serialize + Deserialize { // Intended to be only called once. pub fn initialize(self, value: T) { // We check that the struct is not yet initialized by checking if the initialization slot is 0 @@ -38,13 +38,13 @@ impl SharedImmutable where T: Serial } } -impl SharedImmutable where T: Serialize + Deserialize { +impl SharedImmutable where T: Serialize + Deserialize { unconstrained pub fn read_public(self) -> T { self.context.storage_read(self.storage_slot) } } -impl SharedImmutable where T: Serialize + Deserialize { +impl SharedImmutable where T: Serialize + Deserialize { pub fn read_private(self) -> T { let header = self.context.get_header(); let mut fields = [0; T_SERIALIZED_LEN]; diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr index 9773ee59f75..a2be6062513 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr @@ -127,7 +127,7 @@ impl ScheduledDelayChange { } } -impl Serialize<1> for ScheduledDelayChange { +impl Serialize<1> for ScheduledDelayChange { fn serialize(self) -> [Field; 1] { // We pack all three u32 values into a single U128, which is made up of two u64 limbs. // Low limb: [ pre_inner: u32 | post_inner: u32 ] @@ -145,7 +145,7 @@ impl Serialize<1> for ScheduledDelayChange { } } -impl Deserialize<1> for ScheduledDelayChange { +impl Deserialize<1> for ScheduledDelayChange { fn deserialize(input: [Field; 1]) -> Self { let packed = U128::from_integer(input[0]); @@ -175,7 +175,7 @@ impl Deserialize<1> for ScheduledDelayChange { } } -impl Eq for ScheduledDelayChange { +impl Eq for ScheduledDelayChange { fn eq(self, other: Self) -> bool { (self.pre == other.pre) & (self.post == other.post) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr index c569510e2cd..cae523b1f5d 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr @@ -1,6 +1,6 @@ use crate::state_vars::shared_mutable::scheduled_delay_change::ScheduledDelayChange; -global TEST_INITIAL_DELAY = 13; +global TEST_INITIAL_DELAY: u32 = 13; fn assert_equal_after_conversion(original: ScheduledDelayChange) { // We have to do explicit type annotations because Noir lacks turbofish support. @@ -184,13 +184,13 @@ fn test_schedule_change_to_longer_delay_after_change() { #[test] fn test_schedule_change_to_longer_delay_from_initial() { - let new = TEST_INITIAL_DELAY + 1; + let new: u32 = TEST_INITIAL_DELAY + 1; let current_block_number = 50; let mut delay_change = get_initial_delay_change(); delay_change.schedule_change(new, current_block_number); - // Like in the after change scenario, change is effective immediately because the new delay is longer than the + // Like in the after change scenario, change is effective immediately because the new delay is longer than the // current one. assert_eq(delay_change.pre.unwrap(), TEST_INITIAL_DELAY); assert_eq(delay_change.post.unwrap(), new); @@ -198,7 +198,7 @@ fn test_schedule_change_to_longer_delay_from_initial() { assert_eq(delay_change.get_current(current_block_number), new); } -fn assert_effective_minimum_delay_invariants( +fn assert_effective_minimum_delay_invariants( delay_change: &mut ScheduledDelayChange, historical_block_number: u32, effective_minimum_delay: u32 @@ -222,8 +222,8 @@ fn assert_effective_minimum_delay_invariants( let value_change_block = change_schedule_block + delay_change.get_current(change_schedule_block); assert(expected_earliest_value_change_block <= value_change_block); - // Finally, a delay reduction could be scheduled immediately after the historical block. We reduce the delay to - // zero, which means that at the delay block of change there'll be no delay and a value change could be + // Finally, a delay reduction could be scheduled immediately after the historical block. We reduce the delay to + // zero, which means that at the delay block of change there'll be no delay and a value change could be // performed immediately then. delay_change.schedule_change(0, historical_block_number + 1); assert(expected_earliest_value_change_block <= delay_change.block_of_change); @@ -326,7 +326,7 @@ fn test_get_effective_delay_at_initial() { let historical_block_number = 200; - // Like in the after change scenario, no delay change is scheduled, so the effective delay is simply the current + // Like in the after change scenario, no delay change is scheduled, so the effective delay is simply the current // one (initial). let effective_minimum_delay = delay_change.get_effective_minimum_delay_at(historical_block_number); assert_eq(effective_minimum_delay, TEST_INITIAL_DELAY); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr index 84d3816b66b..443fdf10973 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr @@ -2,7 +2,7 @@ use dep::protocol_types::{traits::{FromField, ToField}, address::AztecAddress, h use crate::{context::PrivateContext, state_vars::shared_mutable::shared_mutable::SharedMutable}; -struct SharedMutablePrivateGetter { +struct SharedMutablePrivateGetter { context: &mut PrivateContext, // The contract address of the contract we want to read from other_contract_address: AztecAddress, @@ -12,7 +12,7 @@ struct SharedMutablePrivateGetter { // We have this as a view-only interface to reading Shared Mutables in other contracts. // Currently the Shared Mutable does not support this. We can adapt SharedMutable at a later date -impl SharedMutablePrivateGetter where T: FromField + ToField + Eq { +impl SharedMutablePrivateGetter where T: FromField + ToField + Eq { pub fn new( context: &mut PrivateContext, other_contract_address: AztecAddress, @@ -25,7 +25,7 @@ impl SharedMutablePrivateGetter where T: Fr pub fn get_value_in_private(self, header: Header) -> T { // We create a dummy SharedMutable state variable so that we can reuse its historical_read_from_public_storage - // method, greatly reducing code duplication. + // method, greatly reducing code duplication. let dummy: SharedMutable = SharedMutable::new((), self.storage_slot); let (value_change, delay_change, historical_block_number) = dummy.historical_read_from_public_storage(header, self.other_contract_address); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/storage.nr b/noir-projects/aztec-nr/aztec/src/state_vars/storage.nr index 8ae9faf228c..abcf627f798 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/storage.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/storage.nr @@ -1,15 +1,15 @@ use dep::protocol_types::traits::{Deserialize, Serialize}; -trait Storage where T: Serialize + Deserialize { +pub trait Storage where T: Serialize + Deserialize { fn get_storage_slot(self) -> Field { self.storage_slot } } // Struct representing an exportable storage variable in the contract -// Every entry in the storage struct will be exported in the compilation artifact as a +// Every entry in the storage struct will be exported in the compilation artifact as a // Storable entity, containing the storage slot -struct Storable { +pub struct Storable { slot: Field, } diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index 92a6fe8cc91..8d45bbc33fa 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -14,7 +14,7 @@ use crate::hash::hash_args; use crate::note::{note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}}; use crate::oracle::{execution::{get_block_number, get_contract_address}, notes::notify_created_note}; -struct TestEnvironment {} +pub struct TestEnvironment {} impl TestEnvironment { fn new() -> Self { @@ -101,11 +101,11 @@ impl TestEnvironment { address } - fn deploy(self, path: str, name: str) -> Deployer { + fn deploy(self, path: str, name: str) -> Deployer { Deployer { path, name, public_keys_hash: 0 } } - fn deploy_self(self, name: str) -> Deployer<0, M> { + fn deploy_self(self, name: str) -> Deployer<0, M> { Deployer { path: "", name, public_keys_hash: 0 } } diff --git a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr index e95367b8b4f..3243409da9b 100644 --- a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr +++ b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr @@ -7,7 +7,7 @@ use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOT use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; use crate::note::note_interface::NullifiableNote; -global MOCK_NOTE_LENGTH = 1; +global MOCK_NOTE_LENGTH: u32 = 1; struct MockNote { header: NoteHeader, diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 42001cc6a4e..7a6911994bd 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -5,12 +5,12 @@ use dep::aztec::{ oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext }; -global VALUE_NOTE_LEN: u64 = 3; // 3 plus a header. +global VALUE_NOTE_LEN: u32 = 3; // 3 plus a header. // docs:start:value-note-def #[derive(Serialize)] #[note] -struct ValueNote { +pub struct ValueNote { value: Field, // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. npk_m_hash: Field, diff --git a/noir-projects/noir-contracts/bootstrap.sh b/noir-projects/noir-contracts/bootstrap.sh index 3eb62c4530f..a3d0ae1a135 100755 --- a/noir-projects/noir-contracts/bootstrap.sh +++ b/noir-projects/noir-contracts/bootstrap.sh @@ -17,7 +17,7 @@ fi echo "Compiling contracts..." NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} -$NARGO compile --silence-warnings +nargo compile --silence-warnings echo "Transpiling contracts..." scripts/transpile.sh \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr index f772eb0237f..18f4cd0aebb 100644 --- a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr @@ -12,7 +12,7 @@ contract Auth { }; // Authorizing a new address has a certain block delay before it goes into effect. - global CHANGE_AUTHORIZED_DELAY_BLOCKS = 5; + global CHANGE_AUTHORIZED_DELAY_BLOCKS: u32 = 5; #[storage] struct Storage { diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index c1b737beecb..83e26e6ca13 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -41,6 +41,7 @@ contract Counter { let counters = storage.counters; balance_utils::get_balance(counters.at(owner).set) } + // docs:end:get_counter // docs:start:test_imports use dep::aztec::test::{helpers::{test_environment::TestEnvironment}}; diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 16d8097470f..29735a9cdf3 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -43,11 +43,11 @@ contract Token { // In the first transfer iteration we are computing a lot of additional information (validating inputs, retrieving // keys, etc.), so the gate count is already relatively high. We therefore only read a few notes to keep the happy // case with few constraints. - global INITIAL_TRANSFER_CALL_MAX_NOTES = 2; + global INITIAL_TRANSFER_CALL_MAX_NOTES: u32 = 2; // All the recursive call does is nullify notes, meaning the gate count is low, but it is all constant overhead. We // therefore read more notes than in the base case to increase the efficiency of the overhead, since this results in // an overall small circuit regardless. - global RECURSIVE_TRANSFER_CALL_MAX_NOTES = 8; + global RECURSIVE_TRANSFER_CALL_MAX_NOTES: u32 = 8; #[event] #[derive(Serialize)] diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr index df3fb51adf0..3c2ffaab8a3 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr @@ -19,11 +19,11 @@ impl BalanceSet { } impl BalanceSet { - unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { + unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { self.balance_of_with_offset(0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, offset: u32 ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { @@ -46,7 +46,7 @@ impl BalanceSet { } impl BalanceSet { - pub fn add( + pub fn add( self: Self, owner_npk_m: NpkM, addend: U128 @@ -63,7 +63,7 @@ impl BalanceSet { } } - pub fn sub( + pub fn sub( self: Self, owner_npk_m: NpkM, amount: U128 @@ -85,7 +85,7 @@ impl BalanceSet { // The `max_notes` parameter is used to fine-tune the number of constraints created by this function. The gate count // scales relatively linearly with `max_notes`, but a lower `max_notes` parameter increases the likelihood of // `try_sub` subtracting an amount smaller than `target_amount`. - pub fn try_sub( + pub fn try_sub( self: Self, target_amount: U128, max_notes: u32 @@ -115,7 +115,7 @@ impl BalanceSet { // The preprocessor (a filter applied in an unconstrained context) does not check if total sum is larger or equal to // 'min_sum' - all it does is remove extra notes if it does reach that value. // Note that proper usage of this preprocessor requires for notes to be sorted in descending order. -pub fn preprocess_notes_min_sum( +pub fn preprocess_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + NullifiableNote + OwnedNote { diff --git a/noir-projects/noir-protocol-circuits/bootstrap.sh b/noir-projects/noir-protocol-circuits/bootstrap.sh index ebc4e25f773..80761a8a20e 100755 --- a/noir-projects/noir-protocol-circuits/bootstrap.sh +++ b/noir-projects/noir-protocol-circuits/bootstrap.sh @@ -20,7 +20,7 @@ node ./generate_variants.js echo "Compiling protocol circuits..." NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} -$NARGO compile --silence-warnings +nargo compile --silence-warnings BB_HASH=${BB_HASH:-$(cd ../../ && git ls-tree -r HEAD | grep 'barretenberg/cpp' | awk '{print $3}' | git hash-object --stdin)} echo Using BB hash $BB_HASH diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr index b03f665d227..0a1bbf3444d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr @@ -1,7 +1,7 @@ use crate::utils::field::field_from_bytes; use crate::traits::{Serialize, Deserialize, FromField, ToField, Empty}; -global SELECTOR_SIZE = 4; +global SELECTOR_SIZE: u32 = 4; struct EventSelector { // 1st 4-bytes (big-endian leftmost) of abi-encoding of an event. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr index 26ae4aeac2c..eda80e000a0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr @@ -1,7 +1,7 @@ use crate::utils::field::field_from_bytes; use crate::traits::{Serialize, Deserialize, FromField, ToField, Empty}; -global SELECTOR_SIZE = 4; +global SELECTOR_SIZE: u32 = 4; struct FunctionSelector { // 1st 4-bytes of abi-encoding of function. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr index 652f8bf3732..db29fe89171 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr @@ -1,4 +1,4 @@ -global NOTE_HASH_LEAF_PREIMAGE_LENGTH: u64 = 1; +global NOTE_HASH_LEAF_PREIMAGE_LENGTH: u32 = 1; use crate::{ abis::{read_request::ScopedReadRequest, side_effect::Readable}, hash::compute_siloed_note_hash, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index 535a3e9ccb8..a954f5dbd1f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr @@ -49,7 +49,7 @@ impl PrivateCircuitPublicInputsArrayLengths { } // Public inputs to private app circuit. -struct PrivateCircuitPublicInputs { +pub struct PrivateCircuitPublicInputs { call_context: CallContext, args_hash: Field, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr index 0e118db7070..0f073a4dcba 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr @@ -4,7 +4,7 @@ use crate::{ hash::poseidon2_hash_with_separator, traits::{ToField, Serialize, Deserialize} }; -global PARTIAL_ADDRESS_LENGTH = 1; +global PARTIAL_ADDRESS_LENGTH: u32 = 1; // Partial address struct PartialAddress { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index d84713c9e86..61b2a8a4f78 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -196,7 +196,7 @@ global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x1abe6c7f5c4caf04cbf7556495 global ROUTER_ADDRESS = AztecAddress::from_field(0x1d8f25db3e8faa6a96cb1ecf57876a2ee04581deb3c4f181488ccd817abcbdb0); // LENGTH OF STRUCTS SERIALIZED TO FIELDS -global AZTEC_ADDRESS_LENGTH = 1; +global AZTEC_ADDRESS_LENGTH: u32 = 1; global GAS_FEES_LENGTH: u32 = 2; global GAS_LENGTH: u32 = 2; global GAS_SETTINGS_LENGTH: u32 = GAS_LENGTH * 2 + GAS_FEES_LENGTH + /* inclusion_fee */ 1; @@ -205,7 +205,7 @@ global CONTENT_COMMITMENT_LENGTH: u32 = 4; global CONTRACT_INSTANCE_LENGTH: u32 = 5; global CONTRACT_STORAGE_READ_LENGTH: u32 = 3; global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: u32 = 3; -global ETH_ADDRESS_LENGTH = 1; +global ETH_ADDRESS_LENGTH: u32 = 1; global FUNCTION_DATA_LENGTH: u32 = 2; global FUNCTION_LEAF_PREIMAGE_LENGTH: u32 = 5; global GLOBAL_VARIABLES_LENGTH: u32 = 7 + GAS_FEES_LENGTH; @@ -214,29 +214,29 @@ global L1_TO_L2_MESSAGE_LENGTH: u32 = 6; global L2_TO_L1_MESSAGE_LENGTH: u32 = 3; global SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; global MAX_BLOCK_NUMBER_LENGTH: u32 = 2; // 1 for the option flag, 1 for the value -global KEY_VALIDATION_REQUEST_LENGTH = 4; -global KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH = KEY_VALIDATION_REQUEST_LENGTH + 1; -global SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH = KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH + 1; +global KEY_VALIDATION_REQUEST_LENGTH: u32 = 4; +global KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH: u32 = KEY_VALIDATION_REQUEST_LENGTH + 1; +global SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH: u32 = KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH + 1; global PARTIAL_STATE_REFERENCE_LENGTH: u32 = 6; -global READ_REQUEST_LENGTH = 2; -global TREE_LEAF_READ_REQUEST_LENGTH = 2; -global LOG_HASH_LENGTH = 3; -global SCOPED_LOG_HASH_LENGTH = LOG_HASH_LENGTH + 1; -global ENCRYPTED_LOG_HASH_LENGTH = 4; -global SCOPED_ENCRYPTED_LOG_HASH_LENGTH = ENCRYPTED_LOG_HASH_LENGTH + 1; -global NOTE_LOG_HASH_LENGTH = 4; -global NOTE_HASH_LENGTH = 2; -global SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 1; -global NULLIFIER_LENGTH = 3; -global SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; -global PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH = AZTEC_ADDRESS_LENGTH + CALL_CONTEXT_LENGTH + 3 + 2 * GAS_LENGTH; -global PRIVATE_CALL_REQUEST_LENGTH = AZTEC_ADDRESS_LENGTH + CALL_CONTEXT_LENGTH + 4; -global PUBLIC_CALL_REQUEST_LENGTH = PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH + 1 /* counter */; -global ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; +global READ_REQUEST_LENGTH: u32 = 2; +global TREE_LEAF_READ_REQUEST_LENGTH: u32 = 2; +global LOG_HASH_LENGTH: u32 = 3; +global SCOPED_LOG_HASH_LENGTH: u32 = LOG_HASH_LENGTH + 1; +global ENCRYPTED_LOG_HASH_LENGTH: u32 = 4; +global SCOPED_ENCRYPTED_LOG_HASH_LENGTH: u32 = ENCRYPTED_LOG_HASH_LENGTH + 1; +global NOTE_LOG_HASH_LENGTH: u32 = 4; +global NOTE_HASH_LENGTH: u32 = 2; +global SCOPED_NOTE_HASH_LENGTH: u32 = NOTE_HASH_LENGTH + 1; +global NULLIFIER_LENGTH: u32 = 3; +global SCOPED_NULLIFIER_LENGTH: u32 = NULLIFIER_LENGTH + 1; +global PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH: u32 = AZTEC_ADDRESS_LENGTH + CALL_CONTEXT_LENGTH + 3 + 2 * GAS_LENGTH; +global PRIVATE_CALL_REQUEST_LENGTH: u32 = AZTEC_ADDRESS_LENGTH + CALL_CONTEXT_LENGTH + 4; +global PUBLIC_CALL_REQUEST_LENGTH: u32 = PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH + 1 /* counter */; +global ROLLUP_VALIDATION_REQUESTS_LENGTH: u32 = MAX_BLOCK_NUMBER_LENGTH; global STATE_REFERENCE_LENGTH: u32 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; global TX_CONTEXT_LENGTH: u32 = 2 + GAS_SETTINGS_LENGTH; global TX_REQUEST_LENGTH: u32 = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; -global TOTAL_FEES_LENGTH = 1; +global TOTAL_FEES_LENGTH: u32 = 1; global HEADER_LENGTH: u32 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH + TOTAL_FEES_LENGTH; global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_CALL) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + (PUBLIC_CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL) + PUBLIC_CALL_REQUEST_LENGTH + (L2_TO_L1_MESSAGE_LENGTH * MAX_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (ENCRYPTED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = CALL_CONTEXT_LENGTH + /*argsHash + returnsHash*/ 2 + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + (PUBLIC_CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; @@ -245,29 +245,29 @@ global PUBLIC_CONTEXT_INPUTS_LENGTH: u32 = CALL_CONTEXT_LENGTH + HEADER_LENGTH + global AGGREGATION_OBJECT_LENGTH: u32 = 16; -global SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; -global PUBLIC_DATA_READ_LENGTH = 3; -global PRIVATE_VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_TX) + 2; -global PUBLIC_VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX) + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX); +global SCOPED_READ_REQUEST_LEN: u32 = READ_REQUEST_LENGTH + 1; +global PUBLIC_DATA_READ_LENGTH: u32 = 3; +global PRIVATE_VALIDATION_REQUESTS_LENGTH: u32 = ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_TX) + 2; +global PUBLIC_VALIDATION_REQUESTS_LENGTH: u32 = ROLLUP_VALIDATION_REQUESTS_LENGTH + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX) + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX); -global PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 3; -global COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NOTE_HASHES_PER_TX + MAX_NULLIFIERS_PER_TX + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + 3 + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; -global COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH + 1; +global PUBLIC_DATA_UPDATE_REQUEST_LENGTH: u32 = 3; +global COMBINED_ACCUMULATED_DATA_LENGTH: u32 = MAX_NOTE_HASHES_PER_TX + MAX_NULLIFIERS_PER_TX + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + 3 + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; +global COMBINED_CONSTANT_DATA_LENGTH: u32 = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH + 1; -global PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_TX) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (SCOPED_ENCRYPTED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (PUBLIC_CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); -global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + PRIVATE_VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PUBLIC_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; +global PRIVATE_ACCUMULATED_DATA_LENGTH: u32 = (SCOPED_NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_TX) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (SCOPED_ENCRYPTED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (PUBLIC_CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); +global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = 1 + PRIVATE_VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PUBLIC_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; -global PUBLIC_ACCUMULATED_DATA_LENGTH = (MAX_NOTE_HASHES_PER_TX * SCOPED_NOTE_HASH_LENGTH) + (MAX_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (MAX_NOTE_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_ENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) + GAS_LENGTH; -global PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = PUBLIC_VALIDATION_REQUESTS_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + 1 + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) + AZTEC_ADDRESS_LENGTH; +global PUBLIC_ACCUMULATED_DATA_LENGTH: u32 = (MAX_NOTE_HASHES_PER_TX * SCOPED_NOTE_HASH_LENGTH) + (MAX_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (MAX_NOTE_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_ENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) + GAS_LENGTH; +global PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = PUBLIC_VALIDATION_REQUESTS_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + 1 + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) + AZTEC_ADDRESS_LENGTH; -global KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + COMBINED_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 1 + AZTEC_ADDRESS_LENGTH; +global KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = ROLLUP_VALIDATION_REQUESTS_LENGTH + COMBINED_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 1 + AZTEC_ADDRESS_LENGTH; -global CONSTANT_ROLLUP_DATA_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 1 + GLOBAL_VARIABLES_LENGTH; +global CONSTANT_ROLLUP_DATA_LENGTH: u32 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 1 + GLOBAL_VARIABLES_LENGTH; // + 5 for rollup_type, height_in_block_tree, txs_effects_hash, out_hash, accumulated_fees -global BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; +global BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH: u32 = CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; // + 64 for 32 * FeeRecipient { recipient, value }, + 4 for previous_block_hash, end_block_hash, out_hash, vk_tree_root + 1 temporarily for prover_id -global BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 2 * APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 2 * GLOBAL_VARIABLES_LENGTH + 69; +global BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH: u32 = 2 * APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 2 * GLOBAL_VARIABLES_LENGTH + 69; global GET_NOTES_ORACLE_RETURN_LENGTH: u32 = 674; global NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: u32 = 32 * MAX_NOTE_HASHES_PER_TX; @@ -284,17 +284,17 @@ global NUM_MSGS_PER_BASE_PARITY: u32 = 4; global NUM_BASE_PARITY_PER_ROOT_PARITY: u32 = 4; // Lengths of the different types of proofs in fields -global RECURSIVE_PROOF_LENGTH = 439; -global NESTED_RECURSIVE_PROOF_LENGTH = 439; -global TUBE_PROOF_LENGTH = RECURSIVE_PROOF_LENGTH; // in the future these can differ +global RECURSIVE_PROOF_LENGTH: u32 = 439; +global NESTED_RECURSIVE_PROOF_LENGTH: u32 = 439; +global TUBE_PROOF_LENGTH: u32 = RECURSIVE_PROOF_LENGTH; // in the future these can differ -global VERIFICATION_KEY_LENGTH_IN_FIELDS = 128; +global VERIFICATION_KEY_LENGTH_IN_FIELDS: u32 = 128; // VK is composed of // - circuit size encoded as a fr field element (32 bytes) // - num of inputs encoded as a fr field element (32 bytes) // - 16 affine elements (curve base field fq) encoded as fr elements takes (16 * 4 * 32 bytes) // 16 above refers to the constant AvmFlavor::NUM_PRECOMPUTED_ENTITIES -global AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS = 2 + 16 * 4; +global AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS: u32 = 2 + 16 * 4; /** * Enumerate the hash_indices which are used for pedersen hashing. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr index 72e77f13ffa..0535468e478 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr @@ -117,12 +117,16 @@ mod tests { TestLeafPreimage { value: 30, next_value: 40 }, ]; - fn build_tree() -> NonEmptyMerkleTree<4, 3, 1, 2> { + global test_tree_height: u8 = 3; + global test_supertree_height: u8 = 1; + global test_subtree_height: u8 = 2; + + fn build_tree() -> NonEmptyMerkleTree<4, test_tree_height, test_supertree_height, test_subtree_height> { NonEmptyMerkleTree::new( leaf_preimages.map(|leaf_preimage: TestLeafPreimage| leaf_preimage.as_leaf()), - [0; 3], - [0; 1], - [0; 2] + [0; test_tree_height], + [0; test_supertree_height], + [0; test_subtree_height] ) } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/point.nr b/noir-projects/noir-protocol-circuits/crates/types/src/point.nr index f3737136951..5de69793449 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/point.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/point.nr @@ -1,7 +1,7 @@ pub use dep::std::embedded_curve_ops::EmbeddedCurvePoint as Point; use crate::{traits::{Deserialize, Empty, Hash, Serialize}, hash::poseidon2_hash}; -global POINT_LENGTH: Field = 3; +global POINT_LENGTH: u32 = 3; impl Serialize for Point { fn serialize(self: Self) -> [Field; POINT_LENGTH] { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/scalar.nr b/noir-projects/noir-protocol-circuits/crates/types/src/scalar.nr index ac674bf24c9..51379c120de 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/scalar.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/scalar.nr @@ -1,7 +1,7 @@ pub use dep::std::embedded_curve_ops::EmbeddedCurveScalar as Scalar; use crate::traits::{Empty, Serialize}; -global SCALAR_SIZE: Field = 2; +global SCALAR_SIZE: u32 = 2; impl Empty for Scalar { fn empty() -> Self { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/vk_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/vk_tree.nr index cf875776cc8..9cb521d9dbe 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/vk_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/vk_tree.nr @@ -10,7 +10,7 @@ use crate::constants::{ }; use crate::merkle_tree::merkle_tree::MerkleTree; -global VK_TREE_WIDTH = 32; +global VK_TREE_WIDTH: u32 = 32; #[test] fn check_vk_tree_width() { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr index d3e35504cb6..e2190c49967 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr @@ -12,7 +12,7 @@ use crate::meta::{derive_deserialize, derive_serialize}; // use the optional type for safety. Doing it now would lead to a worse devex // and would make it harder to sync up with the cpp code. // Preferred over Default trait to convey intent, as default doesn't necessarily mean empty. -trait Empty { +pub trait Empty { fn empty() -> Self; } @@ -56,11 +56,11 @@ pub fn is_empty_array(array: [T; N]) -> bool where T: Empty + Eq array.all(|elem| is_empty(elem)) } -trait Hash { +pub trait Hash { fn hash(self) -> Field; } -trait ToField { +pub trait ToField { fn to_field(self) -> Field; } @@ -150,7 +150,7 @@ impl FromField for U128 { // docs:start:serialize #[derive_via(derive_serialize)] -trait Serialize { +pub trait Serialize { fn serialize(self) -> [Field; N]; } // docs:end:serialize @@ -174,7 +174,7 @@ impl Serialize for str { // docs:start:deserialize #[derive_via(derive_deserialize)] -trait Deserialize { +pub trait Deserialize { fn deserialize(fields: [Field; N]) -> Self; } // docs:end:deserialize diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr b/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr index 474901eec9c..ac113fe2f79 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr @@ -1,11 +1,11 @@ use crate::traits::{Serialize, Deserialize}; -global BOOL_SERIALIZED_LEN: Field = 1; -global U8_SERIALIZED_LEN: Field = 1; -global U32_SERIALIZED_LEN: Field = 1; -global U64_SERIALIZED_LEN: Field = 1; -global U128_SERIALIZED_LEN: Field = 1; -global FIELD_SERIALIZED_LEN: Field = 1; +global BOOL_SERIALIZED_LEN: u32 = 1; +global U8_SERIALIZED_LEN: u32 = 1; +global U32_SERIALIZED_LEN: u32 = 1; +global U64_SERIALIZED_LEN: u32 = 1; +global U128_SERIALIZED_LEN: u32 = 1; +global FIELD_SERIALIZED_LEN: u32 = 1; impl Serialize for bool { fn serialize(self) -> [Field; BOOL_SERIALIZED_LEN] { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr index be6f88970f5..28c3b0062ff 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr @@ -69,7 +69,7 @@ mod tests { utils::arrays::assert_split_transformed_value_arrays::{assert_split_transformed_value_arrays, assert_split_transformed_value_arrays_with_hint} }; - global NUM_TEST_ITEMS = 5; + global NUM_TEST_ITEMS: u32 = 5; fn is_transformed(from: TestValue, to: Field) -> bool { from.value == to From 7d385e8735e14690f5e21881501f3085925e2620 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 06:48:40 +0000 Subject: [PATCH 26/79] revert --- noir-projects/noir-contracts/bootstrap.sh | 2 +- noir-projects/noir-protocol-circuits/bootstrap.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/noir-contracts/bootstrap.sh b/noir-projects/noir-contracts/bootstrap.sh index a3d0ae1a135..3eb62c4530f 100755 --- a/noir-projects/noir-contracts/bootstrap.sh +++ b/noir-projects/noir-contracts/bootstrap.sh @@ -17,7 +17,7 @@ fi echo "Compiling contracts..." NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} -nargo compile --silence-warnings +$NARGO compile --silence-warnings echo "Transpiling contracts..." scripts/transpile.sh \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/bootstrap.sh b/noir-projects/noir-protocol-circuits/bootstrap.sh index 80761a8a20e..ebc4e25f773 100755 --- a/noir-projects/noir-protocol-circuits/bootstrap.sh +++ b/noir-projects/noir-protocol-circuits/bootstrap.sh @@ -20,7 +20,7 @@ node ./generate_variants.js echo "Compiling protocol circuits..." NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} -nargo compile --silence-warnings +$NARGO compile --silence-warnings BB_HASH=${BB_HASH:-$(cd ../../ && git ls-tree -r HEAD | grep 'barretenberg/cpp' | awk '{print $3}' | git hash-object --stdin)} echo Using BB hash $BB_HASH From 10df443b5b7a405c715f5ad54ec0cbfc777d519b Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 08:16:51 +0000 Subject: [PATCH 27/79] one step to go --- .../aztec-nr/aztec/src/macros/mod.nr | 12 +++-- .../aztec-nr/aztec/src/macros/notes/mod.nr | 6 +++ .../crates/types/src/meta/mod.nr | 51 +++++++++++++++---- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 54c5c193147..976f60e338b 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -81,15 +81,17 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { let mut max_note_length: u32 = 0; - let notes = NOTES.values(); + let notes = NOTES.entries(); let body = if notes.len() > 0 { - max_note_length = notes.fold(0, | acc, (_, len, _): (StructDefinition, u32, Field) | { + max_note_length = notes.fold(0, | acc, (_, (_, len, _)): (Type, (StructDefinition, u32, Field)) | { acc + len }); + let if_statements = notes.map( - | (note, _, _): (StructDefinition, u32, Field) | { + | (_, (note, _, _)): (Type, (StructDefinition, u32, Field)) | { let note_name = note.name(); quote { + // $note if note_type_id == $note_name::get_note_type_id() { aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($note_name::deserialize_content, note_header, compute_nullifier, serialized_note) } @@ -138,7 +140,9 @@ pub comptime fn generate_note_exports() -> Quoted { pub comptime fn aztec(m: Module) -> Quoted { let interface = generate_contract_interface(m); - let unconstrained_functions = m.functions().filter(| f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute("test")); + let unconstrained_functions = m.functions().filter( + | f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute("test") & !f.has_named_attribute("public") + ); for f in unconstrained_functions { transform_unconstrained(f); } diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 6d97776c2a3..2db161c690f 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -59,6 +59,12 @@ comptime fn generate_note_interface( let fixed_fields_args = fixed_fields.map(| (name, _): (Quoted, Type) | quote{self.$name}).push_back(quote {self.get_header().storage_slot}).join(quote {,}); let nullable_fields_args = nullable_fields.map(|field| quote { self.$field }).join(quote {,}); + let deserialize_content_lambda = quote { + | value: [Field; $content_len] | { + $deserialized_content + } + }; + (quote { impl aztec::note::note_interface::NoteInterface<$content_len> for $name { fn to_be_bytes(self, storage_slot: Field) -> [u8; $content_len * 32 + 64] { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 74d50c89c16..7c8dc2cf50b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -1,6 +1,5 @@ use super::traits::{Serialize, Deserialize}; -// TODO: This is bad and incomplete. Fix it! pub comptime fn pack_from_fields( name: Quoted, typ: Type, @@ -9,7 +8,7 @@ pub comptime fn pack_from_fields( replacements: [(Quoted, Quoted)] ) -> (Quoted, u32) { let mut result = quote {}; - let mut consumed: u32 = already_consumed; + let mut consumed: u32 = 0; let found_replacements = replacements.filter(| (to_omit, _): (Quoted, Quoted) | to_omit == name); @@ -20,8 +19,8 @@ pub comptime fn pack_from_fields( }; if replacement == quote {} { - if typ.is_field() | typ.as_integer().is_some() { - result = quote { $buffer[$consumed] as $typ }; + if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { + result = quote { $buffer[$already_consumed] as $typ }; consumed = 1; } else if typ.as_struct().is_some() { let (nested_def, _) = typ.as_struct().unwrap(); @@ -33,7 +32,7 @@ pub comptime fn pack_from_fields( quote { $field_name }, field_type, quote { $buffer }, - consumed, + consumed + already_consumed, replacements ); consumed += consumed_by_field; @@ -49,12 +48,12 @@ pub comptime fn pack_from_fields( let (element_type, array_len) = typ.as_array().unwrap(); let array_len = array_len.as_constant().unwrap(); let mut array_fields_list = &[]; - for i in 0..array_len { + for _ in 0..array_len { let (deserialized_field, consumed_by_field) = pack_from_fields( quote { $name }, element_type, quote { $buffer }, - consumed, + consumed + already_consumed, replacements ); array_fields_list = array_fields_list.push_back(deserialized_field); @@ -62,6 +61,23 @@ pub comptime fn pack_from_fields( } let array_fields = array_fields_list.join(quote {,}); result = quote { [ $array_fields ] }; + } else if typ.as_str().is_some() { + let length_type = typ.as_str().unwrap(); + let str_len = length_type.as_constant().unwrap(); + let mut byte_list = &[]; + for _ in 0..str_len { + let (deserialized_field, consumed_by_field) = pack_from_fields( + quote { $name }, + quote { u8}.as_type(), + quote { $buffer }, + consumed + already_consumed, + replacements + ); + byte_list = byte_list.push_back(deserialized_field); + consumed += consumed_by_field; + } + let bytes = byte_list.join(quote {,}); + result = quote { [ $bytes ].as_str_unchecked() }; } else { assert(false, f"Unsupported type for serialization of argument {name} and type {typ}"); std::mem::zeroed() @@ -77,7 +93,7 @@ pub comptime fn flatten_to_fields(name: Quoted, typ: Type, omit: [Quoted]) -> ([ let mut aux_vars = &[]; if omit.all(| to_omit | to_omit != name) { - if typ.is_field() | typ.as_integer().is_some() { + if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { fields = fields.push_back(quote { $name as Field }); } else if typ.as_struct().is_some() { let nested_struct = typ.as_struct().unwrap(); @@ -163,7 +179,13 @@ struct Smol { b: Field, } -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Eq)] +struct HasArray { + a: [Field; 2], + b: bool +} + +#[derive(Serialize, Deserialize, Eq)] struct Fancier { a: Smol, b: [Field; 2], @@ -184,6 +206,15 @@ fn smol_test() { assert(deserialized == smol); } +#[test] +fn has_array_test() { + let has_array = HasArray { a: [1, 2], b: true }; + let serialized = has_array.serialize(); + assert(serialized == [1, 2, 1], serialized); + let deserialized = HasArray::deserialize(serialized); + assert(deserialized == has_array); +} + #[test] fn fancier_test() { let fancier = Fancier { a: Smol { a: 1, b: 2 }, b: [0, 1], c: [1, 2, 3], d: "metaprogramming!" }; @@ -193,4 +224,6 @@ fn fancier_test() { 1, 2, 0, 1, 1, 2, 3, 0x6d, 0x65, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x21 ], serialized ); + let deserialized = Fancier::deserialize(serialized); + assert(deserialized == fancier); } From 13e016f4c1f37b063d2e482bff3bde5cbbac6312 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 10:29:40 +0000 Subject: [PATCH 28/79] more fixing and updating aztec.nr --- .../aztec/src/macros/functions/interfaces.nr | 133 ++++++++++++++++- .../aztec/src/macros/functions/mod.nr | 134 +----------------- .../aztec-nr/aztec/src/macros/mod.nr | 11 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 8 +- .../aztec-nr/aztec/src/macros/storage/mod.nr | 4 +- .../src/dapp_payload.nr | 6 +- .../contracts/avm_test_contract/src/main.nr | 1 - .../contracts/card_game_contract/src/cards.nr | 8 +- .../contracts/card_game_contract/src/game.nr | 18 +-- .../contracts/card_game_contract/src/main.nr | 2 + .../contracts/claim_contract/src/main.nr | 5 +- .../src/capsule.nr | 4 +- .../src/main.nr | 4 +- .../crowdfunding_contract/src/main.nr | 5 +- .../src/types/card_note.nr | 2 +- .../docs_example_contract/src/types/leader.nr | 2 +- .../ecdsa_public_key_note/src/lib.nr | 4 +- .../contracts/lending_contract/src/asset.nr | 2 +- .../lending_contract/src/position.nr | 2 +- .../price_feed_contract/src/asset.nr | 2 +- .../private_fpc_contract/src/main.nr | 2 +- .../private_fpc_contract/src/settings.nr | 2 +- .../spam_contract/src/types/balance_set.nr | 12 +- 23 files changed, 184 insertions(+), 189 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr index f87f2e3da5d..2e1629b5d4f 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr @@ -1,4 +1,8 @@ -use std::{meta::type_of, collections::umap::UHashMap, hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher}}; +use std::{ + meta::{unquote, type_of}, collections::umap::UHashMap, + hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} +}; +use crate::macros::utils::{get_fn_visibility, is_fn_view, is_fn_private, add_to_field_slice, compute_fn_selector, is_fn_public}; comptime mut global STUBS: UHashMap> = UHashMap::default(); @@ -40,6 +44,133 @@ pub(crate) comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { result } +pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { + let fn_name = f.name(); + let fn_parameters = f.parameters(); + let fn_return_type = f.return_type(); + let fn_visibility = get_fn_visibility(f); + let is_static_call = is_fn_view(f); + let is_void = fn_return_type == type_of(()); + let fn_visibility_capitalized = if is_fn_private(f) { + quote { Private } + } else { + quote { Public } + }; + let is_static_call_capitalized = if is_static_call { + quote { Static } + } else { + quote { } + }; + let is_void_capitalized = if is_void { quote { Void } } else { quote { } }; + let args_acc_name = quote { args_acc }; + let args_acc = fn_parameters.fold( + quote { + let mut $args_acc_name = &[]; + }, + |args_hasher, param: (Quoted, Type)| { + let (name, typ) = param; + let appended_arg = add_to_field_slice(args_acc_name, name, typ); + quote { + $args_hasher + $appended_arg + } + } + ); + + let args_hash_name = if fn_visibility == quote { private } { + quote { args_hash } + } else { + quote {} + }; + + let args = if fn_visibility == quote { private } { + quote { + $args_acc + let $args_hash_name = dep::aztec::hash::hash_args($args_acc_name); + } + } else { + args_acc + }; + + let fn_parameters_list = fn_parameters.map( + | (name, typ): (Quoted, Type) | { + quote { $name: $typ } + } + ).join(quote{,}); + + let fn_name_str = fn_name.as_str_quote(); + + let fn_name_len: u32 = unquote!(quote { $fn_name_str.as_bytes().len()}); + + let arg_types_list = fn_parameters.map(|(_, typ): (_, Type)| quote { $typ }).join(quote {,}); + let arg_types = if fn_parameters.len() == 1 { + f"({arg_types_list},)".quoted_contents() + } else { + f"({arg_types_list})".quoted_contents() + }; + + let generics = if is_void { + f"{arg_types}>".quoted_contents() + } else { + f"{fn_return_type}, {arg_types}>".quoted_contents() + }; + + let call_interface_name = f"dep::aztec::context::call_interfaces::{fn_visibility_capitalized}{is_static_call_capitalized}{is_void_capitalized}CallInterface".quoted_contents(); + let call_interface_name_w_generics = f"{call_interface_name}<{fn_name_len}, {generics}".quoted_contents(); + + let fn_selector: Field = compute_fn_selector(f); + + let gas_opts = if is_fn_public(f) { + quote { gas_opts: dep::aztec::context::gas::GasOpts::default() } + } else { + quote {} + }; + + let input_type = f"crate::context::inputs::{fn_visibility_capitalized}ContextInputs".quoted_contents().as_type(); + + let return_type_hint = if is_fn_private(f) { + quote { protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs }.as_type() + } else { + fn_return_type + }; + + let parameter_names = if fn_parameters.len() > 0 { + let params = fn_parameters.map(|(name, _): (Quoted, _)| name).join(quote {,}); + f",{params}".quoted_contents() + } else { + quote {} + }; + + let original = quote { + | inputs: $input_type | -> $return_type_hint { + $fn_name(inputs $parameter_names) + } + }; + + let args_hash = if fn_visibility == quote { private } { + quote { $args_hash_name, } + } else { + quote {} + }; + + quote { + pub fn $fn_name(self, $fn_parameters_list) -> $call_interface_name_w_generics { + $args + let selector = dep::aztec::protocol_types::abis::function_selector::FunctionSelector::from_field($fn_selector); + $call_interface_name { + target_contract: self.target_contract, + selector, + name: $fn_name_str, + $args_hash + args: $args_acc_name, + original: $original, + is_static: $is_static_call, + $gas_opts + } + } + } +} + pub(crate) comptime fn register_stub(m: Module, stub: Quoted) { let current_stubs = STUBS.get(m); let stubs_to_insert = if current_stubs.is_some() { diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 7e0dba2bf62..b2387ae4599 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -1,13 +1,12 @@ mod interfaces; -use std::meta::{type_of, unquote}; +use std::meta::type_of; use super::utils::{ modify_fn_body, is_fn_private, get_fn_visibility, is_fn_view, is_fn_initializer, is_fn_internal, - fn_has_noinitcheck, compute_fn_selector, add_to_field_slice, add_to_hasher, is_fn_public, - module_has_storage, module_has_initializer + fn_has_noinitcheck, add_to_hasher, module_has_storage, module_has_initializer }; -use interfaces::{create_fn_abi_export, register_stub}; +use interfaces::{create_fn_abi_export, register_stub, stub_fn}; // Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] pub comptime fn internal(_f: FunctionDefinition) {} @@ -255,130 +254,3 @@ pub comptime fn transform_unconstrained(f: FunctionDefinition) { f.set_return_public(true); f.set_body(modified_body); } - -pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { - let fn_name = f.name(); - let fn_parameters = f.parameters(); - let fn_return_type = f.return_type(); - let fn_visibility = get_fn_visibility(f); - let is_static_call = is_fn_view(f); - let is_void = fn_return_type == type_of(()); - let fn_visibility_capitalized = if is_fn_private(f) { - quote { Private } - } else { - quote { Public } - }; - let is_static_call_capitalized = if is_static_call { - quote { Static } - } else { - quote { } - }; - let is_void_capitalized = if is_void { quote { Void } } else { quote { } }; - let args_acc_name = quote { args_acc }; - let args_acc = fn_parameters.fold( - quote { - let mut $args_acc_name = &[]; - }, - |args_hasher, param: (Quoted, Type)| { - let (name, typ) = param; - let appended_arg = add_to_field_slice(args_acc_name, name, typ); - quote { - $args_hasher - $appended_arg - } - } - ); - - let args_hash_name = if fn_visibility == quote { private } { - quote { args_hash } - } else { - quote {} - }; - - let args = if fn_visibility == quote { private } { - quote { - $args_acc - let $args_hash_name = dep::aztec::hash::hash_args($args_acc_name); - } - } else { - args_acc - }; - - let fn_parameters_list = fn_parameters.map( - | (name, typ): (Quoted, Type) | { - quote { $name: $typ } - } - ).join(quote{,}); - - let fn_name_str = fn_name.as_str_quote(); - - let fn_name_len: u32 = unquote!(quote { $fn_name_str.as_bytes().len()}); - - let arg_types_list = fn_parameters.map(|(_, typ): (_, Type)| quote { $typ }).join(quote {,}); - let arg_types = if fn_parameters.len() == 1 { - f"({arg_types_list},)".quoted_contents() - } else { - f"({arg_types_list})".quoted_contents() - }; - - let generics = if is_void { - f"{arg_types}>".quoted_contents() - } else { - f"{fn_return_type}, {arg_types}>".quoted_contents() - }; - - let call_interface_name = f"dep::aztec::context::call_interfaces::{fn_visibility_capitalized}{is_static_call_capitalized}{is_void_capitalized}CallInterface".quoted_contents(); - let call_interface_name_w_generics = f"{call_interface_name}<{fn_name_len}, {generics}".quoted_contents(); - - let fn_selector: Field = compute_fn_selector(f); - - let gas_opts = if is_fn_public(f) { - quote { gas_opts: dep::aztec::context::gas::GasOpts::default() } - } else { - quote {} - }; - - let input_type = f"crate::context::inputs::{fn_visibility_capitalized}ContextInputs".quoted_contents().as_type(); - - let return_type_hint = if is_fn_private(f) { - quote { protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs }.as_type() - } else { - fn_return_type - }; - - let parameter_names = if fn_parameters.len() > 0 { - let params = fn_parameters.map(|(name, _): (Quoted, _)| name).join(quote {,}); - f",{params}".quoted_contents() - } else { - quote {} - }; - - let original = quote { - | inputs: $input_type | -> $return_type_hint { - $fn_name(inputs $parameter_names) - } - }; - - let args_hash = if fn_visibility == quote { private } { - quote { $args_hash_name, } - } else { - quote {} - }; - - quote { - pub fn $fn_name(self, $fn_parameters_list) -> $call_interface_name_w_generics { - $args - let selector = dep::aztec::protocol_types::abis::function_selector::FunctionSelector::from_field($fn_selector); - $call_interface_name { - target_contract: self.target_contract, - selector, - name: $fn_name_str, - $args_hash - args: $args_acc_name, - original: $original, - is_static: $is_static_call, - $gas_opts - } - } - } -} diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 976f60e338b..fd30b417026 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -20,8 +20,8 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { quote {} }; - let has_storage = module_has_storage(m); - let storage_layout_getter = if has_storage & STORAGE_LAYOUT_NAME.get(m).is_some() { + let has_storage_layout = module_has_storage(m) & STORAGE_LAYOUT_NAME.get(m).is_some(); + let storage_layout_getter = if has_storage_layout { let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap(); quote { pub fn storage_layout() -> StorageLayout { @@ -32,7 +32,7 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { quote {} }; - let library_storage_layout_getter = if has_storage { + let library_storage_layout_getter = if has_storage_layout { quote { #[contract_library_method] $storage_layout_getter @@ -91,7 +91,6 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quote | (_, (note, _, _)): (Type, (StructDefinition, u32, Field)) | { let note_name = note.name(); quote { - // $note if note_type_id == $note_name::get_note_type_id() { aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($note_name::deserialize_content, note_header, compute_nullifier, serialized_note) } @@ -147,12 +146,12 @@ pub comptime fn aztec(m: Module) -> Quoted { transform_unconstrained(f); } - let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); + //let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); let note_exports = generate_note_exports(); quote { $note_exports $interface - $compute_note_hash_and_optionally_a_nullifier + //$compute_note_hash_and_optionally_a_nullifier } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 2db161c690f..3cc00c27a56 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -53,18 +53,12 @@ comptime fn generate_note_interface( typ, quote { value }, 0, - &[(quote {header}, quote { NoteHeader::empty() })] + &[(quote {header}, quote { aztec::note::note_header::NoteHeader::empty() })] ); let fixed_fields_args = fixed_fields.map(| (name, _): (Quoted, Type) | quote{self.$name}).push_back(quote {self.get_header().storage_slot}).join(quote {,}); let nullable_fields_args = nullable_fields.map(|field| quote { self.$field }).join(quote {,}); - let deserialize_content_lambda = quote { - | value: [Field; $content_len] | { - $deserialized_content - } - }; - (quote { impl aztec::note::note_interface::NoteInterface<$content_len> for $name { fn to_be_bytes(self, storage_slot: Field) -> [u8; $content_len * 32 + 64] { diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index d8975588dff..176311323c3 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -10,8 +10,8 @@ comptime mut global STORAGE_LAYOUT_NAME: UHashMap bool { if typ.as_struct().is_some() { - let (_, generics) = typ.as_struct().unwrap(); - let maybe_map = if generics.len() == 3 { + let (def, generics) = typ.as_struct().unwrap(); + let maybe_map = if (def.name() == quote { Map }) & (generics.len() == 3) { let maybe_key = generics[0]; let maybe_value = generics[1]; let maybe_context = generics[2]; diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr index 592f2cbe441..6b938ea6bc5 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr @@ -6,11 +6,11 @@ use dep::aztec::protocol_types::{ use dep::authwit::entrypoint::function_call::FunctionCall; -global DAPP_MAX_CALLS: u64 = 1; +global DAPP_MAX_CALLS: u32 = 1; // FUNCTION_CALL_SIZE * DAPP_MAX_CALLS + 1 -global DAPP_PAYLOAD_SIZE: u64 = 6; +global DAPP_PAYLOAD_SIZE: u32 = 6; // FUNCTION_CALL_SIZE_IN_BYTES * DAPP_MAX_CALLS + 32 -global DAPP_PAYLOAD_SIZE_IN_BYTES: u64 = 130; +global DAPP_PAYLOAD_SIZE_IN_BYTES: u32 = 130; // Note: If you change the following struct you have to update default_entrypoint.ts // docs:start:app-payload-struct diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index ea74cc00ec6..273da571ce7 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -39,7 +39,6 @@ contract AvmTest { use dep::aztec::macros::{storage::storage, functions::{public, private}}; use dep::aztec::context::gas::GasOpts; - #[storage] struct Storage { single: PublicMutable, diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index 543e33357d0..fefa9f4c8d7 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -68,7 +68,7 @@ struct Deck { set: PrivateSet, } -pub fn filter_cards( +pub fn filter_cards( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], desired_cards: [Card; N] ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { @@ -102,7 +102,7 @@ impl Deck { } impl Deck<&mut PrivateContext> { - pub fn add_cards(&mut self, cards: [Card; N], owner: AztecAddress) -> [CardNote] { + pub fn add_cards(&mut self, cards: [Card; N], owner: AztecAddress) -> [CardNote] { let owner_keys = get_current_public_keys(self.set.context, owner); let owner_ivpk_m = owner_keys.ivpk_m; let owner_npk_m_hash = owner_keys.npk_m.hash(); @@ -120,7 +120,7 @@ impl Deck<&mut PrivateContext> { inserted_cards } - pub fn remove_cards(&mut self, cards: [Card; N]) { + pub fn remove_cards(&mut self, cards: [Card; N]) { let options = NoteGetterOptions::with_filter(filter_cards, cards); let notes = self.set.pop_notes(options); assert(notes.len() == N, "Not all cards were removed"); @@ -173,7 +173,7 @@ pub fn get_pack_cards( cards } -pub fn compute_deck_strength(cards: [Card; N]) -> Field { +pub fn compute_deck_strength(cards: [Card; N]) -> Field { cards.fold( 0, |acc, card: Card| { diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr index 057c40640cc..5da0b4b6698 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr @@ -1,8 +1,8 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Serialize, Deserialize}}; use crate::cards::Card; -global NUMBER_OF_PLAYERS: u64 = 2; -global NUMBER_OF_CARDS_DECK: u64 = 2; +global NUMBER_OF_PLAYERS: u32 = 2; +global NUMBER_OF_CARDS_DECK: u32 = 2; struct PlayerEntry { address: AztecAddress, @@ -16,7 +16,7 @@ impl PlayerEntry { } } -global PLAYER_SERIALIZED_LEN: Field = 3; +global PLAYER_SERIALIZED_LEN: u32 = 3; impl Deserialize for PlayerEntry { fn deserialize(fields: [Field; PLAYER_SERIALIZED_LEN]) -> PlayerEntry { @@ -36,7 +36,7 @@ impl Eq for PlayerEntry { } } -global PLAYABLE_CARDS = 4; +global PLAYABLE_CARDS: u32 = 4; struct Game { players: [PlayerEntry; NUMBER_OF_PLAYERS], @@ -44,11 +44,11 @@ struct Game { started: bool, finished: bool, claimed: bool, - current_player: u64, - current_round: u64, + current_player: u32, + current_round: u32, } -global GAME_SERIALIZED_LEN: Field = 15; +global GAME_SERIALIZED_LEN: u32 = 15; impl Serialize for Game { fn serialize(game: Game) -> [Field; GAME_SERIALIZED_LEN] { @@ -88,8 +88,8 @@ impl Deserialize for Game { started: fields[10] as bool, finished: fields[11] as bool, claimed: fields[12] as bool, - current_player: fields[13] as u64, - current_round: fields[14] as u64 + current_player: fields[13] as u32, + current_round: fields[14] as u32 } } } diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr index 095f870193b..62367267c5d 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr @@ -14,6 +14,8 @@ contract CardGame { use crate::game::{PLAYABLE_CARDS, PlayerEntry, Game}; use dep::aztec::macros::{storage::storage, functions::{private, public, internal}}; + use value_note::value_note::ValueNote; + #[storage] struct Storage { collections: Map, Context>, diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index 3ba37a8698c..93d42b7e9ee 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -3,13 +3,12 @@ use dep::aztec::macros::aztec; #[aztec] contract Claim { use dep::aztec::{ - note::utils::compute_note_hash_for_nullify, - protocol_types::address::AztecAddress, + note::utils::compute_note_hash_for_nullify, protocol_types::address::AztecAddress, state_vars::SharedImmutable, macros::{storage::storage, functions::{private, public, initializer}} }; use dep::value_note::value_note::ValueNote; - use dep::token::Token; + use token::Token; #[storage] struct Storage { diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr index 99c90896b4a..32d739f3946 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr @@ -2,10 +2,10 @@ // docs:start:pop_capsule #[oracle(popCapsule)] -unconstrained fn pop_capsule_oracle() -> [Field; N] {} +unconstrained fn pop_capsule_oracle() -> [Field; N] {} // A capsule is a "blob" of data that is passed to the contract through an oracle. -unconstrained pub fn pop_capsule() -> [Field; N] { +unconstrained pub fn pop_capsule() -> [Field; N] { pop_capsule_oracle() } // docs:end:pop_capsule \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 572a406c40f..a4ecf782c50 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -149,13 +149,13 @@ contract ContractClassRegisterer { // - Unconstrained function -> we provide a membership proof // Ordinary logs are not protected by the above so this fn shouldn't be called by anything else #[contract_library_method] - pub fn emit_contract_class_unencrypted_log(context: &mut PrivateContext, log: [Field; N]) { + pub fn emit_contract_class_unencrypted_log(context: &mut PrivateContext, log: [Field; N]) { let contract_address = context.this_address(); let counter = context.next_counter(); let log_hash = emit_contract_class_unencrypted_log_private_internal(contract_address, log, counter); // 40 = addr (32) + raw log len (4) + processed log len (4) let len = 40 + N * 32; - let side_effect = LogHash { value: log_hash, counter, length: len }; + let side_effect = LogHash { value: log_hash, counter, length: len as Field }; context.unencrypted_logs_hashes.push(side_effect); } } diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index 0959c5df4f0..099e0834d3c 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -9,8 +9,7 @@ contract Crowdfunding { use dep::aztec::{ encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, keys::getters::get_current_public_keys, prelude::{AztecAddress, PrivateSet, SharedImmutable}, - utils::comparison::Comparator, - unencrypted_logs::unencrypted_event_emission::encode_event, + utils::comparison::Comparator, unencrypted_logs::unencrypted_event_emission::encode_event, macros::{storage::storage, events::event, functions::{public, initializer, private, internal}}, protocol_types::traits::Serialize }; @@ -18,7 +17,7 @@ contract Crowdfunding { // docs:start:import_valuenote use dep::value_note::value_note::ValueNote; // docs:end:import_valuenote - use dep::token::Token; + use token::Token; use router::utils::privately_check_timestamp; // docs:end:all-deps diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 14a11bf4d87..8c4c3a2c39c 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -6,7 +6,7 @@ use dep::aztec::{ }; // docs:start:state_vars-CardNote -global CARD_NOTE_LEN: u64 = 3; // 3 plus a header. +global CARD_NOTE_LEN: u32 = 3; // 3 plus a header. #[note] struct CardNote { diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr index 85f1b08199d..9678f2d5668 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr @@ -6,7 +6,7 @@ struct Leader { points: u8, } -global LEADER_SERIALIZED_LEN: Field = 2; +global LEADER_SERIALIZED_LEN: u32 = 2; impl Deserialize for Leader { fn deserialize(fields: [Field; LEADER_SERIALIZED_LEN]) -> Self { diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index 19270ec8846..72594080837 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -9,9 +9,9 @@ use dep::aztec::{ use std::hash::from_field_unsafe; -global ECDSA_PUBLIC_KEY_NOTE_LEN: Field = 5; +global ECDSA_PUBLIC_KEY_NOTE_LEN: u32 = 5; // ECDSA_PUBLIC_KEY_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global ECDSA_PUBLIC_KEY_NOTE_BYTES_LEN: Field = 5 * 32 + 64; +global ECDSA_PUBLIC_KEY_NOTE_BYTES_LEN: u32 = 5 * 32 + 64; // Stores an ECDSA public key composed of two 32-byte elements // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr index 7440df2640f..fe0f0153048 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr @@ -13,7 +13,7 @@ struct Asset { oracle: AztecAddress, } -global SERIALIZED_LEN: Field = 6; +global SERIALIZED_LEN: u32 = 6; impl Serialize for Asset { fn serialize(Asset: Asset) -> [Field; SERIALIZED_LEN] { diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/position.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/position.nr index 7a2b9a0cb1e..2e575428e1c 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/position.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/position.nr @@ -6,7 +6,7 @@ struct Position { debt: Field, } -global POSITION_SERIALIZED_LEN: Field = 3; +global POSITION_SERIALIZED_LEN: u32 = 3; impl Serialize for Position { fn serialize(position: Position) -> [Field; POSITION_SERIALIZED_LEN] { diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr index 147c33c0e6c..86ecc9a90fc 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr @@ -4,7 +4,7 @@ struct Asset { price: U128, } -global ASSET_SERIALIZED_LEN: Field = 2; +global ASSET_SERIALIZED_LEN: u32 = 2; impl Serialize for Asset { fn serialize(asset: Asset) -> [Field; ASSET_SERIALIZED_LEN] { diff --git a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr index 8a5a42f0a20..910cff462d0 100644 --- a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/main.nr @@ -9,7 +9,7 @@ contract PrivateFPC { state_vars::SharedImmutable, macros::{storage::storage, functions::{private, initializer, public}} }; - use dep::token::Token; + use token::Token; use crate::settings::Settings; #[storage] diff --git a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/settings.nr b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/settings.nr index 3c51a1861a0..934b44dd476 100644 --- a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/settings.nr +++ b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/settings.nr @@ -1,6 +1,6 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Serialize, Deserialize}}; -global SETTINGS_LENGTH = 2; +global SETTINGS_LENGTH: u32 = 2; struct Settings { other_asset: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr index 69cb4a14334..a6496ac4c85 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr @@ -19,11 +19,11 @@ impl BalanceSet { } impl BalanceSet { - unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { + unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { self.balance_of_with_offset(0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, offset: u32 ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { @@ -46,7 +46,7 @@ impl BalanceSet { } impl BalanceSet { - pub fn add( + pub fn add( self: Self, owner_npk_m: NpkM, addend: U128 @@ -63,7 +63,7 @@ impl BalanceSet { } } - pub fn sub( + pub fn sub( self: Self, owner_npk_m: NpkM, amount: U128 @@ -85,7 +85,7 @@ impl BalanceSet { // The `max_notes` parameter is used to fine-tune the number of constraints created by this function. The gate count // scales relatively linearly with `max_notes`, but a lower `max_notes` parameter increases the likelihood of // `try_sub` subtracting an amount smaller than `target_amount`. - pub fn try_sub( + pub fn try_sub( self: Self, target_amount: U128, max_notes: u32 @@ -115,7 +115,7 @@ impl BalanceSet { // The preprocessor (a filter applied in an unconstrained context) does not check if total sum is larger or equal to // 'min_sum' - all it does is remove extra notes if it does reach that value. // Note that proper usage of this preprocessor requires for notes to be sorted in descending order. -pub fn preprocess_notes_min_sum( +pub fn preprocess_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + NullifiableNote + OwnedNote { From 03e6b094108021a8ecfcaa758c28cb6c66593ca8 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 11:55:55 +0000 Subject: [PATCH 29/79] final fixes --- .../aztec-nr/aztec/src/macros/functions/interfaces.nr | 10 +++++++++- .../noir-contracts/contracts/test_contract/src/main.nr | 2 +- .../contracts/test_log_contract/src/test.nr | 0 .../contracts/token_blacklist_contract/src/main.nr | 5 +++-- .../token_blacklist_contract/src/types/balances_map.nr | 10 +++++----- 5 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 noir-projects/noir-contracts/contracts/test_log_contract/src/test.nr diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr index 2e1629b5d4f..a3b37a2dd97 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr @@ -47,7 +47,15 @@ pub(crate) comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let fn_name = f.name(); let fn_parameters = f.parameters(); + // Fixes [ typ ; ( len : numeric Field ) ] error let fn_return_type = f.return_type(); + let fn_return_type_quoted = if fn_return_type.as_array().is_some() { + let (element_type, array_len) = fn_return_type.as_array().unwrap(); + let array_len = array_len.as_constant().unwrap(); + quote { [$element_type; $array_len] } + } else { + quote { $fn_return_type } + }; let fn_visibility = get_fn_visibility(f); let is_static_call = is_fn_view(f); let is_void = fn_return_type == type_of(()); @@ -112,7 +120,7 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let generics = if is_void { f"{arg_types}>".quoted_contents() } else { - f"{fn_return_type}, {arg_types}>".quoted_contents() + f"{fn_return_type_quoted}, {arg_types}>".quoted_contents() }; let call_interface_name = f"dep::aztec::context::call_interfaces::{fn_visibility_capitalized}{is_static_call_capitalized}{is_void_capitalized}CallInterface".quoted_contents(); diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 4f0e789dd63..f5873ec0ec5 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -42,7 +42,7 @@ contract Test { }; use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash}; use dep::value_note::value_note::ValueNote; - // TODO investigate why the macros require EmbeddableCurvePoint and EmbeddableCurveScalar + // TODO investigate why the macros require EmbeddedCurvePoint and EmbeddedCurveScalar use std::embedded_curve_ops::{EmbeddedCurveScalar, EmbeddedCurvePoint, fixed_base_scalar_mul as derive_public_key}; use std::meta::derive; diff --git a/noir-projects/noir-contracts/contracts/test_log_contract/src/test.nr b/noir-projects/noir-contracts/contracts/test_log_contract/src/test.nr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 2b7ca063b5f..45cc7e76994 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -16,7 +16,8 @@ contract TokenBlacklist { use dep::aztec::{ hash::compute_secret_hash, prelude::{AztecAddress, Map, NoteGetterOptions, PrivateSet, PublicMutable, SharedMutable}, - encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note_unconstrained, encode_and_encrypt_note}, utils::comparison::Comparator, + encrypted_logs::encrypted_note_emission::{encode_and_encrypt_note_unconstrained, encode_and_encrypt_note}, + utils::comparison::Comparator, macros::{storage::storage, functions::{private, public, initializer, view, internal}} }; @@ -25,7 +26,7 @@ contract TokenBlacklist { use crate::types::{transparent_note::TransparentNote, token_note::TokenNote, balances_map::BalancesMap, roles::UserFlags}; // Changing an address' roles has a certain block delay before it goes into effect. - global CHANGE_ROLES_DELAY_BLOCKS = 2; + global CHANGE_ROLES_DELAY_BLOCKS: u32 = 2; #[storage] struct Storage { diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index f0649e364b7..c4361d1c1d3 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -24,14 +24,14 @@ impl BalancesMap { } impl BalancesMap { - unconstrained pub fn balance_of( + unconstrained pub fn balance_of( self: Self, owner: AztecAddress ) -> U128 where T: NoteInterface + NullifiableNote + OwnedNote { self.balance_of_with_offset(owner, 0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, owner: AztecAddress, offset: u32 @@ -55,7 +55,7 @@ impl BalancesMap { } impl BalancesMap { - pub fn add( + pub fn add( self: Self, owner: AztecAddress, addend: U128 @@ -75,7 +75,7 @@ impl BalancesMap { } } - pub fn sub( + pub fn sub( self: Self, owner: AztecAddress, subtrahend: U128 @@ -100,7 +100,7 @@ impl BalancesMap { } } -pub fn filter_notes_min_sum( +pub fn filter_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { From 5a292b38e133436e05eee3c99967c109079b1ec4 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 13:06:34 +0000 Subject: [PATCH 30/79] more generic numerics --- .../noir-protocol-circuits/crates/blob/src/config.nr | 10 +++++----- .../crates/parity-lib/src/root/root_parity_inputs.nr | 2 +- .../reset-kernel-lib/src/reset/read_request.nr | 10 ++++++++-- .../crates/rollup-lib/src/base/base_rollup_inputs.nr | 4 ++-- .../crates/types/src/merkle_tree/membership.nr | 12 ++++-------- .../crates/types/src/tests/merkle_tree_utils.nr | 12 ++++++------ .../noir-protocol-circuits/generate_variants.js | 2 +- 7 files changed, 27 insertions(+), 25 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr b/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr index 5062a5506a3..8b3fbac3339 100644 --- a/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr +++ b/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr @@ -2,11 +2,11 @@ use dep::bigint::{BigNum, fields::bls12_381Fr::BLS12_381_Fr_Params}; type F = BigNum<3, BLS12_381_Fr_Params>; -global FIELDS_PER_BLOB: u64 = 4096; -global LOG_FIELDS_PER_BLOB: u64 = 12; -global EXTRA_FIELDS_PER_BLOB: u64 = 16; // 16 = floor(4096 FIELDS_PER_BLOB / 254 noir_field_bits), wasting only 32 bits. -global NOIR_FIELDS_PER_BLOB: u64 = FIELDS_PER_BLOB + EXTRA_FIELDS_PER_BLOB; -global FIELDS_CARRYING_AN_EXTRA_BIT_PER_BLOB: u64 = EXTRA_FIELDS_PER_BLOB * 254; // EXTRA_FIELDS_PER_BLOB * 254 = 4064. So the first 4064 bls Fr fields in the blob will carry an extra bit in their 255th bit position, that will be used to reconstitute 16 extra fields. +global FIELDS_PER_BLOB: u32 = 4096; +global LOG_FIELDS_PER_BLOB: u32 = 12; +global EXTRA_FIELDS_PER_BLOB: u32 = 16; // 16 = floor(4096 FIELDS_PER_BLOB / 254 noir_field_bits), wasting only 32 bits. +global NOIR_FIELDS_PER_BLOB: u32 = FIELDS_PER_BLOB + EXTRA_FIELDS_PER_BLOB; +global FIELDS_CARRYING_AN_EXTRA_BIT_PER_BLOB: u32 = EXTRA_FIELDS_PER_BLOB * 254; // EXTRA_FIELDS_PER_BLOB * 254 = 4064. So the first 4064 bls Fr fields in the blob will carry an extra bit in their 255th bit position, that will be used to reconstitute 16 extra fields. global D: F = BigNum { limbs: [4096, 0, 0] }; global D_INV = BigNum { limbs: [0x686828bfce5c19400fffff00100001, 0x6878b46ae3705eb6a46a89213de7d3, 0x73e6] }; diff --git a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr index a40fef1590c..659ed678997 100644 --- a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr @@ -4,7 +4,7 @@ use crate::{ utils::sha256_merkle_tree::Sha256MerkleTree }; -global NUM_BASE_PARITY_PER_ROOT_PARITY: u64 = 4; +global NUM_BASE_PARITY_PER_ROOT_PARITY: u32 = 4; struct RootParityInputs { children: [RootParityInput; NUM_BASE_PARITY_PER_ROOT_PARITY], diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr index b7196b494f2..5411441bfa2 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr @@ -86,7 +86,13 @@ fn validate_pending_read_requests( +fn validate_settled_read_requests< + let READ_REQUEST_LEN: u32, + let NUM_SETTLED_READS: u32, + H, + let TREE_HEIGHT: u32, + LEAF_PREIMAGE +>( read_requests: [ScopedReadRequest; READ_REQUEST_LEN], hints: [H; NUM_SETTLED_READS], tree_root: Field @@ -143,7 +149,7 @@ pub fn verify_reset_read_requests< let NUM_PENDING_READS: u32, let NUM_SETTLED_READS: u32, H, - TREE_HEIGHT, + let TREE_HEIGHT: u32, LEAF_PREIMAGE >( read_requests: [ScopedReadRequest; READ_REQUEST_LEN], diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 937af0792e2..ffaf9527fc2 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -492,8 +492,8 @@ mod tests { value: Field, } - global MAX_nullifiers_PER_TEST = 4; - global MAX_PUBLIC_DATA_READS_PER_TEST = 2; + global MAX_nullifiers_PER_TEST: u32 = 4; + global MAX_PUBLIC_DATA_READS_PER_TEST: u32 = 2; fn update_public_data_tree( public_data_tree: &mut NonEmptyMerkleTree, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr index 0535468e478..72e77f13ffa 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr @@ -117,16 +117,12 @@ mod tests { TestLeafPreimage { value: 30, next_value: 40 }, ]; - global test_tree_height: u8 = 3; - global test_supertree_height: u8 = 1; - global test_subtree_height: u8 = 2; - - fn build_tree() -> NonEmptyMerkleTree<4, test_tree_height, test_supertree_height, test_subtree_height> { + fn build_tree() -> NonEmptyMerkleTree<4, 3, 1, 2> { NonEmptyMerkleTree::new( leaf_preimages.map(|leaf_preimage: TestLeafPreimage| leaf_preimage.as_leaf()), - [0; test_tree_height], - [0; test_supertree_height], - [0; test_subtree_height] + [0; 3], + [0; 1], + [0; 2] ) } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr index 4cc3700875a..c9eb336efd9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr @@ -65,14 +65,14 @@ fn test_merkle_tree_update_leaf_three_layers() { assert_eq(tree.get_root(), calculate_empty_tree_root(3)); } -struct NonEmptyMerkleTree { +struct NonEmptyMerkleTree { subtree: MerkleTree, zero_hashes: [Field; TREE_HEIGHT], left_supertree_branch: [Field; SUPERTREE_HEIGHT], _phantom_subtree_height: [Field; SUBTREE_HEIGHT], } -impl Empty for NonEmptyMerkleTree { +impl Empty for NonEmptyMerkleTree { fn empty() -> Self { NonEmptyMerkleTree { subtree: MerkleTree::empty(), @@ -83,7 +83,7 @@ impl NonEmptyMerkleTree { +impl NonEmptyMerkleTree { pub fn new( non_zero_leaves: [Field; SUBTREE_ITEMS], _tree_height: [Field; TREE_HEIGHT], @@ -94,7 +94,7 @@ impl Date: Wed, 18 Sep 2024 13:40:41 +0000 Subject: [PATCH 31/79] fix: address a bunch of issues with generics --- .../aztec-nr/address-note/src/address_note.nr | 4 +- .../aztec-nr/authwit/src/cheatcodes.nr | 4 +- .../aztec-nr/authwit/src/entrypoint/app.nr | 6 +- .../aztec-nr/authwit/src/entrypoint/fee.nr | 6 +- .../authwit/src/entrypoint/function_call.nr | 4 +- .../aztec/src/encrypted_logs/incoming_body.nr | 10 +-- .../aztec/src/history/note_inclusion.nr | 4 +- .../aztec/src/history/note_validity.nr | 4 +- .../aztec/src/history/nullifier_inclusion.nr | 4 +- .../src/history/nullifier_non_inclusion.nr | 4 +- .../aztec-nr/aztec/src/note/lifecycle.nr | 8 +- .../aztec-nr/aztec/src/note/note_header.nr | 2 +- .../aztec/src/state_vars/private_immutable.nr | 6 +- .../aztec/src/state_vars/private_mutable.nr | 4 +- .../aztec/src/state_vars/public_immutable.nr | 4 +- .../aztec/src/state_vars/public_mutable.nr | 4 +- .../aztec/src/state_vars/shared_immutable.nr | 6 +- .../shared_mutable/scheduled_delay_change.nr | 6 +- .../scheduled_delay_change/test.nr | 12 +-- .../shared_mutable_private_getter.nr | 6 +- .../src/test/helpers/test_environment.nr | 4 +- .../aztec/src/test/mocks/mock_note.nr | 4 +- .../aztec-nr/uint-note/src/uint_note.nr | 4 +- .../aztec-nr/value-note/src/value_note.nr | 4 +- .../src/dapp_payload.nr | 6 +- .../src/subscription_note.nr | 4 +- .../contracts/auth_contract/src/main.nr | 2 +- .../contracts/card_game_contract/src/cards.nr | 8 +- .../contracts/card_game_contract/src/game.nr | 14 ++-- .../src/capsule.nr | 4 +- .../src/main.nr | 4 +- .../src/types/card_note.nr | 4 +- .../docs_example_contract/src/types/leader.nr | 2 +- .../token_contract/src/types/balance_set.nr | 12 +-- .../token_contract/src/types/token_note.nr | 4 +- .../src/types/transparent_note.nr | 6 +- .../crates/types/src/abis/event_selector.nr | 2 +- .../types/src/abis/function_selector.nr | 2 +- .../types/src/abis/note_hash_leaf_preimage.nr | 2 +- .../types/src/address/partial_address.nr | 2 +- .../crates/types/src/constants.nr | 80 +++++++++---------- .../types/src/merkle_tree/membership.nr | 2 + .../crates/types/src/point.nr | 2 +- .../types/src/recursion/verification_key.nr | 2 +- .../crates/types/src/scalar.nr | 2 +- .../types/src/tests/fixtures/vk_tree.nr | 2 +- .../types/src/tests/merkle_tree_utils.nr | 12 +-- .../crates/types/src/type_serialization.nr | 12 +-- .../assert_split_transformed_value_arrays.nr | 2 +- 49 files changed, 160 insertions(+), 158 deletions(-) diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index 6be58816d1e..cec5e576629 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -7,9 +7,9 @@ use dep::aztec::{ oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext }; -global ADDRESS_NOTE_LEN: Field = 3; +global ADDRESS_NOTE_LEN: u32 = 3; // ADDRESS_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global ADDRESS_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global ADDRESS_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; // docs:start:address_note_def // docs:start:address_note_struct diff --git a/noir-projects/aztec-nr/authwit/src/cheatcodes.nr b/noir-projects/aztec-nr/authwit/src/cheatcodes.nr index 74e8b3621de..bb770da9866 100644 --- a/noir-projects/aztec-nr/authwit/src/cheatcodes.nr +++ b/noir-projects/aztec-nr/authwit/src/cheatcodes.nr @@ -6,7 +6,7 @@ use dep::aztec::{ use crate::auth::{compute_inner_authwit_hash, compute_authwit_message_hash, set_authorized}; -pub fn add_private_authwit_from_call_interface( +pub fn add_private_authwit_from_call_interface( on_behalf_of: AztecAddress, caller: AztecAddress, call_interface: C @@ -22,7 +22,7 @@ pub fn add_private_authwit_from_call_interface( cheatcodes::add_authwit(on_behalf_of, message_hash); } -pub fn add_public_authwit_from_call_interface( +pub fn add_public_authwit_from_call_interface( on_behalf_of: AztecAddress, caller: AztecAddress, call_interface: C diff --git a/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr b/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr index c658539a306..b74d6637f9b 100644 --- a/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr +++ b/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr @@ -7,11 +7,11 @@ use dep::aztec::protocol_types::{ use crate::entrypoint::function_call::{FunctionCall, FUNCTION_CALL_SIZE_IN_BYTES}; // FUNCTION_CALL_SIZE * ACCOUNT_MAX_CALLS + 1 -global APP_PAYLOAD_SIZE: u64 = 21; +global APP_PAYLOAD_SIZE: u32 = 21; // FUNCTION_CALL_SIZE_IN_BYTES * ACCOUNT_MAX_CALLS + 32 -global APP_PAYLOAD_SIZE_IN_BYTES: u64 = 424; +global APP_PAYLOAD_SIZE_IN_BYTES: u32 = 424; -global ACCOUNT_MAX_CALLS: u64 = 4; +global ACCOUNT_MAX_CALLS: u32 = 4; // Note: If you change the following struct you have to update default_entrypoint.ts // docs:start:app-payload-struct diff --git a/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr b/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr index f2cf7a76eaf..6465584f56b 100644 --- a/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr +++ b/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr @@ -6,12 +6,12 @@ use dep::aztec::protocol_types::{ use crate::entrypoint::function_call::FunctionCall; // 2 * 5 (FUNCTION_CALL_SIZE) + 2 -global FEE_PAYLOAD_SIZE: Field = 12; +global FEE_PAYLOAD_SIZE: u32 = 12; // 2 * 98 (FUNCTION_CALL_SIZE_IN_BYTES) + 32 -global FEE_PAYLOAD_SIZE_IN_BYTES: Field = 228; +global FEE_PAYLOAD_SIZE_IN_BYTES: u32 = 228; -global MAX_FEE_FUNCTION_CALLS = 2; +global MAX_FEE_FUNCTION_CALLS: u32 = 2; // docs:start:fee-payload-struct struct FeePayload { diff --git a/noir-projects/aztec-nr/authwit/src/entrypoint/function_call.nr b/noir-projects/aztec-nr/authwit/src/entrypoint/function_call.nr index 5ba2bf836b5..4ff0dd2c8f2 100644 --- a/noir-projects/aztec-nr/authwit/src/entrypoint/function_call.nr +++ b/noir-projects/aztec-nr/authwit/src/entrypoint/function_call.nr @@ -1,9 +1,9 @@ use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, traits::Serialize}; // 1 (ARGS_HASH) + 1 (FUNCTION_SELECTOR) + 1 (TARGET_ADDRESS) + 1 (IS_PUBLIC) + 1 (IS_STATIC) -global FUNCTION_CALL_SIZE: Field = 5; +global FUNCTION_CALL_SIZE: u32 = 5; // 3 * 32 + 2 -global FUNCTION_CALL_SIZE_IN_BYTES: Field = 98; +global FUNCTION_CALL_SIZE_IN_BYTES: u32 = 98; struct FunctionCall { args_hash: Field, diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr index 4ba224c2761..f0cb22180b1 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr @@ -55,8 +55,8 @@ mod test { header: NoteHeader, } - global ADDRESS_NOTE_LEN: Field = 3; - global ADDRESS_NOTE_BYTES_LEN = 32 * 3 + 64; + global ADDRESS_NOTE_LEN: u32 = 3; + global ADDRESS_NOTE_BYTES_LEN: u32 = 32 * 3 + 64; impl NoteInterface for AddressNote { fn compute_note_hiding_point(_self: Self) -> Point { @@ -186,9 +186,9 @@ mod test { } } - global TEST_EVENT_LEN: Field = 3; - global TEST_EVENT_BYTES_LEN = 32 * 3 + 64; - global TEST_EVENT_BYTES_LEN_WITHOUT_RANDOMNESS = 32 * 3 + 32; + global TEST_EVENT_LEN: u32 = 3; + global TEST_EVENT_BYTES_LEN: u32 = 32 * 3 + 64; + global TEST_EVENT_BYTES_LEN_WITHOUT_RANDOMNESS: u32 = 32 * 3 + 32; impl EventInterface for TestEvent { fn get_event_type_id() -> EventSelector { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index 6dc078e986b..8cd4643df5d 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -7,11 +7,11 @@ use crate::{ }; trait ProveNoteInclusion { - fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface; + fn prove_note_inclusion(header: Header, note: Note) where Note: NoteInterface; } impl ProveNoteInclusion for Header { - fn prove_note_inclusion(self, note: Note) where Note: NoteInterface { + fn prove_note_inclusion(self, note: Note) where Note: NoteInterface { let note_hash = compute_note_hash_for_nullify(note); let witness = unsafe { diff --git a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr index 8fa98581b90..5b96acac152 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr @@ -3,11 +3,11 @@ use crate::{context::PrivateContext, note::note_interface::NoteInterface}; use dep::protocol_types::header::Header; trait ProveNoteValidity { - fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; + fn prove_note_validity(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; } impl ProveNoteValidity for Header { - fn prove_note_validity( + fn prove_note_validity( self, note: Note, context: &mut PrivateContext diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index fb67a6bf885..3e25d9d7d2d 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -32,12 +32,12 @@ impl ProveNullifierInclusion for Header { } trait ProveNoteIsNullified { - fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; + fn prove_note_is_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; } impl ProveNoteIsNullified for Header { // docs:start:prove_note_is_nullified - fn prove_note_is_nullified( + fn prove_note_is_nullified( self, note: Note, context: &mut PrivateContext diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index c70689473e5..d72e0812663 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -41,12 +41,12 @@ impl ProveNullifierNonInclusion for Header { } trait ProveNoteNotNullified { - fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; + fn prove_note_not_nullified(header: Header, note: Note, context: &mut PrivateContext) where Note: NoteInterface; } impl ProveNoteNotNullified for Header { // docs:start:prove_note_not_nullified - fn prove_note_not_nullified( + fn prove_note_not_nullified( self, note: Note, context: &mut PrivateContext diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index 5253b37ddd2..0b88f56724f 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -6,7 +6,7 @@ use crate::note::{ }; use crate::oracle::notes::{notify_created_note, notify_nullified_note}; -pub fn create_note( +pub fn create_note( context: &mut PrivateContext, storage_slot: Field, note: &mut Note @@ -36,7 +36,7 @@ pub fn create_note( NoteEmission::new(*note) } -pub fn create_note_hash_from_public( +pub fn create_note_hash_from_public( context: &mut PublicContext, storage_slot: Field, note: &mut Note @@ -52,7 +52,7 @@ pub fn create_note_hash_from_public( } // Note: This function is currently totally unused. -pub fn destroy_note( +pub fn destroy_note( context: &mut PrivateContext, note: Note ) where Note: NoteInterface { @@ -61,7 +61,7 @@ pub fn destroy_note( destroy_note_unsafe(context, note, note_hash_for_read_request) } -pub fn destroy_note_unsafe( +pub fn destroy_note_unsafe( context: &mut PrivateContext, note: Note, note_hash_for_read_request: Field diff --git a/noir-projects/aztec-nr/aztec/src/note/note_header.nr b/noir-projects/aztec-nr/aztec/src/note/note_header.nr index 2c20777fd4d..bf71981024e 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_header.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_header.nr @@ -1,6 +1,6 @@ use dep::protocol_types::{address::AztecAddress, traits::{Empty, Serialize}}; -global NOTE_HEADER_LENGTH: Field = 4; +global NOTE_HEADER_LENGTH: u32 = 4; struct NoteHeader { contract_address: AztecAddress, diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 5510253e228..6618de9374e 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -41,7 +41,7 @@ impl PrivateImmutable { impl PrivateImmutable { // docs:start:initialize - pub fn initialize( + pub fn initialize( self, note: &mut Note ) -> NoteEmission where Note: NoteInterface { @@ -54,7 +54,7 @@ impl PrivateImmutable { // docs:end:initialize // docs:start:get_note - pub fn get_note(self) -> Note where Note: NoteInterface { + pub fn get_note(self) -> Note where Note: NoteInterface { let storage_slot = self.storage_slot; get_note(self.context, storage_slot).0 } @@ -71,7 +71,7 @@ impl PrivateImmutable { // view_note does not actually use the context, but it calls oracles that are only available in private // docs:start:view_note - unconstrained pub fn view_note(self) -> Note where Note: NoteInterface { + unconstrained pub fn view_note(self) -> Note where Note: NoteInterface { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(0) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index 2a084b360a7..1c7315a49e2 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -43,7 +43,7 @@ impl PrivateMutable { } } -impl PrivateMutable where Note: NoteInterface { +impl PrivateMutable where Note: NoteInterface { // docs:start:initialize pub fn initialize(self, note: &mut Note) -> NoteEmission { // Nullify the storage slot. @@ -102,7 +102,7 @@ impl PrivateMutable where Note: NoteInter // docs:end:get_note } -impl PrivateMutable where Note: NoteInterface { +impl PrivateMutable where Note: NoteInterface { unconstrained pub fn is_initialized(self) -> bool { let nullifier = self.compute_initialization_nullifier(); check_nullifier_exists(nullifier) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr index 78d077be7ab..fa7582aed7f 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr @@ -24,7 +24,7 @@ impl PublicImmutable { // docs:end:public_immutable_struct_new } -impl PublicImmutable where T: Serialize + Deserialize { +impl PublicImmutable where T: Serialize + Deserialize { // docs:start:public_immutable_struct_write pub fn initialize(self, value: T) { // We check that the struct is not yet initialized by checking if the initialization slot is 0 @@ -46,7 +46,7 @@ impl PublicImmutable where T: Seria // docs:end:public_immutable_struct_read } -impl PublicImmutablewhere T: Deserialize { +impl PublicImmutable where T: Deserialize { unconstrained pub fn read(self) -> T { self.context.storage_read(self.storage_slot) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr index 72fce5d0b59..5cb02b44635 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr @@ -24,7 +24,7 @@ impl PublicMutable { // docs:end:public_mutable_struct_new } -impl PublicMutable where T: Serialize + Deserialize { +impl PublicMutable where T: Serialize + Deserialize { // docs:start:public_mutable_struct_read pub fn read(self) -> T { self.context.storage_read(self.storage_slot) @@ -38,7 +38,7 @@ impl PublicMutable where T: Serializ // docs:end:public_mutable_struct_write } -impl PublicMutable where T: Deserialize { +impl PublicMutable where T: Deserialize { unconstrained pub fn read(self) -> T { self.context.storage_read(self.storage_slot) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr index 97db8c5de5f..16d7a77bf5c 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr @@ -20,7 +20,7 @@ impl SharedImmutable { } } -impl SharedImmutable where T: Serialize + Deserialize { +impl SharedImmutable where T: Serialize + Deserialize { // Intended to be only called once. pub fn initialize(self, value: T) { // We check that the struct is not yet initialized by checking if the initialization slot is 0 @@ -38,13 +38,13 @@ impl SharedImmutable where T: Serial } } -impl SharedImmutable where T: Serialize + Deserialize { +impl SharedImmutable where T: Serialize + Deserialize { unconstrained pub fn read_public(self) -> T { self.context.storage_read(self.storage_slot) } } -impl SharedImmutable where T: Serialize + Deserialize { +impl SharedImmutable where T: Serialize + Deserialize { pub fn read_private(self) -> T { let header = self.context.get_header(); let mut fields = [0; T_SERIALIZED_LEN]; diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr index 9773ee59f75..a2be6062513 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr @@ -127,7 +127,7 @@ impl ScheduledDelayChange { } } -impl Serialize<1> for ScheduledDelayChange { +impl Serialize<1> for ScheduledDelayChange { fn serialize(self) -> [Field; 1] { // We pack all three u32 values into a single U128, which is made up of two u64 limbs. // Low limb: [ pre_inner: u32 | post_inner: u32 ] @@ -145,7 +145,7 @@ impl Serialize<1> for ScheduledDelayChange { } } -impl Deserialize<1> for ScheduledDelayChange { +impl Deserialize<1> for ScheduledDelayChange { fn deserialize(input: [Field; 1]) -> Self { let packed = U128::from_integer(input[0]); @@ -175,7 +175,7 @@ impl Deserialize<1> for ScheduledDelayChange { } } -impl Eq for ScheduledDelayChange { +impl Eq for ScheduledDelayChange { fn eq(self, other: Self) -> bool { (self.pre == other.pre) & (self.post == other.post) diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr index c569510e2cd..33114b0e96f 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change/test.nr @@ -1,6 +1,6 @@ use crate::state_vars::shared_mutable::scheduled_delay_change::ScheduledDelayChange; -global TEST_INITIAL_DELAY = 13; +global TEST_INITIAL_DELAY: u32 = 13; fn assert_equal_after_conversion(original: ScheduledDelayChange) { // We have to do explicit type annotations because Noir lacks turbofish support. @@ -190,7 +190,7 @@ fn test_schedule_change_to_longer_delay_from_initial() { let mut delay_change = get_initial_delay_change(); delay_change.schedule_change(new, current_block_number); - // Like in the after change scenario, change is effective immediately because the new delay is longer than the + // Like in the after change scenario, change is effective immediately because the new delay is longer than the // current one. assert_eq(delay_change.pre.unwrap(), TEST_INITIAL_DELAY); assert_eq(delay_change.post.unwrap(), new); @@ -198,7 +198,7 @@ fn test_schedule_change_to_longer_delay_from_initial() { assert_eq(delay_change.get_current(current_block_number), new); } -fn assert_effective_minimum_delay_invariants( +fn assert_effective_minimum_delay_invariants( delay_change: &mut ScheduledDelayChange, historical_block_number: u32, effective_minimum_delay: u32 @@ -222,8 +222,8 @@ fn assert_effective_minimum_delay_invariants( let value_change_block = change_schedule_block + delay_change.get_current(change_schedule_block); assert(expected_earliest_value_change_block <= value_change_block); - // Finally, a delay reduction could be scheduled immediately after the historical block. We reduce the delay to - // zero, which means that at the delay block of change there'll be no delay and a value change could be + // Finally, a delay reduction could be scheduled immediately after the historical block. We reduce the delay to + // zero, which means that at the delay block of change there'll be no delay and a value change could be // performed immediately then. delay_change.schedule_change(0, historical_block_number + 1); assert(expected_earliest_value_change_block <= delay_change.block_of_change); @@ -326,7 +326,7 @@ fn test_get_effective_delay_at_initial() { let historical_block_number = 200; - // Like in the after change scenario, no delay change is scheduled, so the effective delay is simply the current + // Like in the after change scenario, no delay change is scheduled, so the effective delay is simply the current // one (initial). let effective_minimum_delay = delay_change.get_effective_minimum_delay_at(historical_block_number); assert_eq(effective_minimum_delay, TEST_INITIAL_DELAY); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr index 84d3816b66b..443fdf10973 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable_private_getter.nr @@ -2,7 +2,7 @@ use dep::protocol_types::{traits::{FromField, ToField}, address::AztecAddress, h use crate::{context::PrivateContext, state_vars::shared_mutable::shared_mutable::SharedMutable}; -struct SharedMutablePrivateGetter { +struct SharedMutablePrivateGetter { context: &mut PrivateContext, // The contract address of the contract we want to read from other_contract_address: AztecAddress, @@ -12,7 +12,7 @@ struct SharedMutablePrivateGetter { // We have this as a view-only interface to reading Shared Mutables in other contracts. // Currently the Shared Mutable does not support this. We can adapt SharedMutable at a later date -impl SharedMutablePrivateGetter where T: FromField + ToField + Eq { +impl SharedMutablePrivateGetter where T: FromField + ToField + Eq { pub fn new( context: &mut PrivateContext, other_contract_address: AztecAddress, @@ -25,7 +25,7 @@ impl SharedMutablePrivateGetter where T: Fr pub fn get_value_in_private(self, header: Header) -> T { // We create a dummy SharedMutable state variable so that we can reuse its historical_read_from_public_storage - // method, greatly reducing code duplication. + // method, greatly reducing code duplication. let dummy: SharedMutable = SharedMutable::new((), self.storage_slot); let (value_change, delay_change, historical_block_number) = dummy.historical_read_from_public_storage(header, self.other_contract_address); diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index 070837c69e1..d96e960be24 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -101,11 +101,11 @@ impl TestEnvironment { address } - fn deploy(self, path: str, name: str) -> Deployer { + fn deploy(self, path: str, name: str) -> Deployer { Deployer { path, name, public_keys_hash: 0 } } - fn deploy_self(self, name: str) -> Deployer<0, M> { + fn deploy_self(self, name: str) -> Deployer<0, M> { Deployer { path: "", name, public_keys_hash: 0 } } diff --git a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr index 12e2e741260..faa780954ac 100644 --- a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr +++ b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr @@ -6,9 +6,9 @@ use crate::{ use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, point::Point}; use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; -global MOCK_NOTE_LENGTH = 1; +global MOCK_NOTE_LENGTH: u32 = 1; // MOCK_NOTE_LENGTH * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global MOCK_NOTE_BYTES_LENGTH: Field = 1 * 32 + 64; +global MOCK_NOTE_BYTES_LENGTH: u32 = 1 * 32 + 64; struct MockNote { header: NoteHeader, diff --git a/noir-projects/aztec-nr/uint-note/src/uint_note.nr b/noir-projects/aztec-nr/uint-note/src/uint_note.nr index e744da7813f..41774e7536e 100644 --- a/noir-projects/aztec-nr/uint-note/src/uint_note.nr +++ b/noir-projects/aztec-nr/uint-note/src/uint_note.nr @@ -9,8 +9,8 @@ use dep::aztec::{ }; use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; -global UINT_NOTE_LEN: Field = 3; // 3 plus a header. -global UINT_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global UINT_NOTE_LEN: u32 = 3; // 3 plus a header. +global UINT_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; #[aztec(note)] struct UintNote { diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 356aaa4444e..1b4c1fff073 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -10,9 +10,9 @@ use dep::aztec::{ use dep::std::{embedded_curve_ops::multi_scalar_mul}; use std::hash::from_field_unsafe; -global VALUE_NOTE_LEN: Field = 3; // 3 plus a header. +global VALUE_NOTE_LEN: u32 = 3; // 3 plus a header. // VALUE_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global VALUE_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global VALUE_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; // docs:start:value-note-def #[aztec(note)] diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr index 592f2cbe441..6b938ea6bc5 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr @@ -6,11 +6,11 @@ use dep::aztec::protocol_types::{ use dep::authwit::entrypoint::function_call::FunctionCall; -global DAPP_MAX_CALLS: u64 = 1; +global DAPP_MAX_CALLS: u32 = 1; // FUNCTION_CALL_SIZE * DAPP_MAX_CALLS + 1 -global DAPP_PAYLOAD_SIZE: u64 = 6; +global DAPP_PAYLOAD_SIZE: u32 = 6; // FUNCTION_CALL_SIZE_IN_BYTES * DAPP_MAX_CALLS + 32 -global DAPP_PAYLOAD_SIZE_IN_BYTES: u64 = 130; +global DAPP_PAYLOAD_SIZE_IN_BYTES: u32 = 130; // Note: If you change the following struct you have to update default_entrypoint.ts // docs:start:app-payload-struct diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index 36ca60c7515..5edfe215f69 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -5,9 +5,9 @@ use dep::aztec::{ protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER }; -global SUBSCRIPTION_NOTE_LEN: Field = 4; +global SUBSCRIPTION_NOTE_LEN: u32 = 4; // SUBSCRIPTION_NOTE_BYTES_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global SUBSCRIPTION_NOTE_BYTES_LEN: Field = SUBSCRIPTION_NOTE_LEN * 32 + 64; +global SUBSCRIPTION_NOTE_BYTES_LEN: u32 = SUBSCRIPTION_NOTE_LEN * 32 + 64; #[aztec(note)] struct SubscriptionNote { diff --git a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr index a971c8b109b..11549fae5d5 100644 --- a/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_contract/src/main.nr @@ -7,7 +7,7 @@ contract Auth { use dep::aztec::state_vars::{PublicImmutable, SharedMutable}; // Authorizing a new address has a certain block delay before it goes into effect. - global CHANGE_AUTHORIZED_DELAY_BLOCKS = 5; + global CHANGE_AUTHORIZED_DELAY_BLOCKS: u32 = 5; #[aztec(storage)] struct Storage { diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index 543e33357d0..fefa9f4c8d7 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -68,7 +68,7 @@ struct Deck { set: PrivateSet, } -pub fn filter_cards( +pub fn filter_cards( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], desired_cards: [Card; N] ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { @@ -102,7 +102,7 @@ impl Deck { } impl Deck<&mut PrivateContext> { - pub fn add_cards(&mut self, cards: [Card; N], owner: AztecAddress) -> [CardNote] { + pub fn add_cards(&mut self, cards: [Card; N], owner: AztecAddress) -> [CardNote] { let owner_keys = get_current_public_keys(self.set.context, owner); let owner_ivpk_m = owner_keys.ivpk_m; let owner_npk_m_hash = owner_keys.npk_m.hash(); @@ -120,7 +120,7 @@ impl Deck<&mut PrivateContext> { inserted_cards } - pub fn remove_cards(&mut self, cards: [Card; N]) { + pub fn remove_cards(&mut self, cards: [Card; N]) { let options = NoteGetterOptions::with_filter(filter_cards, cards); let notes = self.set.pop_notes(options); assert(notes.len() == N, "Not all cards were removed"); @@ -173,7 +173,7 @@ pub fn get_pack_cards( cards } -pub fn compute_deck_strength(cards: [Card; N]) -> Field { +pub fn compute_deck_strength(cards: [Card; N]) -> Field { cards.fold( 0, |acc, card: Card| { diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr index 057c40640cc..82c3a1cfa61 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr @@ -1,7 +1,7 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Serialize, Deserialize}}; use crate::cards::Card; -global NUMBER_OF_PLAYERS: u64 = 2; +global NUMBER_OF_PLAYERS: u32 = 2; global NUMBER_OF_CARDS_DECK: u64 = 2; struct PlayerEntry { @@ -16,7 +16,7 @@ impl PlayerEntry { } } -global PLAYER_SERIALIZED_LEN: Field = 3; +global PLAYER_SERIALIZED_LEN: u32 = 3; impl Deserialize for PlayerEntry { fn deserialize(fields: [Field; PLAYER_SERIALIZED_LEN]) -> PlayerEntry { @@ -36,7 +36,7 @@ impl Eq for PlayerEntry { } } -global PLAYABLE_CARDS = 4; +global PLAYABLE_CARDS: u32 = 4; struct Game { players: [PlayerEntry; NUMBER_OF_PLAYERS], @@ -48,7 +48,7 @@ struct Game { current_round: u64, } -global GAME_SERIALIZED_LEN: Field = 15; +global GAME_SERIALIZED_LEN: u32 = 15; impl Serialize for Game { fn serialize(game: Game) -> [Field; GAME_SERIALIZED_LEN] { @@ -144,10 +144,10 @@ impl Game { assert(self.started, "Game not started"); assert(!self.finished, "Game finished"); - let round_offset = self.current_round * NUMBER_OF_PLAYERS; + let round_offset = self.current_round * (NUMBER_OF_PLAYERS as u64); self.rounds_cards[round_offset + self.current_player] = card; - self.current_player = (self.current_player + 1) % NUMBER_OF_PLAYERS; + self.current_player = (self.current_player + 1) % (NUMBER_OF_PLAYERS as u64); if self.current_player == 0 { self._finish_round(); @@ -155,7 +155,7 @@ impl Game { } fn _finish_round(&mut self) { - let round_offset = self.current_round * NUMBER_OF_PLAYERS; + let round_offset = self.current_round as u32 * NUMBER_OF_PLAYERS; self.current_round += 1; let mut winner_index = 0; diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr index 99c90896b4a..32d739f3946 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/capsule.nr @@ -2,10 +2,10 @@ // docs:start:pop_capsule #[oracle(popCapsule)] -unconstrained fn pop_capsule_oracle() -> [Field; N] {} +unconstrained fn pop_capsule_oracle() -> [Field; N] {} // A capsule is a "blob" of data that is passed to the contract through an oracle. -unconstrained pub fn pop_capsule() -> [Field; N] { +unconstrained pub fn pop_capsule() -> [Field; N] { pop_capsule_oracle() } // docs:end:pop_capsule \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 8158fc27015..20334ecedba 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -144,12 +144,12 @@ contract ContractClassRegisterer { // - Unconstrained function -> we provide a membership proof // Ordinary logs are not protected by the above so this fn shouldn't be called by anything else #[contract_library_method] - pub fn emit_contract_class_unencrypted_log(context: &mut PrivateContext, log: [Field; N]) { + pub fn emit_contract_class_unencrypted_log(context: &mut PrivateContext, log: [Field; N]) { let contract_address = context.this_address(); let counter = context.next_counter(); let log_hash = emit_contract_class_unencrypted_log_private_internal(contract_address, log, counter); // 40 = addr (32) + raw log len (4) + processed log len (4) - let len = 40 + N * 32; + let len = 40 + N as Field * 32; let side_effect = LogHash { value: log_hash, counter, length: len }; context.unencrypted_logs_hashes.push(side_effect); } diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 5de9b5dea6d..d177384f869 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -4,9 +4,9 @@ use dep::aztec::{ protocol_types::{traits::Serialize, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; -global CARD_NOTE_LEN: Field = 3; +global CARD_NOTE_LEN: u32 = 3; // CARD_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global CARD_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global CARD_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; // docs:start:state_vars-CardNote #[aztec(note)] diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr index 85f1b08199d..9678f2d5668 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr @@ -6,7 +6,7 @@ struct Leader { points: u8, } -global LEADER_SERIALIZED_LEN: Field = 2; +global LEADER_SERIALIZED_LEN: u32 = 2; impl Deserialize for Leader { fn deserialize(fields: [Field; LEADER_SERIALIZED_LEN]) -> Self { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr index 25d0407c6bb..bc082704050 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr @@ -19,11 +19,11 @@ impl BalanceSet { } impl BalanceSet { - unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + OwnedNote { self.balance_of_with_offset(0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, offset: u32 ) -> U128 where T: NoteInterface + OwnedNote { @@ -46,7 +46,7 @@ impl BalanceSet { } impl BalanceSet { - pub fn add( + pub fn add( self: Self, owner_npk_m: NpkM, addend: U128 @@ -63,7 +63,7 @@ impl BalanceSet { } } - pub fn sub( + pub fn sub( self: Self, owner_npk_m: NpkM, amount: U128 @@ -85,7 +85,7 @@ impl BalanceSet { // The `max_notes` parameter is used to fine-tune the number of constraints created by this function. The gate count // scales relatively linearly with `max_notes`, but a lower `max_notes` parameter increases the likelihood of // `try_sub` subtracting an amount smaller than `target_amount`. - pub fn try_sub( + pub fn try_sub( self: Self, target_amount: U128, max_notes: u32 @@ -115,7 +115,7 @@ impl BalanceSet { // The preprocessor (a filter applied in an unconstrained context) does not check if total sum is larger or equal to // 'min_sum' - all it does is remove extra notes if it does reach that value. // Note that proper usage of this preprocessor requires for notes to be sorted in descending order. -pub fn preprocess_notes_min_sum( +pub fn preprocess_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index d9e5c9c7ee4..5909159a5f8 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -15,8 +15,8 @@ trait OwnedNote { fn get_amount(self) -> U128; } -global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. -global TOKEN_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global TOKEN_NOTE_LEN: u32 = 3; // 3 plus a header. +global TOKEN_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; // docs:start:TokenNote #[aztec(note)] diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index 867aa4d3467..8c2b0c0e138 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -5,9 +5,9 @@ use dep::aztec::{ protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; -global TRANSPARENT_NOTE_LEN: Field = 2; +global TRANSPARENT_NOTE_LEN: u32 = 2; // TRANSPARENT_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global TRANSPARENT_NOTE_BYTES_LEN: Field = 2 * 32 + 64; +global TRANSPARENT_NOTE_BYTES_LEN: u32 = 2 * 32 + 64; // Transparent note represents a note that is created in the clear (public execution), but can only be spent by those // that know the preimage of the "secret_hash" (the secret). This is typically used when shielding a token balance. @@ -46,7 +46,7 @@ impl NoteInterface for Transpa // 1) We pass the secret as an argument to the function and use it to compute a secret hash, // 2) we fetch a note via the "get_notes" oracle which accepts the secret hash as an argument, // 3) the "get_notes" oracle constrains that the secret hash in the returned note matches the one computed in - // circuit. + // circuit. // This achieves that the note can only be spent by the party that knows the secret. fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_nullify(self); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr index b03f665d227..0a1bbf3444d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr @@ -1,7 +1,7 @@ use crate::utils::field::field_from_bytes; use crate::traits::{Serialize, Deserialize, FromField, ToField, Empty}; -global SELECTOR_SIZE = 4; +global SELECTOR_SIZE: u32 = 4; struct EventSelector { // 1st 4-bytes (big-endian leftmost) of abi-encoding of an event. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr index 26ae4aeac2c..eda80e000a0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr @@ -1,7 +1,7 @@ use crate::utils::field::field_from_bytes; use crate::traits::{Serialize, Deserialize, FromField, ToField, Empty}; -global SELECTOR_SIZE = 4; +global SELECTOR_SIZE: u32 = 4; struct FunctionSelector { // 1st 4-bytes of abi-encoding of function. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr index 652f8bf3732..db29fe89171 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr @@ -1,4 +1,4 @@ -global NOTE_HASH_LEAF_PREIMAGE_LENGTH: u64 = 1; +global NOTE_HASH_LEAF_PREIMAGE_LENGTH: u32 = 1; use crate::{ abis::{read_request::ScopedReadRequest, side_effect::Readable}, hash::compute_siloed_note_hash, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr index 0e118db7070..0f073a4dcba 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr @@ -4,7 +4,7 @@ use crate::{ hash::poseidon2_hash_with_separator, traits::{ToField, Serialize, Deserialize} }; -global PARTIAL_ADDRESS_LENGTH = 1; +global PARTIAL_ADDRESS_LENGTH: u32 = 1; // Partial address struct PartialAddress { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index d84713c9e86..91ad24162fb 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -196,7 +196,7 @@ global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x1abe6c7f5c4caf04cbf7556495 global ROUTER_ADDRESS = AztecAddress::from_field(0x1d8f25db3e8faa6a96cb1ecf57876a2ee04581deb3c4f181488ccd817abcbdb0); // LENGTH OF STRUCTS SERIALIZED TO FIELDS -global AZTEC_ADDRESS_LENGTH = 1; +global AZTEC_ADDRESS_LENGTH: u32 = 1; global GAS_FEES_LENGTH: u32 = 2; global GAS_LENGTH: u32 = 2; global GAS_SETTINGS_LENGTH: u32 = GAS_LENGTH * 2 + GAS_FEES_LENGTH + /* inclusion_fee */ 1; @@ -205,38 +205,38 @@ global CONTENT_COMMITMENT_LENGTH: u32 = 4; global CONTRACT_INSTANCE_LENGTH: u32 = 5; global CONTRACT_STORAGE_READ_LENGTH: u32 = 3; global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: u32 = 3; -global ETH_ADDRESS_LENGTH = 1; +global ETH_ADDRESS_LENGTH: u32 = 1; global FUNCTION_DATA_LENGTH: u32 = 2; global FUNCTION_LEAF_PREIMAGE_LENGTH: u32 = 5; global GLOBAL_VARIABLES_LENGTH: u32 = 7 + GAS_FEES_LENGTH; -global APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; +global APPEND_ONLY_TREE_SNAPSHOT_LENGTH: u32 = 2; global L1_TO_L2_MESSAGE_LENGTH: u32 = 6; global L2_TO_L1_MESSAGE_LENGTH: u32 = 3; -global SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; +global SCOPED_L2_TO_L1_MESSAGE_LENGTH: u32 = L2_TO_L1_MESSAGE_LENGTH + 1; global MAX_BLOCK_NUMBER_LENGTH: u32 = 2; // 1 for the option flag, 1 for the value -global KEY_VALIDATION_REQUEST_LENGTH = 4; -global KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH = KEY_VALIDATION_REQUEST_LENGTH + 1; -global SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH = KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH + 1; +global KEY_VALIDATION_REQUEST_LENGTH: u32 = 4; +global KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH: u32 = KEY_VALIDATION_REQUEST_LENGTH + 1; +global SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH: u32 = KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH + 1; global PARTIAL_STATE_REFERENCE_LENGTH: u32 = 6; -global READ_REQUEST_LENGTH = 2; -global TREE_LEAF_READ_REQUEST_LENGTH = 2; -global LOG_HASH_LENGTH = 3; -global SCOPED_LOG_HASH_LENGTH = LOG_HASH_LENGTH + 1; -global ENCRYPTED_LOG_HASH_LENGTH = 4; -global SCOPED_ENCRYPTED_LOG_HASH_LENGTH = ENCRYPTED_LOG_HASH_LENGTH + 1; -global NOTE_LOG_HASH_LENGTH = 4; -global NOTE_HASH_LENGTH = 2; -global SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 1; -global NULLIFIER_LENGTH = 3; -global SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; -global PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH = AZTEC_ADDRESS_LENGTH + CALL_CONTEXT_LENGTH + 3 + 2 * GAS_LENGTH; -global PRIVATE_CALL_REQUEST_LENGTH = AZTEC_ADDRESS_LENGTH + CALL_CONTEXT_LENGTH + 4; -global PUBLIC_CALL_REQUEST_LENGTH = PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH + 1 /* counter */; -global ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; +global READ_REQUEST_LENGTH: u32 = 2; +global TREE_LEAF_READ_REQUEST_LENGTH: u32 = 2; +global LOG_HASH_LENGTH: u32 = 3; +global SCOPED_LOG_HASH_LENGTH: u32 = LOG_HASH_LENGTH + 1; +global ENCRYPTED_LOG_HASH_LENGTH: u32 = 4; +global SCOPED_ENCRYPTED_LOG_HASH_LENGTH: u32 = ENCRYPTED_LOG_HASH_LENGTH + 1; +global NOTE_LOG_HASH_LENGTH: u32 = 4; +global NOTE_HASH_LENGTH: u32 = 2; +global SCOPED_NOTE_HASH_LENGTH: u32 = NOTE_HASH_LENGTH + 1; +global NULLIFIER_LENGTH: u32 = 3; +global SCOPED_NULLIFIER_LENGTH: u32 = NULLIFIER_LENGTH + 1; +global PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH: u32 = AZTEC_ADDRESS_LENGTH + CALL_CONTEXT_LENGTH + 3 + 2 * GAS_LENGTH; +global PRIVATE_CALL_REQUEST_LENGTH: u32 = AZTEC_ADDRESS_LENGTH + CALL_CONTEXT_LENGTH + 4; +global PUBLIC_CALL_REQUEST_LENGTH: u32 = PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH + 1 /* counter */; +global ROLLUP_VALIDATION_REQUESTS_LENGTH: u32 = MAX_BLOCK_NUMBER_LENGTH; global STATE_REFERENCE_LENGTH: u32 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; global TX_CONTEXT_LENGTH: u32 = 2 + GAS_SETTINGS_LENGTH; global TX_REQUEST_LENGTH: u32 = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; -global TOTAL_FEES_LENGTH = 1; +global TOTAL_FEES_LENGTH: u32 = 1; global HEADER_LENGTH: u32 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH + TOTAL_FEES_LENGTH; global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_CALL) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + (PUBLIC_CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL) + PUBLIC_CALL_REQUEST_LENGTH + (L2_TO_L1_MESSAGE_LENGTH * MAX_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (ENCRYPTED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = CALL_CONTEXT_LENGTH + /*argsHash + returnsHash*/ 2 + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + (PUBLIC_CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; @@ -245,29 +245,29 @@ global PUBLIC_CONTEXT_INPUTS_LENGTH: u32 = CALL_CONTEXT_LENGTH + HEADER_LENGTH + global AGGREGATION_OBJECT_LENGTH: u32 = 16; -global SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; -global PUBLIC_DATA_READ_LENGTH = 3; -global PRIVATE_VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_TX) + 2; -global PUBLIC_VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX) + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX); +global SCOPED_READ_REQUEST_LEN: u32 = READ_REQUEST_LENGTH + 1; +global PUBLIC_DATA_READ_LENGTH: u32 = 3; +global PRIVATE_VALIDATION_REQUESTS_LENGTH: u32 = ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_TX) + 2; +global PUBLIC_VALIDATION_REQUESTS_LENGTH: u32 = ROLLUP_VALIDATION_REQUESTS_LENGTH + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX) + (TREE_LEAF_READ_REQUEST_LENGTH * MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX); -global PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 3; -global COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NOTE_HASHES_PER_TX + MAX_NULLIFIERS_PER_TX + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + 3 + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; -global COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH + 1; +global PUBLIC_DATA_UPDATE_REQUEST_LENGTH: u32 = 3; +global COMBINED_ACCUMULATED_DATA_LENGTH: u32 = MAX_NOTE_HASHES_PER_TX + MAX_NULLIFIERS_PER_TX + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + 3 + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; +global COMBINED_CONSTANT_DATA_LENGTH: u32 = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH + 1; -global PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_TX) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (SCOPED_ENCRYPTED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (PUBLIC_CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); -global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + PRIVATE_VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PUBLIC_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; +global PRIVATE_ACCUMULATED_DATA_LENGTH: u32 = (SCOPED_NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_TX) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (SCOPED_ENCRYPTED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (PUBLIC_CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); +global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = 1 + PRIVATE_VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PUBLIC_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; -global PUBLIC_ACCUMULATED_DATA_LENGTH = (MAX_NOTE_HASHES_PER_TX * SCOPED_NOTE_HASH_LENGTH) + (MAX_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (MAX_NOTE_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_ENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) + GAS_LENGTH; -global PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = PUBLIC_VALIDATION_REQUESTS_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + 1 + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) + AZTEC_ADDRESS_LENGTH; +global PUBLIC_ACCUMULATED_DATA_LENGTH: u32 = (MAX_NOTE_HASHES_PER_TX * SCOPED_NOTE_HASH_LENGTH) + (MAX_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (MAX_NOTE_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_ENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) + GAS_LENGTH; +global PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = PUBLIC_VALIDATION_REQUESTS_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + 1 + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) + AZTEC_ADDRESS_LENGTH; -global KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + COMBINED_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 1 + AZTEC_ADDRESS_LENGTH; +global KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = ROLLUP_VALIDATION_REQUESTS_LENGTH + COMBINED_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 1 + AZTEC_ADDRESS_LENGTH; -global CONSTANT_ROLLUP_DATA_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 1 + GLOBAL_VARIABLES_LENGTH; +global CONSTANT_ROLLUP_DATA_LENGTH: u32 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 1 + GLOBAL_VARIABLES_LENGTH; // + 5 for rollup_type, height_in_block_tree, txs_effects_hash, out_hash, accumulated_fees -global BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; +global BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH: u32 = CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; // + 64 for 32 * FeeRecipient { recipient, value }, + 4 for previous_block_hash, end_block_hash, out_hash, vk_tree_root + 1 temporarily for prover_id -global BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 2 * APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 2 * GLOBAL_VARIABLES_LENGTH + 69; +global BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH: u32 = 2 * APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 2 * GLOBAL_VARIABLES_LENGTH + 69; global GET_NOTES_ORACLE_RETURN_LENGTH: u32 = 674; global NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: u32 = 32 * MAX_NOTE_HASHES_PER_TX; @@ -284,8 +284,8 @@ global NUM_MSGS_PER_BASE_PARITY: u32 = 4; global NUM_BASE_PARITY_PER_ROOT_PARITY: u32 = 4; // Lengths of the different types of proofs in fields -global RECURSIVE_PROOF_LENGTH = 439; -global NESTED_RECURSIVE_PROOF_LENGTH = 439; +global RECURSIVE_PROOF_LENGTH: u32 = 439; +global NESTED_RECURSIVE_PROOF_LENGTH: u32 = 439; global TUBE_PROOF_LENGTH = RECURSIVE_PROOF_LENGTH; // in the future these can differ global VERIFICATION_KEY_LENGTH_IN_FIELDS = 128; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr index 72e77f13ffa..48ea00b3a90 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr @@ -117,6 +117,8 @@ mod tests { TestLeafPreimage { value: 30, next_value: 40 }, ]; + + fn build_tree() -> NonEmptyMerkleTree<4, 3, 1, 2> { NonEmptyMerkleTree::new( leaf_preimages.map(|leaf_preimage: TestLeafPreimage| leaf_preimage.as_leaf()), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/point.nr b/noir-projects/noir-protocol-circuits/crates/types/src/point.nr index f3737136951..5de69793449 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/point.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/point.nr @@ -1,7 +1,7 @@ pub use dep::std::embedded_curve_ops::EmbeddedCurvePoint as Point; use crate::{traits::{Deserialize, Empty, Hash, Serialize}, hash::poseidon2_hash}; -global POINT_LENGTH: Field = 3; +global POINT_LENGTH: u32 = 3; impl Serialize for Point { fn serialize(self: Self) -> [Field; POINT_LENGTH] { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/recursion/verification_key.nr b/noir-projects/noir-protocol-circuits/crates/types/src/recursion/verification_key.nr index 4c5be1ef939..2ebd2de3cde 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/recursion/verification_key.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/recursion/verification_key.nr @@ -1,6 +1,6 @@ use crate::{traits::{Serialize, Deserialize, Empty}, constants::VERIFICATION_KEY_LENGTH_IN_FIELDS}; -global SERIALIZED_VERIFICATION_KEY_LENGTH = VERIFICATION_KEY_LENGTH_IN_FIELDS + 1; +global SERIALIZED_VERIFICATION_KEY_LENGTH: u32 = VERIFICATION_KEY_LENGTH_IN_FIELDS + 1; struct VerificationKey { key: [Field; VERIFICATION_KEY_LENGTH_IN_FIELDS], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/scalar.nr b/noir-projects/noir-protocol-circuits/crates/types/src/scalar.nr index ac674bf24c9..51379c120de 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/scalar.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/scalar.nr @@ -1,7 +1,7 @@ pub use dep::std::embedded_curve_ops::EmbeddedCurveScalar as Scalar; use crate::traits::{Empty, Serialize}; -global SCALAR_SIZE: Field = 2; +global SCALAR_SIZE: u32 = 2; impl Empty for Scalar { fn empty() -> Self { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/vk_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/vk_tree.nr index cf875776cc8..9cb521d9dbe 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/vk_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/vk_tree.nr @@ -10,7 +10,7 @@ use crate::constants::{ }; use crate::merkle_tree::merkle_tree::MerkleTree; -global VK_TREE_WIDTH = 32; +global VK_TREE_WIDTH: u32 = 32; #[test] fn check_vk_tree_width() { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr index 4cc3700875a..424b32c3d6f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr @@ -65,14 +65,14 @@ fn test_merkle_tree_update_leaf_three_layers() { assert_eq(tree.get_root(), calculate_empty_tree_root(3)); } -struct NonEmptyMerkleTree { +struct NonEmptyMerkleTree { subtree: MerkleTree, zero_hashes: [Field; TREE_HEIGHT], left_supertree_branch: [Field; SUPERTREE_HEIGHT], _phantom_subtree_height: [Field; SUBTREE_HEIGHT], } -impl Empty for NonEmptyMerkleTree { +impl Empty for NonEmptyMerkleTree { fn empty() -> Self { NonEmptyMerkleTree { subtree: MerkleTree::empty(), @@ -83,7 +83,7 @@ impl NonEmptyMerkleTree { +impl NonEmptyMerkleTree { pub fn new( non_zero_leaves: [Field; SUBTREE_ITEMS], _tree_height: [Field; TREE_HEIGHT], @@ -94,7 +94,7 @@ impl for bool { fn serialize(self) -> [Field; BOOL_SERIALIZED_LEN] { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr index be6f88970f5..28c3b0062ff 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr @@ -69,7 +69,7 @@ mod tests { utils::arrays::assert_split_transformed_value_arrays::{assert_split_transformed_value_arrays, assert_split_transformed_value_arrays_with_hint} }; - global NUM_TEST_ITEMS = 5; + global NUM_TEST_ITEMS: u32 = 5; fn is_transformed(from: TestValue, to: Field) -> bool { from.value == to From fcb39b3d613f358dc3f3053a6bbe9c7f58256e52 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 18 Sep 2024 13:43:16 +0000 Subject: [PATCH 32/79] chore: add safety check for converting u32 to u8 --- .../crates/types/src/tests/merkle_tree_utils.nr | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr index 424b32c3d6f..0d759258d51 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr @@ -90,6 +90,10 @@ impl Self { + // Hack to get around us converting a u32 to a u8. + // TODO: improve this. + (SUBTREE_HEIGHT as Field).assert_max_bit_size(8); + assert_eq( TREE_HEIGHT, SUPERTREE_HEIGHT + SUBTREE_HEIGHT, "tree height must be the sum of supertree and subtree height" ); From ae87091dd6a03d47993302dd75c5b0a80c7180c8 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 13:43:25 +0000 Subject: [PATCH 33/79] remove .quoted_contents() as much as possible --- .../aztec/src/macros/functions/interfaces.nr | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr index a3b37a2dd97..965e5f2456c 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr @@ -49,13 +49,13 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let fn_parameters = f.parameters(); // Fixes [ typ ; ( len : numeric Field ) ] error let fn_return_type = f.return_type(); - let fn_return_type_quoted = if fn_return_type.as_array().is_some() { - let (element_type, array_len) = fn_return_type.as_array().unwrap(); - let array_len = array_len.as_constant().unwrap(); - quote { [$element_type; $array_len] } - } else { - quote { $fn_return_type } - }; + // let fn_return_type_quoted = if fn_return_type.as_array().is_some() { + // let (element_type, array_len) = fn_return_type.as_array().unwrap(); + // let array_len = array_len.as_constant().unwrap(); + // quote { [$element_type; $array_len] } + // } else { + // quote { $fn_return_type } + // }; let fn_visibility = get_fn_visibility(f); let is_static_call = is_fn_view(f); let is_void = fn_return_type == type_of(()); @@ -110,21 +110,21 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let fn_name_len: u32 = unquote!(quote { $fn_name_str.as_bytes().len()}); - let arg_types_list = fn_parameters.map(|(_, typ): (_, Type)| quote { $typ }).join(quote {,}); + let arg_types_list: Quoted = fn_parameters.map(|(_, typ): (_, Type)| quote { $typ }).join(quote {,}); let arg_types = if fn_parameters.len() == 1 { - f"({arg_types_list},)".quoted_contents() + // Extra colon to avoid it being interpreted as a parenthesized expression instead of a tuple + quote { ($arg_types_list,) } } else { - f"({arg_types_list})".quoted_contents() + quote { ($arg_types_list) } }; - let generics = if is_void { - f"{arg_types}>".quoted_contents() + let call_interface_generics = if is_void { + quote { $fn_name_len, $arg_types } } else { - f"{fn_return_type_quoted}, {arg_types}>".quoted_contents() + quote { $fn_name_len, $fn_return_type, $arg_types } }; let call_interface_name = f"dep::aztec::context::call_interfaces::{fn_visibility_capitalized}{is_static_call_capitalized}{is_void_capitalized}CallInterface".quoted_contents(); - let call_interface_name_w_generics = f"{call_interface_name}<{fn_name_len}, {generics}".quoted_contents(); let fn_selector: Field = compute_fn_selector(f); @@ -144,14 +144,14 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let parameter_names = if fn_parameters.len() > 0 { let params = fn_parameters.map(|(name, _): (Quoted, _)| name).join(quote {,}); - f",{params}".quoted_contents() + quote { inputs, $params } } else { - quote {} + quote {inputs} }; let original = quote { | inputs: $input_type | -> $return_type_hint { - $fn_name(inputs $parameter_names) + $fn_name($parameter_names) } }; @@ -162,7 +162,7 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { }; quote { - pub fn $fn_name(self, $fn_parameters_list) -> $call_interface_name_w_generics { + pub fn $fn_name(self, $fn_parameters_list) -> $call_interface_name<$call_interface_generics> { $args let selector = dep::aztec::protocol_types::abis::function_selector::FunctionSelector::from_field($fn_selector); $call_interface_name { From 75dbb7e816ac3ed7050686f5b2726870701410b9 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 18 Sep 2024 13:52:02 +0000 Subject: [PATCH 34/79] . --- .../contracts/ecdsa_public_key_note/src/lib.nr | 4 ++-- .../contracts/lending_contract/src/asset.nr | 2 +- .../contracts/lending_contract/src/position.nr | 2 +- .../contracts/nft_contract/src/types/nft_note.nr | 4 ++-- .../contracts/price_feed_contract/src/asset.nr | 2 +- .../contracts/private_fpc_contract/src/settings.nr | 2 +- .../schnorr_account_contract/src/public_key_note.nr | 4 ++-- .../contracts/spam_contract/src/types/balance_set.nr | 12 ++++++------ .../contracts/spam_contract/src/types/token_note.nr | 4 ++-- .../contracts/test_contract/src/test_note.nr | 6 +++--- .../contracts/token_blacklist_contract/src/main.nr | 2 +- .../src/types/balances_map.nr | 10 +++++----- .../token_blacklist_contract/src/types/token_note.nr | 4 ++-- .../src/types/transparent_note.nr | 6 +++--- .../regression_4436/src/main.nr | 4 ++-- 15 files changed, 34 insertions(+), 34 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index 511e046c7ce..1847b6cd5b4 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -5,9 +5,9 @@ use dep::aztec::{ protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; -global ECDSA_PUBLIC_KEY_NOTE_LEN: Field = 5; +global ECDSA_PUBLIC_KEY_NOTE_LEN: u32 = 5; // ECDSA_PUBLIC_KEY_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global ECDSA_PUBLIC_KEY_NOTE_BYTES_LEN: Field = 5 * 32 + 64; +global ECDSA_PUBLIC_KEY_NOTE_BYTES_LEN: u32 = 5 * 32 + 64; // Stores an ECDSA public key composed of two 32-byte elements // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr index 7440df2640f..fe0f0153048 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr @@ -13,7 +13,7 @@ struct Asset { oracle: AztecAddress, } -global SERIALIZED_LEN: Field = 6; +global SERIALIZED_LEN: u32 = 6; impl Serialize for Asset { fn serialize(Asset: Asset) -> [Field; SERIALIZED_LEN] { diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/position.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/position.nr index 7a2b9a0cb1e..2e575428e1c 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/position.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/position.nr @@ -6,7 +6,7 @@ struct Position { debt: Field, } -global POSITION_SERIALIZED_LEN: Field = 3; +global POSITION_SERIALIZED_LEN: u32 = 3; impl Serialize for Position { fn serialize(position: Position) -> [Field; POSITION_SERIALIZED_LEN] { diff --git a/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr b/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr index cce6812150b..5a50ab3877a 100644 --- a/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr +++ b/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr @@ -10,9 +10,9 @@ use dep::aztec::{ }; use std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; -global NFT_NOTE_LEN: Field = 3; +global NFT_NOTE_LEN: u32 = 3; // NFT_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global NFT_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global NFT_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; #[aztec(note)] struct NFTNote { diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr index 147c33c0e6c..86ecc9a90fc 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr @@ -4,7 +4,7 @@ struct Asset { price: U128, } -global ASSET_SERIALIZED_LEN: Field = 2; +global ASSET_SERIALIZED_LEN: u32 = 2; impl Serialize for Asset { fn serialize(asset: Asset) -> [Field; ASSET_SERIALIZED_LEN] { diff --git a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/settings.nr b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/settings.nr index 3c51a1861a0..934b44dd476 100644 --- a/noir-projects/noir-contracts/contracts/private_fpc_contract/src/settings.nr +++ b/noir-projects/noir-contracts/contracts/private_fpc_contract/src/settings.nr @@ -1,6 +1,6 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Serialize, Deserialize}}; -global SETTINGS_LENGTH = 2; +global SETTINGS_LENGTH: u32 = 2; struct Settings { other_asset: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 948367a413a..55fe9390143 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -4,9 +4,9 @@ use dep::aztec::{ protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; -global PUBLIC_KEY_NOTE_LEN: Field = 3; +global PUBLIC_KEY_NOTE_LEN: u32 = 3; // PUBLIC_KEY_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global PUBLIC_KEY_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global PUBLIC_KEY_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; // Stores a public key composed of two fields // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr index a513efc713c..516ca5341e7 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr @@ -19,11 +19,11 @@ impl BalanceSet { } impl BalanceSet { - unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of(self: Self) -> U128 where T: NoteInterface + OwnedNote { self.balance_of_with_offset(0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, offset: u32 ) -> U128 where T: NoteInterface + OwnedNote { @@ -46,7 +46,7 @@ impl BalanceSet { } impl BalanceSet { - pub fn add( + pub fn add( self: Self, owner_npk_m: NpkM, addend: U128 @@ -63,7 +63,7 @@ impl BalanceSet { } } - pub fn sub( + pub fn sub( self: Self, owner_npk_m: NpkM, amount: U128 @@ -85,7 +85,7 @@ impl BalanceSet { // The `max_notes` parameter is used to fine-tune the number of constraints created by this function. The gate count // scales relatively linearly with `max_notes`, but a lower `max_notes` parameter increases the likelihood of // `try_sub` subtracting an amount smaller than `target_amount`. - pub fn try_sub( + pub fn try_sub( self: Self, target_amount: U128, max_notes: u32 @@ -115,7 +115,7 @@ impl BalanceSet { // The preprocessor (a filter applied in an unconstrained context) does not check if total sum is larger or equal to // 'min_sum' - all it does is remove extra notes if it does reach that value. // Note that proper usage of this preprocessor requires for notes to be sorted in descending order. -pub fn preprocess_notes_min_sum( +pub fn preprocess_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr index 8840d245b5d..9d75a920b8a 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr @@ -15,8 +15,8 @@ trait OwnedNote { fn get_amount(self) -> U128; } -global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. -global TOKEN_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global TOKEN_NOTE_LEN: u32 = 3; // 3 plus a header. +global TOKEN_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; // docs:start:TokenNote #[aztec(note)] diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr index a2bc9c31bff..a01a0fcab4f 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr @@ -1,11 +1,11 @@ use dep::aztec::{note::{note_header::NoteHeader, note_interface::NoteInterface}, context::PrivateContext}; -global TEST_NOTE_LEN: Field = 1; +global TEST_NOTE_LEN: u32 = 1; // TEST_NOTE_LENGTH * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global TEST_NOTE_BYTES_LENGTH: Field = 1 * 32 + 64; +global TEST_NOTE_BYTES_LENGTH: u32 = 1 * 32 + 64; // A note which stores a field and is expected to be passed around using the `addNote` function. -// WARNING: This Note is not private as it does not contain randomness and hence it can be easy to perform +// WARNING: This Note is not private as it does not contain randomness and hence it can be easy to perform // serialized_note attack on it. This note has been developed purely for testing purposes so that it can easily be // manually added to PXE. Do not use for real applications. #[aztec(note)] diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 70c63308e5a..3c1c6498077 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -22,7 +22,7 @@ contract TokenBlacklist { use crate::types::{transparent_note::TransparentNote, token_note::TokenNote, balances_map::BalancesMap, roles::UserFlags}; // Changing an address' roles has a certain block delay before it goes into effect. - global CHANGE_ROLES_DELAY_BLOCKS = 2; + global CHANGE_ROLES_DELAY_BLOCKS: u32 = 2; #[aztec(storage)] struct Storage { diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index d0aeac1b7cf..dee2f7ddd57 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -24,14 +24,14 @@ impl BalancesMap { } impl BalancesMap { - unconstrained pub fn balance_of( + unconstrained pub fn balance_of( self: Self, owner: AztecAddress ) -> U128 where T: NoteInterface + OwnedNote { self.balance_of_with_offset(owner, 0) } - unconstrained pub fn balance_of_with_offset( + unconstrained pub fn balance_of_with_offset( self: Self, owner: AztecAddress, offset: u32 @@ -55,7 +55,7 @@ impl BalancesMap { } impl BalancesMap { - pub fn add( + pub fn add( self: Self, owner: AztecAddress, addend: U128 @@ -75,7 +75,7 @@ impl BalancesMap { } } - pub fn sub( + pub fn sub( self: Self, owner: AztecAddress, subtrahend: U128 @@ -100,7 +100,7 @@ impl BalancesMap { } } -pub fn filter_notes_min_sum( +pub fn filter_notes_min_sum( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 21d1a365d03..5023d643877 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -10,9 +10,9 @@ trait OwnedNote { fn get_amount(self) -> U128; } -global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. +global TOKEN_NOTE_LEN: u32 = 3; // 3 plus a header. // TOKEN_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global TOKEN_NOTE_BYTES_LEN: Field = 3 * 32 + 64; +global TOKEN_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; #[aztec(note)] struct TokenNote { diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index b3a5c8f3171..b6c641d48a7 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -5,9 +5,9 @@ use dep::aztec::{ protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator} }; -global TRANSPARENT_NOTE_LEN: Field = 2; +global TRANSPARENT_NOTE_LEN: u32 = 2; // TRANSPARENT_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) -global TRANSPARENT_NOTE_BYTES_LEN: Field = 2 * 32 + 64; +global TRANSPARENT_NOTE_BYTES_LEN: u32 = 2 * 32 + 64; // Transparent note represents a note that is created in the clear (public execution), but can only be spent by those // that know the preimage of the "secret_hash" (the secret). This is typically used when shielding a token balance. @@ -46,7 +46,7 @@ impl NoteInterface for Transpa // 1) We pass the secret as an argument to the function and use it to compute a secret hash, // 2) we fetch a note via the "get_notes" oracle which accepts the secret hash as an argument, // 3) the "get_notes" oracle constrains that the secret hash in the returned note matches the one computed in - // circuit. + // circuit. // This achieves that the note can only be spent by the party that knows the secret. fn compute_nullifier_without_context(self) -> Field { let note_hash_for_nullify = compute_note_hash_for_nullify(self); diff --git a/noir/noir-repo/test_programs/compile_success_empty/regression_4436/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/regression_4436/src/main.nr index 834ea3250cc..336d0f1f4ed 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/regression_4436/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/regression_4436/src/main.nr @@ -3,8 +3,8 @@ trait LibTrait { fn get_constant() -> Field; } -global STRUCT_A_LEN: Field = 3; -global STRUCT_B_LEN: Field = 5; +global STRUCT_A_LEN: u32 = 3; +global STRUCT_B_LEN: u32 = 5; struct StructA; struct StructB; From 6d071a7438bb49ce4a289ec8ca57aef5dcdcd805 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 18 Sep 2024 13:54:03 +0000 Subject: [PATCH 35/79] . --- noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index 8cd4643df5d..142c2321c08 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -11,7 +11,10 @@ trait ProveNoteInclusion { } impl ProveNoteInclusion for Header { - fn prove_note_inclusion(self, note: Note) where Note: NoteInterface { + fn prove_note_inclusion( + self, + note: Note + ) where Note: NoteInterface { let note_hash = compute_note_hash_for_nullify(note); let witness = unsafe { From 279a22e0f261ddaaec60350335bba62b56ae6720 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 18 Sep 2024 13:59:28 +0000 Subject: [PATCH 36/79] . --- .../crates/types/src/merkle_tree/membership.nr | 2 -- 1 file changed, 2 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr index 48ea00b3a90..72e77f13ffa 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr @@ -117,8 +117,6 @@ mod tests { TestLeafPreimage { value: 30, next_value: 40 }, ]; - - fn build_tree() -> NonEmptyMerkleTree<4, 3, 1, 2> { NonEmptyMerkleTree::new( leaf_preimages.map(|leaf_preimage: TestLeafPreimage| leaf_preimage.as_leaf()), From 75238c3fc9f45726eaf85deb1e2e0f64d76dbf35 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 18 Sep 2024 14:29:06 +0000 Subject: [PATCH 37/79] . --- .../noir-protocol-circuits/crates/blob/src/config.nr | 10 +++++----- .../crates/parity-lib/src/root/root_parity_inputs.nr | 6 ++++-- .../crates/reset-kernel-lib/src/reset/read_request.nr | 4 ++-- .../crates/rollup-lib/src/base/base_rollup_inputs.nr | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr b/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr index 5062a5506a3..8b3fbac3339 100644 --- a/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr +++ b/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr @@ -2,11 +2,11 @@ use dep::bigint::{BigNum, fields::bls12_381Fr::BLS12_381_Fr_Params}; type F = BigNum<3, BLS12_381_Fr_Params>; -global FIELDS_PER_BLOB: u64 = 4096; -global LOG_FIELDS_PER_BLOB: u64 = 12; -global EXTRA_FIELDS_PER_BLOB: u64 = 16; // 16 = floor(4096 FIELDS_PER_BLOB / 254 noir_field_bits), wasting only 32 bits. -global NOIR_FIELDS_PER_BLOB: u64 = FIELDS_PER_BLOB + EXTRA_FIELDS_PER_BLOB; -global FIELDS_CARRYING_AN_EXTRA_BIT_PER_BLOB: u64 = EXTRA_FIELDS_PER_BLOB * 254; // EXTRA_FIELDS_PER_BLOB * 254 = 4064. So the first 4064 bls Fr fields in the blob will carry an extra bit in their 255th bit position, that will be used to reconstitute 16 extra fields. +global FIELDS_PER_BLOB: u32 = 4096; +global LOG_FIELDS_PER_BLOB: u32 = 12; +global EXTRA_FIELDS_PER_BLOB: u32 = 16; // 16 = floor(4096 FIELDS_PER_BLOB / 254 noir_field_bits), wasting only 32 bits. +global NOIR_FIELDS_PER_BLOB: u32 = FIELDS_PER_BLOB + EXTRA_FIELDS_PER_BLOB; +global FIELDS_CARRYING_AN_EXTRA_BIT_PER_BLOB: u32 = EXTRA_FIELDS_PER_BLOB * 254; // EXTRA_FIELDS_PER_BLOB * 254 = 4064. So the first 4064 bls Fr fields in the blob will carry an extra bit in their 255th bit position, that will be used to reconstitute 16 extra fields. global D: F = BigNum { limbs: [4096, 0, 0] }; global D_INV = BigNum { limbs: [0x686828bfce5c19400fffff00100001, 0x6878b46ae3705eb6a46a89213de7d3, 0x73e6] }; diff --git a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr index a40fef1590c..997d2f95972 100644 --- a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr @@ -4,7 +4,7 @@ use crate::{ utils::sha256_merkle_tree::Sha256MerkleTree }; -global NUM_BASE_PARITY_PER_ROOT_PARITY: u64 = 4; +global NUM_BASE_PARITY_PER_ROOT_PARITY: u32 = 4; struct RootParityInputs { children: [RootParityInput; NUM_BASE_PARITY_PER_ROOT_PARITY], @@ -59,7 +59,9 @@ mod tests { use dep::types::tests::fixtures; use dep::types::constants::BASE_PARITY_INDEX; - fn test_setup() -> [RootParityInput; 4] { + use super::NUM_BASE_PARITY_PER_ROOT_PARITY; + + fn test_setup() -> [RootParityInput; NUM_BASE_PARITY_PER_ROOT_PARITY] { // 31 byte test SHA roots let children_sha_roots = [ 0xb3a3fc1968999f2c2d798b900bdf0de41311be2a4d20496a7e792a521fc8ab, diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr index b7196b494f2..5929ea98dd5 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr @@ -86,7 +86,7 @@ fn validate_pending_read_requests( +fn validate_settled_read_requests( read_requests: [ScopedReadRequest; READ_REQUEST_LEN], hints: [H; NUM_SETTLED_READS], tree_root: Field @@ -143,7 +143,7 @@ pub fn verify_reset_read_requests< let NUM_PENDING_READS: u32, let NUM_SETTLED_READS: u32, H, - TREE_HEIGHT, + let TREE_HEIGHT: u32, LEAF_PREIMAGE >( read_requests: [ScopedReadRequest; READ_REQUEST_LEN], diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 937af0792e2..ffaf9527fc2 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -492,8 +492,8 @@ mod tests { value: Field, } - global MAX_nullifiers_PER_TEST = 4; - global MAX_PUBLIC_DATA_READS_PER_TEST = 2; + global MAX_nullifiers_PER_TEST: u32 = 4; + global MAX_PUBLIC_DATA_READS_PER_TEST: u32 = 2; fn update_public_data_tree( public_data_tree: &mut NonEmptyMerkleTree, From 34144d644432e7adc302617bdb0876c034bfab2d Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 14:38:42 +0000 Subject: [PATCH 38/79] indexed note fields --- .../src/core/libraries/ConstantsGen.sol | 12 +-- .../aztec-nr/aztec/src/macros/notes/mod.nr | 79 ++++++++++++------- .../crates/types/src/constants.nr | 12 +-- yarn-project/circuits.js/src/constants.gen.ts | 12 +-- 4 files changed, 68 insertions(+), 47 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 1e1d3606c5c..cf7a6a9f960 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -131,17 +131,17 @@ library Constants { uint256 internal constant L2_GAS_PER_NOTE_HASH = 32; uint256 internal constant L2_GAS_PER_NULLIFIER = 64; uint256 internal constant CANONICAL_KEY_REGISTRY_ADDRESS = - 6823425185167517386380694778823032861295161686691976789058601691508103815523; + 10536361358275073765062614648062211780027045486672640416335829595694222800789; uint256 internal constant CANONICAL_AUTH_REGISTRY_ADDRESS = - 19361441716519463065948254497947932755739298943049449145365332870925554042208; + 3193394520848240339042174260887368015244189807412437862264526499389876805968; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = - 17119407406465801909352274670277571579675739451008438338071219340964365249977; + 2888253181140434202600946137610803790678961451820394869801342223909105696356; uint256 internal constant REGISTERER_CONTRACT_ADDRESS = - 12405643717676802437578418009978929188439257864607100766293128479227092050857; + 21748523092328826737377319989875487952297567340504996985769574672917248477115; uint256 internal constant FEE_JUICE_ADDRESS = - 12096583827711775893711303288210371301779120762215263550909768879597884314839; + 8841799412790957220630076556157089925484823620333112594242679125846566463920; uint256 internal constant ROUTER_ADDRESS = - 13369993014609648298719593339393818582619449364029983937306132176549332172208; + 949422206351581749693459491613246405703946584592224897261267487800745982005; uint256 internal constant AZTEC_ADDRESS_LENGTH = 1; uint256 internal constant GAS_FEES_LENGTH = 2; uint256 internal constant GAS_LENGTH = 2; diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 3cc00c27a56..b6f3ae916ff 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -33,8 +33,8 @@ comptime fn generate_note_interface( s: StructDefinition, note_type_id: Field, hiding_point_name: Quoted, - fixed_fields: [(Quoted, Type)], - nullable_fields: [Quoted] + indexed_fixed_fields: [(Quoted, Type, u32)], + indexed_nullable_fields: [(Quoted, u32)] ) -> (Quoted, u32) { let name = s.name(); let typ = s.as_type(); @@ -56,8 +56,8 @@ comptime fn generate_note_interface( &[(quote {header}, quote { aztec::note::note_header::NoteHeader::empty() })] ); - let fixed_fields_args = fixed_fields.map(| (name, _): (Quoted, Type) | quote{self.$name}).push_back(quote {self.get_header().storage_slot}).join(quote {,}); - let nullable_fields_args = nullable_fields.map(|field| quote { self.$field }).join(quote {,}); + let fixed_fields_args = indexed_fixed_fields.map(| (name, _, _): (Quoted, Type, u32) | quote{self.$name}).push_back(quote {self.get_header().storage_slot}).join(quote {,}); + let nullable_fields_args = indexed_nullable_fields.map(|(name, _): (Quoted, u32)| quote { self.$name }).join(quote {,}); (quote { impl aztec::note::note_interface::NoteInterface<$content_len> for $name { @@ -164,8 +164,8 @@ pub(crate) comptime fn generate_note_export(s: StructDefinition, note_type_id: F comptime fn generate_note_hiding_point( s: StructDefinition, - fixed_fields: [(Quoted, Type)], - nullable_fields: [Quoted] + indexed_fixed_fields: [(Quoted, Type, u32)], + indexed_nullable_fields: [(Quoted, u32)] ) -> (Quoted, Quoted) { let name = s.name(); let hiding_point_name = f"{name}HidingPoint".quoted_contents(); @@ -176,10 +176,10 @@ comptime fn generate_note_hiding_point( let mut new_generics_list = &[]; let mut new_trait_bounds_list = &[]; - for i in 0..fixed_fields.len() { - let (field_name, _) = fixed_fields[i]; + for i in 0..indexed_fixed_fields.len() { + let (field_name, _, index) = indexed_fixed_fields[i]; let arg_type = f"N{i}".quoted_contents(); - let generator_index = i + 1; + let generator_index = index + 1; new_generators_list = new_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); new_scalars_list = new_scalars_list.push_back(quote { std::hash::from_field_unsafe($field_name.to_field()) }); new_args_list = new_args_list.push_back(quote { $field_name: $arg_type }); @@ -212,11 +212,11 @@ comptime fn generate_note_hiding_point( let mut finalize_generics_list = &[]; let mut finalize_trait_bounds_list = &[]; - for i in 0..nullable_fields.len() { - let field_name = nullable_fields[i]; + for i in 0..indexed_nullable_fields.len() { + let (field_name, index) = indexed_nullable_fields[i]; let arg_type = f"N{i}".quoted_contents(); finalize_args_list = finalize_args_list.push_back(quote { $field_name: $arg_type }); - let generator_index = i + 1 + fixed_fields.len(); + let generator_index = index + 1; finalize_generators_list = finalize_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); finalize_scalars_list = finalize_scalars_list.push_back(quote { std::hash::from_field_unsafe($field_name.to_field()) }); finalize_generics_list = finalize_generics_list.push_back(quote { $arg_type }); @@ -229,7 +229,7 @@ comptime fn generate_note_hiding_point( quote {self} }; - let finalize_body = if nullable_fields.len() > 0 { + let finalize_body = if indexed_nullable_fields.len() > 0 { let finalize_generators = finalize_generators_list.join(quote {,}); let finalize_scalars = finalize_scalars_list.join(quote {,}); quote { @@ -325,16 +325,31 @@ comptime fn register_note(note: StructDefinition, note_serialized_len: u32, note NOTES.insert(note.as_type(), (note, note_serialized_len, note_type_id)); } -comptime fn extract_fixed_fields(s: StructDefinition, nullable_fields: [Quoted]) -> [(Quoted, Type)] { - s.fields().filter( - | (name, typ): (Quoted, Type) | (typ != NOTE_HEADER_TYPE) & nullable_fields.all(| field | field != name) - ) +comptime fn index_note_fields( + s: StructDefinition, + nullable_fields: [Quoted] +) -> ([(Quoted, Type, u32)], [(Quoted, u32)]) { + let mut indexed_fixed_fields = &[]; + let mut indexed_nullable_fields = &[]; + let mut counter: u32 = 0; + for field in s.fields() { + let (name, typ) = field; + if (typ != NOTE_HEADER_TYPE) { + if nullable_fields.all(| field | field != name) { + indexed_fixed_fields = indexed_fixed_fields.push_back((name, typ, counter)); + } else { + indexed_nullable_fields = indexed_nullable_fields.push_back((name, counter)); + } + } + counter+=1; + } + (indexed_fixed_fields, indexed_nullable_fields) } comptime fn common_note_annotation( s: StructDefinition, - fixed_fields: [(Quoted, Type)], - nullable_fields: [Quoted] + indexed_fixed_fields: [(Quoted, Type, u32)], + indexed_nullable_fields: [(Quoted, u32)] ) -> (Quoted, Quoted, Field) { // Automatically inject header if not present let filtered_header = s.fields().filter(| (_, typ): (Quoted, Type) | typ == NOTE_HEADER_TYPE); @@ -342,7 +357,7 @@ comptime fn common_note_annotation( let new_fields = s.fields().push_back((quote { header }, NOTE_HEADER_TYPE)); s.set_fields(new_fields); } - let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, fixed_fields, nullable_fields); + let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, indexed_fixed_fields, indexed_nullable_fields); let note_properties = generate_note_properties(s); let note_type_id = compute_note_type_id(s.name()); @@ -354,14 +369,14 @@ comptime fn common_note_annotation( #[varargs] pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { - let fixed_fields = extract_fixed_fields(s, nullable_fields); - let (common, hiding_point_name, note_type_id) = common_note_annotation(s, fixed_fields, nullable_fields); + let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, nullable_fields); + let (common, hiding_point_name, note_type_id) = common_note_annotation(s, indexed_fixed_fields, indexed_nullable_fields); let (note_interface_impl, note_serialized_len) = generate_note_interface( s, note_type_id, hiding_point_name, - fixed_fields, - nullable_fields + indexed_fixed_fields, + indexed_nullable_fields ); let partial_note_impl = generate_partial_note_impl(s, hiding_point_name); register_note(s, note_serialized_len, note_type_id); @@ -374,9 +389,15 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> } pub comptime fn note(s: StructDefinition) -> Quoted { - let fixed_fields = extract_fixed_fields(s, &[]); - let (common, hiding_point_name, note_type_id) = common_note_annotation(s, fixed_fields, &[]); - let (note_interface_impl, note_serialized_len) = generate_note_interface(s, note_type_id, hiding_point_name, fixed_fields, &[]); + let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, &[]); + let (common, hiding_point_name, note_type_id) = common_note_annotation(s, indexed_fixed_fields, indexed_nullable_fields); + let (note_interface_impl, note_serialized_len) = generate_note_interface( + s, + note_type_id, + hiding_point_name, + indexed_fixed_fields, + indexed_nullable_fields + ); register_note(s, note_serialized_len, note_type_id); quote { @@ -386,8 +407,8 @@ pub comptime fn note(s: StructDefinition) -> Quoted { } pub comptime fn note_custom_interface(s: StructDefinition) -> Quoted { - let fixed_fields = extract_fixed_fields(s, &[]); - let (common, _, note_type_id) = common_note_annotation(s, fixed_fields, &[]); + let (indexed_fixed_fields, indexed_nullable_fields)= index_note_fields(s, &[]); + let (common, _, note_type_id) = common_note_annotation(s, indexed_fixed_fields, indexed_nullable_fields); let serialized_len_type = fresh_type_variable(); let note_interface_impl = s.as_type().get_trait_impl(quote { NoteInterface<$serialized_len_type> }.as_trait_constraint()); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 61b2a8a4f78..32b3a41ef5e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -188,12 +188,12 @@ global L2_GAS_PER_NOTE_HASH: u32 = 32; global L2_GAS_PER_NULLIFIER: u32 = 64; // CANONICAL CONTRACT ADDRESSES -global CANONICAL_KEY_REGISTRY_ADDRESS = AztecAddress::from_field(0x0f15ebfaa7e1bb0d1c542c954a8f605909d0fa0a5fd829122bfdec15b4ada163); -global CANONICAL_AUTH_REGISTRY_ADDRESS = AztecAddress::from_field(0x2ace300b02ca5ab0a25052b1e852913a47292096997ca09f758c0e3624e84560); -global DEPLOYER_CONTRACT_ADDRESS = AztecAddress::from_field(0x25d93dc07b5baaf53a98caeae2679df3528cb83e11e2640a57a0a53abbaaadb9); -global REGISTERER_CONTRACT_ADDRESS = AztecAddress::from_field(0x1b6d5873cef5a35f681ab9468527f356c96e09b3c64603aef404ec2ad80aa3a9); -global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x1abe6c7f5c4caf04cbf7556495e08ad9c0a225a5f9d33554ae07285b13c494d7); -global ROUTER_ADDRESS = AztecAddress::from_field(0x1d8f25db3e8faa6a96cb1ecf57876a2ee04581deb3c4f181488ccd817abcbdb0); +global CANONICAL_KEY_REGISTRY_ADDRESS = AztecAddress::from_field(0x174b5e838f4e837627bc8a3ebc4c96d3738bf30d3bf0db16f5c565a04533f795); +global CANONICAL_AUTH_REGISTRY_ADDRESS = AztecAddress::from_field(0x070f65b1fba711fbd8512aefb6178eace06ad812bc52db99d8763e2b06f12150); +global DEPLOYER_CONTRACT_ADDRESS = AztecAddress::from_field(0x0662b180a46cdc8f5deedd4baa002e12be5c4f8d8c3412a2f97f080a26e7fe64); +global REGISTERER_CONTRACT_ADDRESS = AztecAddress::from_field(0x30153a54396e050f4d947d3ffcb3492635ef71f079e9a09a427e4a3ac3a607bb); +global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x138c47f7a69363d2bd2c76ccf08526613aa32958b0a504cfc5f5aab7fe2969b0); +global ROUTER_ADDRESS = AztecAddress::from_field(0x02195a9adfbd7cac0ef961ac18835f10b5d049753cd4e7cbf50059c2e8caf835); // LENGTH OF STRUCTS SERIALIZED TO FIELDS global AZTEC_ADDRESS_LENGTH: u32 = 1; diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 7d751f670a1..0b23b95fba3 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -116,14 +116,14 @@ export const L2_GAS_PER_LOG_BYTE = 4; export const L2_GAS_PER_NOTE_HASH = 32; export const L2_GAS_PER_NULLIFIER = 64; export const CANONICAL_KEY_REGISTRY_ADDRESS = - 6823425185167517386380694778823032861295161686691976789058601691508103815523n; + 10536361358275073765062614648062211780027045486672640416335829595694222800789n; export const CANONICAL_AUTH_REGISTRY_ADDRESS = - 19361441716519463065948254497947932755739298943049449145365332870925554042208n; -export const DEPLOYER_CONTRACT_ADDRESS = 17119407406465801909352274670277571579675739451008438338071219340964365249977n; + 3193394520848240339042174260887368015244189807412437862264526499389876805968n; +export const DEPLOYER_CONTRACT_ADDRESS = 2888253181140434202600946137610803790678961451820394869801342223909105696356n; export const REGISTERER_CONTRACT_ADDRESS = - 12405643717676802437578418009978929188439257864607100766293128479227092050857n; -export const FEE_JUICE_ADDRESS = 12096583827711775893711303288210371301779120762215263550909768879597884314839n; -export const ROUTER_ADDRESS = 13369993014609648298719593339393818582619449364029983937306132176549332172208n; + 21748523092328826737377319989875487952297567340504996985769574672917248477115n; +export const FEE_JUICE_ADDRESS = 8841799412790957220630076556157089925484823620333112594242679125846566463920n; +export const ROUTER_ADDRESS = 949422206351581749693459491613246405703946584592224897261267487800745982005n; export const AZTEC_ADDRESS_LENGTH = 1; export const GAS_FEES_LENGTH = 2; export const GAS_LENGTH = 2; From ebd3817cfd876d4a6181bdfb8214d3febab6a657 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 14:52:06 +0000 Subject: [PATCH 39/79] uint note --- .../aztec-nr/uint-note/src/uint_note.nr | 76 +------------------ 1 file changed, 4 insertions(+), 72 deletions(-) diff --git a/noir-projects/aztec-nr/uint-note/src/uint_note.nr b/noir-projects/aztec-nr/uint-note/src/uint_note.nr index 706ff6fa797..1062566fa7a 100644 --- a/noir-projects/aztec-nr/uint-note/src/uint_note.nr +++ b/noir-projects/aztec-nr/uint-note/src/uint_note.nr @@ -1,16 +1,8 @@ use dep::aztec::{ - generators::{Ga1 as G_amt, Ga2 as G_npk, Ga3 as G_rnd, G_slot}, - prelude::{NoteInterface, PrivateContext}, - protocol_types::{ - constants::GENERATOR_INDEX__NOTE_NULLIFIER, point::{Point, POINT_LENGTH}, - hash::poseidon2_hash_with_separator, traits::Serialize -}, - note::utils::compute_note_hash_for_nullify, keys::getters::get_nsk_app + prelude::{NullifiableNote, PrivateContext}, + protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, + note::utils::compute_note_hash_for_nullify, keys::getters::get_nsk_app, macros::notes::note }; -use dep::std::{embedded_curve_ops::multi_scalar_mul, hash::from_field_unsafe}; - -global UINT_NOTE_LEN: u32 = 3; // 3 plus a header. -global UINT_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; #[note] struct UintNote { @@ -22,7 +14,7 @@ struct UintNote { randomness: Field, } -impl NoteInterface for UintNote { +impl NullifiableNote for UintNote { fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let secret = context.request_nsk_app(self.npk_m_hash); poseidon2_hash_with_separator( @@ -42,66 +34,6 @@ impl NoteInterface for UintNote { GENERATOR_INDEX__NOTE_NULLIFIER ) } - - fn compute_note_hiding_point(self) -> Point { - // We use the unsafe version because the multi_scalar_mul will constrain the scalars. - let amount_scalar = from_field_unsafe(self.value.to_integer()); - let npk_m_hash_scalar = from_field_unsafe(self.npk_m_hash); - let randomness_scalar = from_field_unsafe(self.randomness); - let slot_scalar = from_field_unsafe(self.header.storage_slot); - // We compute the note hiding point as: - // `G_amt * amount + G_npk * npk_m_hash + G_rnd * randomness + G_slot * slot` - // instead of using pedersen or poseidon2 because it allows us to privately add and subtract from amount - // in public by leveraging homomorphism. - multi_scalar_mul( - [G_amt, G_npk, G_rnd, G_slot], - [amount_scalar, npk_m_hash_scalar, randomness_scalar, slot_scalar] - ) - } -} - -impl UintNote { - // TODO: Merge this func with `compute_note_hiding_point`. I (benesjan) didn't do it in the initial PR to not have - // to modify macros and all the related funcs in it. - fn to_note_hiding_point(self) -> UintNoteHidingPoint { - UintNoteHidingPoint::new(self.compute_note_hiding_point()) - } -} - -struct UintNoteHidingPoint { - inner: Point -} - -impl UintNoteHidingPoint { - fn new(point: Point) -> Self { - Self { inner: point } - } - - fn add_amount(&mut self, amount: U128) { - self.inner = multi_scalar_mul([G_amt], [from_field_unsafe(amount.to_integer())]) + self.inner; - } - - fn add_npk_m_hash(&mut self, npk_m_hash: Field) { - self.inner = multi_scalar_mul([G_npk], [from_field_unsafe(npk_m_hash)]) + self.inner; - } - - fn add_randomness(&mut self, randomness: Field) { - self.inner = multi_scalar_mul([G_rnd], [from_field_unsafe(randomness)]) + self.inner; - } - - fn add_slot(&mut self, slot: Field) { - self.inner = multi_scalar_mul([G_slot], [from_field_unsafe(slot)]) + self.inner; - } - - fn finalize(self) -> Field { - self.inner.x - } -} - -impl Serialize for UintNoteHidingPoint { - fn serialize(self) -> [Field; POINT_LENGTH] { - self.inner.serialize() - } } impl Eq for UintNote { From 86ae957f783a0dbf9925ea86ebef0155d26ae7f4 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 18:39:52 +0000 Subject: [PATCH 40/79] more u32 --- .../aztec/src/oracle/get_l1_to_l2_membership_witness.nr | 2 +- .../aztec/src/oracle/get_nullifier_membership_witness.nr | 2 +- .../aztec-nr/aztec/src/oracle/get_public_data_witness.nr | 2 +- .../noir-contracts/contracts/card_game_contract/src/game.nr | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr index 38e81094b2b..53de8599124 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr @@ -1,6 +1,6 @@ use dep::protocol_types::{address::AztecAddress}; -global L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH: u64 = 17; +global L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH: u32 = 17; // Obtains membership witness (index and sibling path) for a message in the L1 to L2 message tree. #[oracle(getL1ToL2MembershipWitness)] diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr index 5050988fee2..986507b1e3c 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr @@ -4,7 +4,7 @@ use dep::protocol_types::{ }; // INDEX_LENGTH + NULLIFIER_LEAF_PREIMAGE_LENGTH + NULLIFIER_TREE_HEIGHT -global NULLIFIER_MEMBERSHIP_WITNESS: Field = 24; +global NULLIFIER_MEMBERSHIP_WITNESS: u32 = 24; struct NullifierMembershipWitness { index: Field, diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr index 8c0f76f5eb8..4f567868dcd 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr @@ -1,7 +1,7 @@ use dep::protocol_types::{constants::PUBLIC_DATA_TREE_HEIGHT, data::PublicDataTreeLeafPreimage, utils::arr_copy_slice}; global LEAF_PREIMAGE_LENGTH: u32 = 4; -global PUBLIC_DATA_WITNESS: Field = 45; +global PUBLIC_DATA_WITNESS: u32 = 45; struct PublicDataWitness { index: Field, diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr index 7cceefb424a..4eb8d5879de 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr @@ -144,10 +144,10 @@ impl Game { assert(self.started, "Game not started"); assert(!self.finished, "Game finished"); - let round_offset = self.current_round * (NUMBER_OF_PLAYERS as u64); + let round_offset = self.current_round * NUMBER_OF_PLAYERS; self.rounds_cards[round_offset + self.current_player] = card; - self.current_player = (self.current_player + 1) % (NUMBER_OF_PLAYERS as u64); + self.current_player = (self.current_player + 1) % NUMBER_OF_PLAYERS; if self.current_player == 0 { self._finish_round(); From 5a2d6c76df7ea0c913697003e92251a8f50aa550 Mon Sep 17 00:00:00 2001 From: thunkar Date: Wed, 18 Sep 2024 19:41:02 +0000 Subject: [PATCH 41/79] fixes --- noir-projects/aztec-nr/aztec/src/macros/mod.nr | 7 +++---- .../noir-contracts/contracts/avm_test_contract/src/main.nr | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index fd30b417026..a74ef784da3 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -88,11 +88,10 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quote }); let if_statements = notes.map( - | (_, (note, _, _)): (Type, (StructDefinition, u32, Field)) | { - let note_name = note.name(); + | (typ, (note, _, _)): (Type, (StructDefinition, u32, Field)) | { quote { - if note_type_id == $note_name::get_note_type_id() { - aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($note_name::deserialize_content, note_header, compute_nullifier, serialized_note) + if note_type_id == $typ::get_note_type_id() { + aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::deserialize_content, note_header, compute_nullifier, serialized_note) } } } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 73265c1b7ec..86528ddd98c 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -219,14 +219,14 @@ contract AvmTest { 1 } - #[aztec(public)] + #[public] fn assert_calldata_copy(args: [Field; 3]) { let offset = 2; // Make this 0 when PublicContextInputs is removed. let cd: [Field; 3] = dep::aztec::context::public_context::calldata_copy(offset, 3); assert(cd == args, "Calldata copy failed"); } - #[aztec(public)] + #[public] fn return_oracle() -> [Field; 3] { dep::aztec::context::public_context::avm_return([1, 2, 3]); [4, 5, 6] // Should not get here. @@ -495,7 +495,7 @@ contract AvmTest { * calls - but not blackboxes!), since otherwise the whole call will * be optimized away. ************************************************************************/ - #[aztec(public)] + #[public] fn bulk_testing(args_field: [Field; 10], args_u8: [u8; 10]) { // Using "inputs" here is a bit of a hack. It's the PublicContextInputs injected // by the public macros. It's needed by the non-nested call to an entry point function. From b0f70344937469dea36bb8a69bcb806cb60dc2aa Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Thu, 19 Sep 2024 00:12:59 +0000 Subject: [PATCH 42/79] . --- .../noir-protocol-circuits/crates/types/src/constants.nr | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index e490b612448..588f52f8aba 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -295,12 +295,10 @@ global VERIFICATION_KEY_LENGTH_IN_FIELDS: u32 = 128; // 16 above refers to the constant AvmFlavor::NUM_PRECOMPUTED_ENTITIES global AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS: u32 = 2 + 16 * 4; -// The length is 2 + AvmFlavor::NUM_PRECOMPUTED_ENTITIES * 4 -global AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS = 2 + 16 * 4; // `AVM_PROOF_LENGTH_IN_FIELDS` must be updated when AVM circuit changes. // To determine latest value, hover `COMPUTED_AVM_PROOF_LENGTH_IN_FIELDS` // in barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp -global AVM_PROOF_LENGTH_IN_FIELDS = 3812; +global AVM_PROOF_LENGTH_IN_FIELDS: u32 = 3812; /** * Enumerate the hash_indices which are used for pedersen hashing. * We start from 1 to avoid the default generators. The generator indices are listed From ae31dfa2df3330c3f502cf834b4d0be451e2cade Mon Sep 17 00:00:00 2001 From: benesjan Date: Thu, 19 Sep 2024 13:12:57 +0000 Subject: [PATCH 43/79] migration notes --- docs/docs/migration_notes.md | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index 85270d9718d..933ea857c8d 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -26,6 +26,83 @@ The `select` function in both `NoteGetterOptions` and `NoteViewerOptions` no lon + options.select(ValueNote::properties().value, Comparator.EQ, amount) ``` +### [Aztec.nr] Changes to contract definition +We've migrated aztec macros to use a newly introduce meta programming feature of Noir. With this transition there are a few changes that need to be done to contracts: + +```diff ++ use dep::aztec::macros::aztec; + +#[aztec] +contract Token { ++ use dep::aztec::macros::{storage::storage, events::event, functions::{initializer, private, view, public}}; + +- #[aztec(storage)] +- struct Storage { ++ #[storage] ++ struct Storage { +- admin: PublicMutable, ++ admin: PublicMutable, +- minters: Map>, ++ minters: Map, Context>, + } + +- #[aztec(public)] +- #[aztec(initializer)] ++ #[public] ++ #[initializer] + fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { + ... + } + +- #[aztec(public)] +- #[aztec(view)] +- fn public_get_name() -> pub FieldCompressedString { ++ #[public] ++ #[view] + fn public_get_name() -> FieldCompressedString { + ... + } +``` + +### [Aztec.nr] Changes to `NoteInterface` +Due to how meta-programming works we are now unable to implement only a selection of methods from a trait. +For this reason we've separated the methods which are auto-implemented and those which needs to be implemented manually into 2 separate traits. +The auto-implemented ones stay in the `NoteInterface` trace and the manually implemented ones were moved to `NullifiableNote` (name likely to change). + +Changes done to AddressNote: +```diff +-global ADDRESS_NOTE_LEN: u32 = 3; +-// ADDRESS_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) +-global ADDRESS_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; + +-#[aztec(note)] ++#[note] +struct AddressNote { + ... +} + +-impl NoteInterface for AddressNote { ++impl NullifiableNote for AddressNote { + fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { + ... + } + + fn compute_nullifier_without_context(self) -> Field { + ... + } +} +``` + +### [Aztec.nr] Changes to contract interface +Instead of `Contract::storage()` static method has been renamed to `Contract::storage_layout()`. + +```diff +- let fee_payer_balances_slot = derive_storage_slot_in_map(Token::storage().balances.slot, fee_payer); +- let user_balances_slot = derive_storage_slot_in_map(Token::storage().balances.slot, user); ++ let fee_payer_balances_slot = derive_storage_slot_in_map(Token::storage_layout().balances.slot, fee_payer); ++ let user_balances_slot = derive_storage_slot_in_map(Token::storage_layout().balances.slot, user); +``` + ## 0.53.0 ### [Aztec.nr] Remove `OwnedNote` and create `UintNote` From e5e299026bb04018d56e4865f31641101d52854e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 19 Sep 2024 15:03:00 +0000 Subject: [PATCH 44/79] Minor migration doc adjustments --- docs/docs/migration_notes.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index 933ea857c8d..be2603f0c13 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -27,7 +27,14 @@ The `select` function in both `NoteGetterOptions` and `NoteViewerOptions` no lon ``` ### [Aztec.nr] Changes to contract definition -We've migrated aztec macros to use a newly introduce meta programming feature of Noir. With this transition there are a few changes that need to be done to contracts: + +We've migrated the Aztec macros to use the newly introduce meta programming Noir feature. Due to being Noir-based, the new macros are less obscure and can be more easily modified. + +As part of this transition, some changes need to be applied to Aztec contracts: + +- The top level `contract` block needs to have the `#[aztec]` macro applied to it. +- All `#[aztec(name)]` macros are renamed to `#[name]`. +- The storage struct (the one that gets the `#[storage]` macro applied) but be generic over a `Context` type, and all state variables receive this type as their last generic type parameter. ```diff + use dep::aztec::macros::aztec; @@ -56,7 +63,7 @@ contract Token { - #[aztec(public)] - #[aztec(view)] -- fn public_get_name() -> pub FieldCompressedString { +- fn public_get_name() -> FieldCompressedString { + #[public] + #[view] fn public_get_name() -> FieldCompressedString { @@ -65,16 +72,12 @@ contract Token { ``` ### [Aztec.nr] Changes to `NoteInterface` -Due to how meta-programming works we are now unable to implement only a selection of methods from a trait. -For this reason we've separated the methods which are auto-implemented and those which needs to be implemented manually into 2 separate traits. -The auto-implemented ones stay in the `NoteInterface` trace and the manually implemented ones were moved to `NullifiableNote` (name likely to change). -Changes done to AddressNote: -```diff --global ADDRESS_NOTE_LEN: u32 = 3; --// ADDRESS_NOTE_LEN * 32 + 32(storage_slot as bytes) + 32(note_type_id as bytes) --global ADDRESS_NOTE_BYTES_LEN: u32 = 3 * 32 + 64; +The new macro model prevents partial trait auto-implementation: they either implement the entire trait or none of it. This means users can no longer implement part of `NoteInterface` and have the rest be auto-implemented. +For this reason we've separated the methods which are auto-implemented and those which needs to be implemented manually into two separate traits: the auto-implemented ones stay in the `NoteInterface` trace and the manually implemented ones were moved to `NullifiableNote` (name likely to change): + +```diff -#[aztec(note)] +#[note] struct AddressNote { @@ -94,7 +97,8 @@ struct AddressNote { ``` ### [Aztec.nr] Changes to contract interface -Instead of `Contract::storage()` static method has been renamed to `Contract::storage_layout()`. + +The `Contract::storage()` static method has been renamed to `Contract::storage_layout()`. ```diff - let fee_payer_balances_slot = derive_storage_slot_in_map(Token::storage().balances.slot, fee_payer); From cd9df606e06b992ad2ba18a72382417473f801e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 19 Sep 2024 19:05:16 +0000 Subject: [PATCH 45/79] Fix nargo fmt crash --- noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index 176311323c3..591e180b9af 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -1,7 +1,4 @@ -use std::{ - collections::umap::UHashMap, - hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} -}; +use std::{collections::umap::UHashMap, hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher}}; use super::utils::get_serialized_size; use super::utils::is_note; @@ -92,7 +89,7 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { storage_layout_constructors = storage_layout_constructors.push_back(quote { $name: dep::aztec::prelude::Storable { slot: $slot } }); //let with_context_generic = add_context_generic(typ, context_generic); //println(with_context_generic); - //new_storage_fields = new_storage_fields.push_back((name, with_context_generic ));ç + //new_storage_fields = new_storage_fields.push_back((name, with_context_generic )); slot += serialized_size; } @@ -130,4 +127,3 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { }; } } - From 881063166774c64a0a41a005d215128afceaa819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 19 Sep 2024 20:22:01 +0000 Subject: [PATCH 46/79] Add comments and misc improvements to utils --- .../aztec-nr/aztec/src/macros/utils.nr | 100 +++++++++++------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index b9231be36cf..0bbb361b286 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -1,10 +1,13 @@ -use std::meta::{typ::fresh_type_variable, unquote, type_of}; +use std::meta::{typ::fresh_type_variable, unquote}; pub(crate) comptime fn get_fn_visibility(f: FunctionDefinition) -> Quoted { if f.has_named_attribute("private") { quote { private } - } else { + } else if f.has_named_attribute("public") { quote { public } + } else { + assert(false, "Function is neither private nor public"); + std::mem::zeroed() } } @@ -32,7 +35,9 @@ pub(crate) comptime fn fn_has_noinitcheck(f: FunctionDefinition) -> bool { f.has_named_attribute("noinitcheck") } +/// Takes a function body as a collection of expressions, and alters it by prepending and appending quoted values. pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quoted) -> Expr { + // We need to quote the body before we can alter its contents, so we fold it by quoting each expression. let mut body_quote = body.fold( quote {}, |full_quote: Quoted, expr: Expr| { @@ -64,21 +69,22 @@ pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: let (element_type, _) = typ.as_array().unwrap(); let serialized_name = f"{name}_serialized".quoted_contents(); quote { - let $serialized_name = $name.map(|x: $element_type | x.serialize()); - for i in 0..$name.len() { - $slice_name = $slice_name.append($serialized_name[i].as_slice()); - } + let $serialized_name = $name.map(|x: $element_type | x.serialize()); + for i in 0..$name.len() { + $slice_name = $slice_name.append($serialized_name[i].as_slice()); } + } } else if typ.as_str().is_some() { quote { - $slice_name = $slice_name.append($name.as_bytes().map(| byte: u8 | byte as Field).as_slice()); - } + $slice_name = $slice_name.append($name.as_bytes().map(| byte: u8 | byte as Field).as_slice()); + } } else { assert(false, f"Cannot add to slice: unsupported type {typ} variable {name}"); std::mem::zeroed() } } +/// Adds a value to a hash::ArgsHasher. Structs and values inside arrays are required to implement the Serialize trait. pub(crate) comptime fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted { if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { quote { $hasher_name.add($name as Field); } @@ -88,15 +94,15 @@ pub(crate) comptime fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Typ let (element_type, _) = typ.as_array().unwrap(); let serialized_name = f"{name}_serialized".quoted_contents(); quote { - let $serialized_name = $name.map(|x: $element_type | x.serialize()); - for i in 0..$name.len() { - $hasher_name.add_multiple($serialized_name[i]); - } + let $serialized_name = $name.map(|x: $element_type | x.serialize()); + for i in 0..$name.len() { + $hasher_name.add_multiple($serialized_name[i]); } + } } else if typ.as_str().is_some() { quote { - $hasher_name.add_multiple($name.as_bytes().map(| byte: u8 | byte as Field)); - } + $hasher_name.add_multiple($name.as_bytes().map(| byte: u8 | byte as Field)); + } } else { assert(false, f"Cannot add to hasher: unsupported type {typ} of variable {name}"); std::mem::zeroed() @@ -113,33 +119,34 @@ comptime fn signature_of_type(typ: Type) -> Quoted { } else { f"u{bit_size}".quoted_contents() } + } else if typ.is_bool() { + quote {bool} + } else if typ.as_str().is_some() { + let str_len_typ = typ.as_str().unwrap(); + let str_len = str_len_typ.as_constant().unwrap(); + f"str<{str_len}>".quoted_contents() + } else if typ.as_array().is_some() { + let (element_type, array_len) = typ.as_array().unwrap(); + let array_len = array_len.as_constant().unwrap(); + let element_typ_quote = signature_of_type(element_type); + f"[{element_typ_quote};{array_len}]".quoted_contents() } else if typ.as_struct().is_some() { let (s, _) = typ.as_struct().unwrap(); let field_signatures = s.fields().map( | (_, typ): (Quoted, Type) | { - signature_of_type(typ) - } + signature_of_type(typ) + } ).join(quote {,}); f"({field_signatures})".quoted_contents() - } else if typ.as_array().is_some() { - let (element_type, array_len) = typ.as_array().unwrap(); - let array_len = array_len.as_constant().unwrap(); - let element_typ_quote = signature_of_type(element_type); - f"[{element_typ_quote};{array_len}]".quoted_contents() - } else if typ.as_str().is_some() { - let str_len_typ = typ.as_str().unwrap(); - let str_len = str_len_typ.as_constant().unwrap(); - f"str<{str_len}>".quoted_contents() } else if typ.as_tuple().is_some() { + // Note that tuples are handled the same way as structs let types = typ.as_tuple().unwrap(); let field_signatures = types.map( | typ: Type | { - signature_of_type(typ) - } + signature_of_type(typ) + } ).join(quote {,}); f"({field_signatures})".quoted_contents() - } else if typ.is_bool() { - quote {bool} } else { assert(false, f"Unsupported type {typ}"); std::mem::zeroed() @@ -175,11 +182,18 @@ impl AsStrQuote for Quoted { } pub(crate) comptime fn compute_fn_selector(f: FunctionDefinition) -> Field { + // The function selector is computed from the function signature, which is made up of the function name and types of + // parameters, but not including the return type. For example, given: + // + // fn foo(a: Field, b: AztecAddress) -> Field + // + // The signature will be "foo(Field,AztecAddress)". + let fn_name = f.name(); let args_signatures = f.parameters().map( | (_, typ): (Quoted, Type) | { - signature_of_type(typ) - } + signature_of_type(typ) + } ).join(quote {,}); let signature_quote = quote { $fn_name($args_signatures) }; let signature_str_quote = signature_quote.as_str_quote(); @@ -191,11 +205,21 @@ pub(crate) comptime fn compute_fn_selector(f: FunctionDefinition) -> Field { } pub(crate) comptime fn compute_event_selector(s: StructDefinition) -> Field { + // The event selector is computed from the type signature of the struct in the event, similar to how one might type + // the constructor function. For example, given: + // + // struct Foo { + // a: Field, + // b: AztecAddress, + // } + // + // The signature will be "Foo(Field,AztecAddress)". + let event_name = s.name(); let args_signatures = s.fields().map( | (_, typ): (Quoted, Type) | { - signature_of_type(typ) - } + signature_of_type(typ) // signature_of_type can handle structs, so this supports nested structs + } ).join(quote {,}); let signature_quote = quote { $event_name($args_signatures) }; let signature_str_quote = signature_quote.as_str_quote(); @@ -210,7 +234,7 @@ pub(crate) comptime fn get_serialized_size(typ: Type) -> u32 { let any = fresh_type_variable(); let maybe_serialize_impl = typ.get_trait_impl(quote { protocol_types::traits::Serialize<$any> }.as_trait_constraint()); assert( - maybe_serialize_impl.is_some(), f"Storable items must implement Serialize. Trait impl not found for {typ}" + maybe_serialize_impl.is_some(), f"Attempted to fetch serialization length, but {typ} does not implement the Serialize trait" ); let serialize_impl = maybe_serialize_impl.unwrap(); serialize_impl.trait_generic_args()[0].as_constant().unwrap() @@ -230,10 +254,8 @@ pub(crate) comptime fn is_note(typ: Type) -> bool { typ.as_struct().map_or( false, | struc: (StructDefinition, [Type]) | { - let (def, _) = struc; - def.has_named_attribute("note") - | def.has_named_attribute("partial_note") - | def.has_named_attribute("note_custom_interface") - } + let (def, _) = struc; + def.has_named_attribute("note") | def.has_named_attribute("partial_note") | def.has_named_attribute("note_custom_interface") + } ) } From 0324653c8a12429c47ba4a815573acf7f304bbd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 19 Sep 2024 21:20:24 +0000 Subject: [PATCH 47/79] Add comments to storage --- .../aztec-nr/aztec/src/macros/storage/mod.nr | 171 +++++++++++------- 1 file changed, 102 insertions(+), 69 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr index 591e180b9af..c438d1b4759 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/storage/mod.nr @@ -5,80 +5,25 @@ use super::utils::is_note; comptime mut global STORAGE_LAYOUT_NAME: UHashMap> = UHashMap::default(); -pub comptime fn is_storage_map(typ: Type) -> bool { - if typ.as_struct().is_some() { - let (def, generics) = typ.as_struct().unwrap(); - let maybe_map = if (def.name() == quote { Map }) & (generics.len() == 3) { - let maybe_key = generics[0]; - let maybe_value = generics[1]; - let maybe_context = generics[2]; - quote { crate::state_vars::map::Map<$maybe_key, $maybe_value, $maybe_context> }.as_type() - } else { - quote {()}.as_type() - }; - typ == maybe_map - } else { - false - } -} - -pub comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map: bool) -> (Quoted, u32) { - assert( - typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container<_, Context>`, or Map" - ); - let (container_struct, generics) = typ.as_struct().unwrap(); - let struct_name = container_struct.name(); - - if is_storage_map(typ) { - let (value_constructor, _) = generate_storage_field_constructor(generics[1], quote { slot }, true); - (quote { $struct_name::new(context, $slot, | context, slot | { $value_constructor }) }, 1) - } else { - let (container_struct, container_struct_generics) = typ.as_struct().unwrap(); - let container_struct_name = container_struct.name(); - // Whatever's stored in a map occupies "a single slot" - let serialized_size = if parent_is_map { - 1 - } else { - let stored_struct = container_struct_generics[0]; - // Private notes always occupy a single slot. Someone could store a Note in PublicMutable for whatever reason though. - if is_note(stored_struct) & (container_struct_name != quote { PublicMutable }) { - 1 - } else { - get_serialized_size(stored_struct) - } - }; - (quote { $struct_name::new(context, $slot)}, serialized_size) - } -} - -comptime fn add_context_generic(typ: Type, context_generic: Type) -> Type { - assert( - typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container<..., Context>`" - ); - if is_storage_map(typ) { - let (def, mut generics) = typ.as_struct().unwrap(); - let name = def.name(); - generics[generics.len() - 2] = add_context_generic(generics[1], context_generic); - generics[generics.len() - 1] = context_generic; - let generics = generics.map(|typ: Type| quote{$typ}).join(quote{,}); - quote { $name<$generics> }.as_type() - } else { - let (def, mut generics) = typ.as_struct().unwrap(); - let name = def.name(); - generics[generics.len() - 1] = context_generic; - let generics = generics.map(|typ: Type| quote{$typ}).join(quote{,}); - quote { $name<$generics> }.as_type() - } -} - -// Just to make sure the contract is marked as having storage -pub comptime fn storage_no_init(_s: StructDefinition) {} - +/// Marks a struct as the one describing the storage layout of a contract. Only a single struct in the entire contract +/// should have this macro (or `storage_no_init`) applied to it. +/// The contract's storage is accessed via the `storage` variable, which will will automatically be made available in +/// all functions as an instance of the struct this macro was applied to. pub comptime fn storage(s: StructDefinition) -> Quoted { + // This macro performs three things: + // - it marks the contract as having storage, so that `macros::utils::module_has_storage` will return true and + // functions will have the storage variable injected and initialized via the `init` function. + // - it implements said `init` function by allocating appropriate storage slots to each state variable. + // - it exposes the storage layout by creating a `StorageLayout` struct that is exposed via the `abi(storage)` + // macro. + let mut slot: u32 = 1; let mut storage_vars_constructors = &[]; let mut storage_layout_fields = &[]; let mut storage_layout_constructors = &[]; + + // TODO(#8658): uncomment the code below to inject the Context type parameter. + //let mut new_storage_fields = &[]; //let context_generic = s.add_generic("Context"); for field in s.fields() { @@ -127,3 +72,91 @@ pub comptime fn storage(s: StructDefinition) -> Quoted { }; } } + +/// Same as `storage`, except the user is in charge of providing an implementation of the `init` constructor function +/// with signature `fn init(context: Context) -> Self`, which allows for manual control of storage slot +/// allocation. Similarly, no `StorageLayout` struct will be created. +/// Only a single struct in the entire contract should have this macro (or `storage`) applied to it. +pub comptime fn storage_no_init(_s: StructDefinition) { + // All `storage` does is provide the `init` implementation, so we don't need to do anything here. Applying this + // macro however will cause for `macros::utils::module_has_storage` to return true, resulting in the injection of + // the `storage` variable. +} + +/// Returns the expression required to initialize a state variable with a given slot, along with its serialization size, +/// i.e. how many contiguous storage slots the variable requires. +comptime fn generate_storage_field_constructor(typ: Type, slot: Quoted, parent_is_map: bool) -> (Quoted, u32) { + assert( + typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container<_, Context>`, or Map" + ); + let (container_struct, generics) = typ.as_struct().unwrap(); + let struct_name = container_struct.name(); + + if is_storage_map(typ) { + // Map state variables recursively initialize their contents - this includes nested maps. + let (value_constructor, _) = generate_storage_field_constructor(generics[1], quote { slot }, true); + (quote { $struct_name::new(context, $slot, | context, slot | { $value_constructor }) }, 1) + } else { + let (container_struct, container_struct_generics) = typ.as_struct().unwrap(); + let container_struct_name = container_struct.name(); + + let serialized_size = if parent_is_map { + // Variables inside a map do not require contiguous slots since the map slot derivation is assumed to result + // in slots very far away from one another. + 1 + } else { + let stored_struct = container_struct_generics[0]; + if is_note(stored_struct) & (container_struct_name != quote { PublicMutable }) { + // Private notes always occupy a single slot, since the slot is only used as a state variable + // identifier. + + // Someone could store a Note in PublicMutable for whatever reason though. + // TODO(#8659): remove the PublicMutable exception above + 1 + } else { + get_serialized_size(stored_struct) + } + }; + + // We assume below that all state variables implement `fn new(context: Context, slot: Field) -> Self`. + (quote { $struct_name::new(context, $slot)}, serialized_size) + } +} + +/// Returns true if `typ` is `state_vars::map::Map`. +comptime fn is_storage_map(typ: Type) -> bool { + if typ.as_struct().is_some() { + let (def, generics) = typ.as_struct().unwrap(); + let maybe_map = if (def.name() == quote { Map }) & (generics.len() == 3) { + let maybe_key = generics[0]; + let maybe_value = generics[1]; + let maybe_context = generics[2]; + quote { crate::state_vars::map::Map<$maybe_key, $maybe_value, $maybe_context> }.as_type() + } else { + quote {()}.as_type() + }; + typ == maybe_map + } else { + false + } +} + +comptime fn add_context_generic(typ: Type, context_generic: Type) -> Type { + assert( + typ.as_struct().is_some(), "Storage containers must be generic structs of the form `Container<..., Context>`" + ); + if is_storage_map(typ) { + let (def, mut generics) = typ.as_struct().unwrap(); + let name = def.name(); + generics[generics.len() - 2] = add_context_generic(generics[1], context_generic); + generics[generics.len() - 1] = context_generic; + let generics = generics.map(|typ: Type| quote{$typ}).join(quote{,}); + quote { $name<$generics> }.as_type() + } else { + let (def, mut generics) = typ.as_struct().unwrap(); + let name = def.name(); + generics[generics.len() - 1] = context_generic; + let generics = generics.map(|typ: Type| quote{$typ}).join(quote{,}); + quote { $name<$generics> }.as_type() + } +} From f50815b2878c3d9b2623dba24d1691694e68a41c Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 20 Sep 2024 15:48:27 -0300 Subject: [PATCH 48/79] Let type always be a slice --- noir-projects/aztec-nr/aztec/src/macros/utils.nr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 0bbb361b286..124e8e2d4f0 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -167,8 +167,8 @@ impl AsStrQuote for Quoted { let token_as_fmt_str = f"{token}"; let token_as_str = unquote!(quote {$token_as_fmt_str}); let token_len = unquote!(quote { $token_as_str.as_bytes().len() }); - let token_as_bytes = unquote!(quote { $token_as_str.as_bytes() }); - total_len+= token_len; + let token_as_bytes = unquote!(quote { $token_as_str.as_bytes().as_slice() }); + total_len += token_len; acc = acc.append(token_as_bytes); } let result = unquote!( From 6c73e62cabaebbce0786af2690654adad78d34f0 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 20 Sep 2024 15:49:31 -0300 Subject: [PATCH 49/79] nargo fmt --- .../noir-protocol-circuits/crates/types/src/constants.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 7defd4dfa58..d860af73422 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -295,11 +295,11 @@ global VERIFICATION_KEY_LENGTH_IN_FIELDS: u32 = 128; // 16 above refers to the constant AvmFlavor::NUM_PRECOMPUTED_ENTITIES global AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS: u32 = 2 + 16 * 4; - // `AVM_PROOF_LENGTH_IN_FIELDS` must be updated when AVM circuit changes. // To determine latest value, hover `COMPUTED_AVM_PROOF_LENGTH_IN_FIELDS` // in barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp global AVM_PROOF_LENGTH_IN_FIELDS: u32 = 3817; + /** * Enumerate the hash_indices which are used for pedersen hashing. * We start from 1 to avoid the default generators. The generator indices are listed From 4d7795d929860ac8ba3e9f5771841de4f60813bf Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 20 Sep 2024 16:32:07 -0300 Subject: [PATCH 50/79] More nargo fmt --- .../contracts/auth_registry_contract/src/main.nr | 3 +-- .../contracts/auth_wit_test_contract/src/main.nr | 5 +---- .../token_blacklist_contract/src/types/transparent_note.nr | 3 --- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr index dcedab28bd9..965f39ea20a 100644 --- a/noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_registry_contract/src/main.nr @@ -3,8 +3,7 @@ use dep::aztec::macros::aztec; #[aztec] contract AuthRegistry { use dep::aztec::{ - state_vars::{PublicMutable, Map}, - protocol_types::address::AztecAddress, + state_vars::{PublicMutable, Map}, protocol_types::address::AztecAddress, macros::{storage::storage, functions::{private, public, internal}} }; use dep::authwit::auth::{IS_VALID_SELECTOR, compute_authwit_message_hash, assert_current_call_valid_authwit}; diff --git a/noir-projects/noir-contracts/contracts/auth_wit_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/auth_wit_test_contract/src/main.nr index 0f40ca3c24d..8fbf2ba8c82 100644 --- a/noir-projects/noir-contracts/contracts/auth_wit_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/auth_wit_test_contract/src/main.nr @@ -2,10 +2,7 @@ use dep::aztec::macros::aztec; #[aztec] contract AuthWitTest { - use dep::aztec::{ - protocol_types::address::AztecAddress, - macros::{functions::{private, public}} - }; + use dep::aztec::{protocol_types::address::AztecAddress, macros::{functions::{private, public}}}; use dep::authwit::auth::{assert_inner_hash_valid_authwit, assert_inner_hash_valid_authwit_public}; diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index 12af4d24966..3d297e6ab7c 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -16,10 +16,8 @@ struct TransparentNote { secret_hash: Field, } - impl NullifiableNote for TransparentNote { - fn compute_nullifier(self, _context: &mut PrivateContext, _note_hash_for_nullify: Field) -> Field { self.compute_nullifier_without_context() } @@ -46,7 +44,6 @@ impl TransparentNote { pub fn new(amount: Field, secret_hash: Field) -> Self { TransparentNote { amount, secret_hash, header: NoteHeader::empty() } } - } impl Eq for TransparentNote { From 9cd31ebe4403d810cf519cbc3ab89f5fe9db8918 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 20 Sep 2024 17:21:45 -0300 Subject: [PATCH 51/79] Don't run the old macros anymore --- noir/noir-repo/compiler/noirc_driver/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/noir/noir-repo/compiler/noirc_driver/src/lib.rs b/noir/noir-repo/compiler/noirc_driver/src/lib.rs index 18a13517b75..81ac5df66ba 100644 --- a/noir/noir-repo/compiler/noirc_driver/src/lib.rs +++ b/noir/noir-repo/compiler/noirc_driver/src/lib.rs @@ -278,6 +278,7 @@ pub fn check_crate( crate_id: CrateId, options: &CompileOptions, ) -> CompilationResult<()> { + let options = CompileOptions { disable_macros: true, ..options.clone() }; let macros: &[&dyn MacroProcessor] = if options.disable_macros { &[] } else { &[&aztec_macros::AztecMacro] }; From d8a14ee99374955e8761e42075a61e10167053ac Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 20 Sep 2024 17:22:35 -0300 Subject: [PATCH 52/79] nargo fmt --- noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index 6c7d698eea0..6f96902ecfe 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -3,8 +3,8 @@ use crate::context::PrivateContext; use crate::note::{ constants::{GET_NOTE_ORACLE_RETURN_LENGTH, VIEW_NOTE_ORACLE_RETURN_LENGTH}, note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, NoteStatus, PropertySelector}, - note_interface::{NoteInterface, NullifiableNote}, - note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_request + note_interface::{NoteInterface, NullifiableNote}, note_viewer_options::NoteViewerOptions, + utils::compute_note_hash_for_read_request }; use crate::oracle; use crate::utils::comparison::compare; From e4e041b892160f035177757395a1db3c4ded1b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 20 Sep 2024 20:50:31 +0000 Subject: [PATCH 53/79] Fix build --- noir-projects/aztec-nr/aztec/src/macros/events/mod.nr | 2 +- noir-projects/aztec-nr/aztec/src/macros/utils.nr | 2 +- .../noir-contracts/contracts/card_game_contract/src/game.nr | 4 ++-- noir/noir-repo/aztec_macros/src/lib.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr index 9b642e6afff..be9e588cb90 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr @@ -57,7 +57,7 @@ comptime fn generate_event_interface(s: StructDefinition) -> Quoted { } fn get_event_type_id() -> aztec::protocol_types::abis::event_selector::EventSelector { - $event_type_id + aztec::protocol_types::abis::event_selector::EventSelector::from_field($event_type_id) } fn emit(self, _emit: fn[Env](Self) -> ()) { diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 124e8e2d4f0..1580a14dae8 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -225,7 +225,7 @@ pub(crate) comptime fn compute_event_selector(s: StructDefinition) -> Field { let signature_str_quote = signature_quote.as_str_quote(); let computation_quote = quote { - protocol_types::abis::event_selector::EventSelector::from_signature($signature_str_quote) + protocol_types::abis::event_selector::EventSelector::from_signature($signature_str_quote).to_field() }; unquote!(computation_quote) } diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr index 7cceefb424a..4eb8d5879de 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr @@ -144,10 +144,10 @@ impl Game { assert(self.started, "Game not started"); assert(!self.finished, "Game finished"); - let round_offset = self.current_round * (NUMBER_OF_PLAYERS as u64); + let round_offset = self.current_round * NUMBER_OF_PLAYERS; self.rounds_cards[round_offset + self.current_player] = card; - self.current_player = (self.current_player + 1) % (NUMBER_OF_PLAYERS as u64); + self.current_player = (self.current_player + 1) % NUMBER_OF_PLAYERS; if self.current_player == 0 { self._finish_round(); diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 4ba8951c2f9..01b0c7fc4b1 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -38,7 +38,7 @@ impl MacroProcessor for AztecMacro { file_id: FileId, context: &HirContext, ) -> Result { - transform(ast, crate_id, file_id, context) + Ok(ast) } fn process_typed_ast( @@ -46,7 +46,7 @@ impl MacroProcessor for AztecMacro { crate_id: &CrateId, context: &mut HirContext, ) -> Result<(), (MacroError, FileId)> { - transform_hir(crate_id, context).map_err(|(err, file_id)| (err.into(), file_id)) + Ok(()) } } From ab5f219063cef80d01bce69660697df8b0bbc694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 20 Sep 2024 21:42:57 +0000 Subject: [PATCH 54/79] Fix docs --- docs/docs/aztec/concepts/storage/partial_notes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/aztec/concepts/storage/partial_notes.md b/docs/docs/aztec/concepts/storage/partial_notes.md index 7a72ef21814..1d21c0b227f 100644 --- a/docs/docs/aztec/concepts/storage/partial_notes.md +++ b/docs/docs/aztec/concepts/storage/partial_notes.md @@ -134,9 +134,9 @@ Then we just emit `P_a.x` and `P_b.x` as a note hashes, and we're done! [`NoteInterface.nr`](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/note/note_interface.nr) implements `compute_note_hiding_point`, which takes a note and computes the point "hides" it. -This is implemented in the example token contract: +This is implemented by applying the `partial_note` attribute: -#include_code compute_note_hiding_point noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr rust +#include_code TokenNote noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr rust Those `G_x` are generators that generated [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-projects/aztec-nr/aztec/src/generators.nr). Anyone can use them for separating different fields in a "partial note". From 64f5936acd594e9d187e97e907796b06d6942ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 20 Sep 2024 21:45:20 +0000 Subject: [PATCH 55/79] Make rs macros not do nothing but compile --- noir/noir-repo/aztec_macros/src/lib.rs | 4 ++-- noir/noir-repo/aztec_macros/src/utils/checks.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 01b0c7fc4b1..4ba8951c2f9 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -38,7 +38,7 @@ impl MacroProcessor for AztecMacro { file_id: FileId, context: &HirContext, ) -> Result { - Ok(ast) + transform(ast, crate_id, file_id, context) } fn process_typed_ast( @@ -46,7 +46,7 @@ impl MacroProcessor for AztecMacro { crate_id: &CrateId, context: &mut HirContext, ) -> Result<(), (MacroError, FileId)> { - Ok(()) + transform_hir(crate_id, context).map_err(|(err, file_id)| (err.into(), file_id)) } } diff --git a/noir/noir-repo/aztec_macros/src/utils/checks.rs b/noir/noir-repo/aztec_macros/src/utils/checks.rs index 5232f67ae87..826790159ea 100644 --- a/noir/noir-repo/aztec_macros/src/utils/checks.rs +++ b/noir/noir-repo/aztec_macros/src/utils/checks.rs @@ -18,5 +18,5 @@ pub fn check_for_aztec_dependency( } pub fn has_aztec_dependency(crate_id: &CrateId, context: &HirContext) -> bool { - context.crate_graph[crate_id].dependencies.iter().any(|dep| dep.as_name() == "aztec") + context.crate_graph[crate_id].dependencies.iter().any(|dep| dep.as_name() == "aztec-prevent-macro-injection") } From 5295b7e535bb60b3cf9de57c50a30ebccc648fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 20 Sep 2024 21:51:49 +0000 Subject: [PATCH 56/79] Fix rust linter --- noir/noir-repo/aztec_macros/src/utils/checks.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/noir/noir-repo/aztec_macros/src/utils/checks.rs b/noir/noir-repo/aztec_macros/src/utils/checks.rs index 826790159ea..c067ec570c8 100644 --- a/noir/noir-repo/aztec_macros/src/utils/checks.rs +++ b/noir/noir-repo/aztec_macros/src/utils/checks.rs @@ -18,5 +18,8 @@ pub fn check_for_aztec_dependency( } pub fn has_aztec_dependency(crate_id: &CrateId, context: &HirContext) -> bool { - context.crate_graph[crate_id].dependencies.iter().any(|dep| dep.as_name() == "aztec-prevent-macro-injection") + context.crate_graph[crate_id] + .dependencies + .iter() + .any(|dep| dep.as_name() == "aztec-prevent-macro-injection") } From b822c3057ff50f193d2d4eccaac11e3f960c746b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 20 Sep 2024 22:26:32 +0000 Subject: [PATCH 57/79] Add some notes to function macros --- .../aztec/src/macros/functions/interfaces.nr | 8 +- .../aztec/src/macros/functions/mod.nr | 126 ++++++++++++++---- 2 files changed, 105 insertions(+), 29 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr index 965e5f2456c..8ba74276920 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr @@ -56,9 +56,11 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { // } else { // quote { $fn_return_type } // }; + let fn_visibility = get_fn_visibility(f); let is_static_call = is_fn_view(f); let is_void = fn_return_type == type_of(()); + let fn_visibility_capitalized = if is_fn_private(f) { quote { Private } } else { @@ -70,11 +72,12 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { quote { } }; let is_void_capitalized = if is_void { quote { Void } } else { quote { } }; + let args_acc_name = quote { args_acc }; let args_acc = fn_parameters.fold( quote { - let mut $args_acc_name = &[]; - }, + let mut $args_acc_name = &[]; + }, |args_hasher, param: (Quoted, Type)| { let (name, typ) = param; let appended_arg = add_to_field_slice(args_acc_name, name, typ); @@ -179,6 +182,7 @@ pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { } } +/// Registers a function stub created via `stub_fn` as part of a module, pub(crate) comptime fn register_stub(m: Module, stub: Quoted) { let current_stubs = STUBS.get(m); let stubs_to_insert = if current_stubs.is_some() { diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index b2387ae4599..cc70c238f29 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -8,8 +8,22 @@ use super::utils::{ use interfaces::{create_fn_abi_export, register_stub, stub_fn}; -// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] -pub comptime fn internal(_f: FunctionDefinition) {} +// Functions can have multiple attributes applied to them, e.g. a single function can have #[public], #[view] and +// #[internal]. However. the order in which this will be evaluated is unknown, which makes combining them tricky. +// +// Our strategy is to have two mutually exclusive attributes, #[private] and #[public] (technically unconstrained is a +// hidden third kind), and make it so all functions must have one of them. These contain the code for all other +// attributes, but they only run it if the corresponding attribute has been applied to the function in question. +// +// For example, `#[private]` knows about `#[internal]` and what it should do, but it only does it if it sees that the +// private function in question also has the `internal` attribute applied. `#[internal]` itself does nothing - it is +// what we call a 'marker' attribute, that only exists for `#[private]` or `#[public]` to check if it's been applied. +// Therefore, the execution order of `#[internal]` and `#[private]` is irrelevant. + +/// Internal functions can only be called by the contract itself, typically from private into public. +pub comptime fn internal(_f: FunctionDefinition) { + // Marker attribute +} comptime fn create_internal_check(f: FunctionDefinition) -> Quoted { let name = f.name(); @@ -17,104 +31,141 @@ comptime fn create_internal_check(f: FunctionDefinition) -> Quoted { quote { assert(context.msg_sender() == context.this_address(), $assertion_message); } } -// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] -pub comptime fn view(_f: FunctionDefinition) {} +/// View functions can only be called in a static execution context. +pub comptime fn view(_f: FunctionDefinition) { + // Marker attribute +} comptime fn create_view_check(f: FunctionDefinition) -> Quoted { let name = f.name(); let assertion_message = f"Function {name} can only be called statically"; if is_fn_private(f) { + // Here `context` is of type context::PrivateContext quote { assert(context.inputs.call_context.is_static_call == true, $assertion_message); } } else { + // Here `context` is of type context::PublicContext quote { assert(context.inputs.is_static_call == true, $assertion_message); } } } -// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] -pub comptime fn initializer(_f: FunctionDefinition) {} +/// An initializer function is similar to a constructor: +/// - it can only be called once +/// - if there are multiple initializer functions, only one of them can be called +/// - no non-initializer functions can be called until an initializer has ben called (except `noinitcheck` functions) +pub comptime fn initializer(_f: FunctionDefinition) { + // Marker attribute +} -// Empty annotation just to leave a mark in the function that can be used to add the check in the correct place over at #[private] or #[public] -pub comptime fn noinitcheck(_f: FunctionDefinition) {} +/// Functions with noinitcheck can be called before contract initialization. +pub comptime fn noinitcheck(_f: FunctionDefinition) { + // Marker attribute +} -comptime fn create_assert_initializer(f: FunctionDefinition) -> Quoted { +comptime fn create_assert_correct_initializer_args(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); f"dep::aztec::initializer::assert_initialization_matches_address_preimage_{fn_visibility}(context);".quoted_contents() } -comptime fn create_init_check(f: FunctionDefinition) -> Quoted { +comptime fn create_mark_as_initialized(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); - f"dep::aztec::initializer::assert_is_initialized_{fn_visibility}(&mut context);".quoted_contents() + f"dep::aztec::initializer::mark_as_initialized_{fn_visibility}(&mut context);".quoted_contents() } -comptime fn create_mark_as_initialized(f: FunctionDefinition) -> Quoted { +comptime fn create_init_check(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); - f"dep::aztec::initializer::mark_as_initialized_{fn_visibility}(&mut context);".quoted_contents() + f"dep::aztec::initializer::assert_is_initialized_{fn_visibility}(&mut context);".quoted_contents() } +/// Private functions are executed client-side and preserve privacy. pub comptime fn private(f: FunctionDefinition) -> Quoted { let fn_abi = create_fn_abi_export(f); let fn_stub = stub_fn(f); register_stub(f.module(), fn_stub); + let module_has_initializer = module_has_initializer(f.module()); let module_has_storage = module_has_storage(f.module()); - let current_params = f.parameters(); + // Private functions undergo a lot of transformations from their Aztec.nr form into a circuit that can be fed to the + // Private Kernel Circuit. + + // First we change the function signature so that it also receives `PrivateContextInputs`, which contain information + // about the execution context (e.g. the caller). + let original_params = f.parameters(); f.set_parameters( &[ ( quote { inputs }, quote { crate::context::inputs::private_context_inputs::PrivateContextInputs }.as_type() ) - ].append(current_params) + ].append(original_params) ); + let mut body = f.body().as_block().unwrap(); + + // The original params are hashed and passed to the `context` object, so that the kernel can verify we're received + // the correct values. + // TODO: Optimize args_hasher for small number of arguments let args_hasher_name = quote { args_hasher }; - let args_hasher = current_params.fold( + let args_hasher = original_params.fold( quote { - let mut $args_hasher_name = dep::aztec::hash::ArgsHasher::new(); + let mut $args_hasher_name = dep::aztec::hash::ArgsHasher::new(); }, |args_hasher, param: (Quoted, Type)| { - let (name, typ) = param; - let appended_arg = add_to_hasher(args_hasher_name, name, typ); - quote { - $args_hasher - $appended_arg + let (name, typ) = param; + let appended_arg = add_to_hasher(args_hasher_name, name, typ); + quote { + $args_hasher + $appended_arg + } } - } ); + let context_creation = quote { let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hasher.hash()); }; + + // Modifications introduced by the different marker attributes. + let internal_check = if is_fn_internal(f) { create_internal_check(f) } else { quote {} }; + let view_check = if is_fn_view(f) { create_view_check(f) } else { quote {} }; + let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) { - (create_assert_initializer(f), create_mark_as_initialized(f)) + (create_assert_correct_initializer_args(f), create_mark_as_initialized(f)) } else { (quote {}, quote {}) }; + let storage_init = if module_has_storage { quote { let storage = Storage::init(&mut context); } } else { quote {} }; + + // Initialization checks are not included in contracts that don't have initializers. let init_check = if module_has_initializer & !fn_has_noinitcheck(f) { create_init_check(f) } else { quote {} }; + // Finally, we need to change the return type to be `PrivateCircuitPublicInputs`, which is what the Private Kernel + // circuit expects. + let return_value_var_name = quote { macro__returned__values }; let return_value_type = f.return_type(); let return_value = if body.len() == 0 { quote {} } else if return_value_type != type_of(()) { + // The original return value is passed to a second args hasher which the context receives. + let (body_without_return, last_body_expr) = body.pop_back(); let return_value = last_body_expr.quoted(); let return_value_assignment = quote { let $return_value_var_name: $return_value_type = $return_value; }; @@ -171,42 +222,60 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { fn_abi } +/// Public functions are executed sequencer-side and do not preserve privacy, similar to the EVM. pub comptime fn public(f: FunctionDefinition) -> Quoted { let fn_abi = create_fn_abi_export(f); let fn_stub = stub_fn(f); register_stub(f.module(), fn_stub); + let module_has_initializer = module_has_initializer(f.module()); let module_has_storage = module_has_storage(f.module()); - let current_params = f.parameters(); + // Public functions undergo a lot of transformations from their Aztec.nr form into a circuit that can be fed to the + // Public Kernel Circuit. + + // First we change the function signature so that it also receives `PublicContextInputs`, which contain information + // about the execution context (e.g. the caller). + + let original_params = f.parameters(); f.set_parameters( &[ ( quote { inputs }, quote { crate::context::inputs::public_context_inputs::PublicContextInputs }.as_type() ) - ].append(current_params) + ].append(original_params) ); + + // Unlike in the private case, in public the `context` does not need to receive the hash of the original params. let context_creation = quote { let mut context = dep::aztec::context::public_context::PublicContext::new(inputs); }; + + // Modifications introduced by the different marker attributes. + let internal_check = if is_fn_internal(f) { create_internal_check(f) } else { quote {} }; + let view_check = if is_fn_view(f) { create_view_check(f) } else { quote {} }; + let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) { - (create_assert_initializer(f), create_mark_as_initialized(f)) + (create_assert_correct_initializer_args(f), create_mark_as_initialized(f)) } else { (quote {}, quote {}) }; + let storage_init = if module_has_storage { quote { let storage = Storage::init(&mut context); } } else { quote {} }; + + // Initialization checks are not included in contracts that don't have initializers. let init_check = if module_has_initializer & !fn_has_noinitcheck(f) & !is_fn_initializer(f) { create_init_check(f) } else { @@ -230,6 +299,9 @@ pub comptime fn public(f: FunctionDefinition) -> Quoted { let modified_body = modify_fn_body(body, to_prepend, to_append); f.set_body(modified_body); + // All public functions are automatically made unconstrained, even if they were not marked as such. This is because + // instead of compiling into a circuit, they will compile to bytecode that will be later transpiled into AVM + // bytecode. f.set_unconstrained(true); f.set_return_public(true); From 6e9cd8a46adb17a39c86dc88ddb741570d61ea28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 20 Sep 2024 22:33:46 +0000 Subject: [PATCH 58/79] Restore nullifier --- noir-projects/aztec-nr/aztec/src/macros/mod.nr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index a74ef784da3..874ecbfc996 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -145,12 +145,12 @@ pub comptime fn aztec(m: Module) -> Quoted { transform_unconstrained(f); } - //let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); + let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); let note_exports = generate_note_exports(); quote { $note_exports $interface - //$compute_note_hash_and_optionally_a_nullifier + $compute_note_hash_and_optionally_a_nullifier } } From cad19e564ccf96ee8b2ca92c66c96a816ad52b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 20 Sep 2024 22:53:54 +0000 Subject: [PATCH 59/79] Minor comments on aztec macr --- .../aztec-nr/aztec/src/macros/mod.nr | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 874ecbfc996..8e00d07b632 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -11,7 +11,29 @@ use notes::{NOTES, generate_note_export}; use functions::transform_unconstrained; use utils::module_has_storage; -pub comptime fn generate_contract_interface(m: Module) -> Quoted { +/// Marks a contract as an Aztec contract, generating the interfaces for its functions and notes, as well as injecting +/// the `compute_note_hash_and_optionally_a_nullifier` function PXE requires in order to validate notes. +pub comptime fn aztec(m: Module) -> Quoted { + let interface = generate_contract_interface(m); + + let unconstrained_functions = m.functions().filter( + | f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute("test") & !f.has_named_attribute("public") + ); + for f in unconstrained_functions { + transform_unconstrained(f); + } + + let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); + let note_exports = generate_note_exports(); + + quote { + $note_exports + $interface + $compute_note_hash_and_optionally_a_nullifier + } +} + +comptime fn generate_contract_interface(m: Module) -> Quoted { let module_name = m.name(); let contract_stubs = STUBS.get(m); let fn_stubs_quote = if contract_stubs.is_some() { @@ -79,7 +101,7 @@ pub comptime fn generate_contract_interface(m: Module) -> Quoted { } } -pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { +comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { let mut max_note_length: u32 = 0; let notes = NOTES.entries(); let body = if notes.len() > 0 { @@ -126,7 +148,7 @@ pub comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quote } } -pub comptime fn generate_note_exports() -> Quoted { +comptime fn generate_note_exports() -> Quoted { let notes = NOTES.values(); notes.map( | (s, _, note_type_id): (StructDefinition, u32, Field) | { @@ -134,23 +156,3 @@ pub comptime fn generate_note_exports() -> Quoted { } ).join(quote {}) } - -pub comptime fn aztec(m: Module) -> Quoted { - let interface = generate_contract_interface(m); - - let unconstrained_functions = m.functions().filter( - | f: FunctionDefinition | f.is_unconstrained() & !f.has_named_attribute("test") & !f.has_named_attribute("public") - ); - for f in unconstrained_functions { - transform_unconstrained(f); - } - - let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); - let note_exports = generate_note_exports(); - - quote { - $note_exports - $interface - $compute_note_hash_and_optionally_a_nullifier - } -} From d4693bf569aa73a499e9a918dd32c389d93b9630 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 05:42:16 +0000 Subject: [PATCH 60/79] updated constants and boxes --- boxes/boxes/react/src/contracts/src/main.nr | 6 +++--- boxes/boxes/vanilla/src/contracts/src/main.nr | 4 ++-- l1-contracts/src/core/libraries/ConstantsGen.sol | 2 -- noir-projects/aztec-nr/aztec/src/macros/mod.nr | 2 +- .../crates/types/src/constants.nr | 10 +++++----- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/boxes/boxes/react/src/contracts/src/main.nr b/boxes/boxes/react/src/contracts/src/main.nr index fc0fa76ca55..6d5d4ecc830 100644 --- a/boxes/boxes/react/src/contracts/src/main.nr +++ b/boxes/boxes/react/src/contracts/src/main.nr @@ -8,11 +8,11 @@ contract BoxReact { encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys, macros::{storage::storage, functions::{private, public, initializer}} }; - use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; + use dep::value_note::value_note::ValueNote; #[storage] - struct Storage { - numbers: Map>, + struct Storage { + numbers: Map, Context>, } #[private] diff --git a/boxes/boxes/vanilla/src/contracts/src/main.nr b/boxes/boxes/vanilla/src/contracts/src/main.nr index 65a871dfaaf..f336c4ad841 100644 --- a/boxes/boxes/vanilla/src/contracts/src/main.nr +++ b/boxes/boxes/vanilla/src/contracts/src/main.nr @@ -11,8 +11,8 @@ contract Vanilla { use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; #[storage] - struct Storage { - numbers: Map>, + struct Storage { + numbers: Map, Context>, } #[private] diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 6b196086401..ac5c6043aa4 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -130,8 +130,6 @@ library Constants { uint256 internal constant L2_GAS_PER_LOG_BYTE = 4; uint256 internal constant L2_GAS_PER_NOTE_HASH = 32; uint256 internal constant L2_GAS_PER_NULLIFIER = 64; - uint256 internal constant CANONICAL_KEY_REGISTRY_ADDRESS = - 10536361358275073765062614648062211780027045486672640416335829595694222800789; uint256 internal constant CANONICAL_AUTH_REGISTRY_ADDRESS = 3193394520848240339042174260887368015244189807412437862264526499389876805968; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 8e00d07b632..a2c94ce007f 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -110,7 +110,7 @@ comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { }); let if_statements = notes.map( - | (typ, (note, _, _)): (Type, (StructDefinition, u32, Field)) | { + | (typ, (_, _, _)): (Type, (StructDefinition, u32, Field)) | { quote { if note_type_id == $typ::get_note_type_id() { aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::deserialize_content, note_header, compute_nullifier, serialized_note) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index d860af73422..3727e053bb5 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -188,11 +188,11 @@ global L2_GAS_PER_NOTE_HASH: u32 = 32; global L2_GAS_PER_NULLIFIER: u32 = 64; // CANONICAL CONTRACT ADDRESSES -global CANONICAL_AUTH_REGISTRY_ADDRESS = AztecAddress::from_field(0x2ace300b02ca5ab0a25052b1e852913a47292096997ca09f758c0e3624e84560); -global DEPLOYER_CONTRACT_ADDRESS = AztecAddress::from_field(0x25d93dc07b5baaf53a98caeae2679df3528cb83e11e2640a57a0a53abbaaadb9); -global REGISTERER_CONTRACT_ADDRESS = AztecAddress::from_field(0x1b6d5873cef5a35f681ab9468527f356c96e09b3c64603aef404ec2ad80aa3a9); -global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x1abe6c7f5c4caf04cbf7556495e08ad9c0a225a5f9d33554ae07285b13c494d7); -global ROUTER_ADDRESS = AztecAddress::from_field(0x1d8f25db3e8faa6a96cb1ecf57876a2ee04581deb3c4f181488ccd817abcbdb0); +global CANONICAL_AUTH_REGISTRY_ADDRESS = AztecAddress::from_field(0x070f65b1fba711fbd8512aefb6178eace06ad812bc52db99d8763e2b06f12150); +global DEPLOYER_CONTRACT_ADDRESS = AztecAddress::from_field(0x0662b180a46cdc8f5deedd4baa002e12be5c4f8d8c3412a2f97f080a26e7fe64); +global REGISTERER_CONTRACT_ADDRESS = AztecAddress::from_field(0x30153a54396e050f4d947d3ffcb3492635ef71f079e9a09a427e4a3ac3a607bb); +global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x138c47f7a69363d2bd2c76ccf08526613aa32958b0a504cfc5f5aab7fe2969b0); +global ROUTER_ADDRESS = AztecAddress::from_field(0x02195a9adfbd7cac0ef961ac18835f10b5d049753cd4e7cbf50059c2e8caf835); // LENGTH OF STRUCTS SERIALIZED TO FIELDS global AZTEC_ADDRESS_LENGTH: u32 = 1; From 976c6d4b1b1615419e9a79b2732ca0f057ac510c Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 06:12:59 +0000 Subject: [PATCH 61/79] comment --- .../aztec-nr/aztec/src/macros/functions/interfaces.nr | 8 -------- 1 file changed, 8 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr index 8ba74276920..1f39f05c4fb 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/interfaces.nr @@ -47,15 +47,7 @@ pub(crate) comptime fn create_fn_abi_export(f: FunctionDefinition) -> Quoted { pub comptime fn stub_fn(f: FunctionDefinition) -> Quoted { let fn_name = f.name(); let fn_parameters = f.parameters(); - // Fixes [ typ ; ( len : numeric Field ) ] error let fn_return_type = f.return_type(); - // let fn_return_type_quoted = if fn_return_type.as_array().is_some() { - // let (element_type, array_len) = fn_return_type.as_array().unwrap(); - // let array_len = array_len.as_constant().unwrap(); - // quote { [$element_type; $array_len] } - // } else { - // quote { $fn_return_type } - // }; let fn_visibility = get_fn_visibility(f); let is_static_call = is_fn_view(f); From 173356b33fbfd993a1017464615daa97bff9eb24 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 07:28:46 +0000 Subject: [PATCH 62/79] remake constants again --- l1-contracts/src/core/libraries/ConstantsGen.sol | 10 +++++----- .../crates/types/src/constants.nr | 10 +++++----- yarn-project/circuits.js/src/constants.gen.ts | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index ac5c6043aa4..de90972406b 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -131,15 +131,15 @@ library Constants { uint256 internal constant L2_GAS_PER_NOTE_HASH = 32; uint256 internal constant L2_GAS_PER_NULLIFIER = 64; uint256 internal constant CANONICAL_AUTH_REGISTRY_ADDRESS = - 3193394520848240339042174260887368015244189807412437862264526499389876805968; + 19361441716519463065948254497947932755739298943049449145365332870925554042208; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = - 2888253181140434202600946137610803790678961451820394869801342223909105696356; + 17119407406465801909352274670277571579675739451008438338071219340964365249977; uint256 internal constant REGISTERER_CONTRACT_ADDRESS = - 21748523092328826737377319989875487952297567340504996985769574672917248477115; + 12405643717676802437578418009978929188439257864607100766293128479227092050857; uint256 internal constant FEE_JUICE_ADDRESS = - 8841799412790957220630076556157089925484823620333112594242679125846566463920; + 12096583827711775893711303288210371301779120762215263550909768879597884314839; uint256 internal constant ROUTER_ADDRESS = - 949422206351581749693459491613246405703946584592224897261267487800745982005; + 13369993014609648298719593339393818582619449364029983937306132176549332172208; uint256 internal constant AZTEC_ADDRESS_LENGTH = 1; uint256 internal constant GAS_FEES_LENGTH = 2; uint256 internal constant GAS_LENGTH = 2; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 3727e053bb5..d860af73422 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -188,11 +188,11 @@ global L2_GAS_PER_NOTE_HASH: u32 = 32; global L2_GAS_PER_NULLIFIER: u32 = 64; // CANONICAL CONTRACT ADDRESSES -global CANONICAL_AUTH_REGISTRY_ADDRESS = AztecAddress::from_field(0x070f65b1fba711fbd8512aefb6178eace06ad812bc52db99d8763e2b06f12150); -global DEPLOYER_CONTRACT_ADDRESS = AztecAddress::from_field(0x0662b180a46cdc8f5deedd4baa002e12be5c4f8d8c3412a2f97f080a26e7fe64); -global REGISTERER_CONTRACT_ADDRESS = AztecAddress::from_field(0x30153a54396e050f4d947d3ffcb3492635ef71f079e9a09a427e4a3ac3a607bb); -global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x138c47f7a69363d2bd2c76ccf08526613aa32958b0a504cfc5f5aab7fe2969b0); -global ROUTER_ADDRESS = AztecAddress::from_field(0x02195a9adfbd7cac0ef961ac18835f10b5d049753cd4e7cbf50059c2e8caf835); +global CANONICAL_AUTH_REGISTRY_ADDRESS = AztecAddress::from_field(0x2ace300b02ca5ab0a25052b1e852913a47292096997ca09f758c0e3624e84560); +global DEPLOYER_CONTRACT_ADDRESS = AztecAddress::from_field(0x25d93dc07b5baaf53a98caeae2679df3528cb83e11e2640a57a0a53abbaaadb9); +global REGISTERER_CONTRACT_ADDRESS = AztecAddress::from_field(0x1b6d5873cef5a35f681ab9468527f356c96e09b3c64603aef404ec2ad80aa3a9); +global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x1abe6c7f5c4caf04cbf7556495e08ad9c0a225a5f9d33554ae07285b13c494d7); +global ROUTER_ADDRESS = AztecAddress::from_field(0x1d8f25db3e8faa6a96cb1ecf57876a2ee04581deb3c4f181488ccd817abcbdb0); // LENGTH OF STRUCTS SERIALIZED TO FIELDS global AZTEC_ADDRESS_LENGTH: u32 = 1; diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 7da70903e3d..112ed245543 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -116,12 +116,12 @@ export const L2_GAS_PER_LOG_BYTE = 4; export const L2_GAS_PER_NOTE_HASH = 32; export const L2_GAS_PER_NULLIFIER = 64; export const CANONICAL_AUTH_REGISTRY_ADDRESS = - 3193394520848240339042174260887368015244189807412437862264526499389876805968n; -export const DEPLOYER_CONTRACT_ADDRESS = 2888253181140434202600946137610803790678961451820394869801342223909105696356n; + 19361441716519463065948254497947932755739298943049449145365332870925554042208n; +export const DEPLOYER_CONTRACT_ADDRESS = 17119407406465801909352274670277571579675739451008438338071219340964365249977n; export const REGISTERER_CONTRACT_ADDRESS = - 21748523092328826737377319989875487952297567340504996985769574672917248477115n; -export const FEE_JUICE_ADDRESS = 8841799412790957220630076556157089925484823620333112594242679125846566463920n; -export const ROUTER_ADDRESS = 949422206351581749693459491613246405703946584592224897261267487800745982005n; + 12405643717676802437578418009978929188439257864607100766293128479227092050857n; +export const FEE_JUICE_ADDRESS = 12096583827711775893711303288210371301779120762215263550909768879597884314839n; +export const ROUTER_ADDRESS = 13369993014609648298719593339393818582619449364029983937306132176549332172208n; export const AZTEC_ADDRESS_LENGTH = 1; export const GAS_FEES_LENGTH = 2; export const GAS_LENGTH = 2; From 4b16d8a73375eaf71f425278855bf1f7b9cea981 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 08:01:41 +0000 Subject: [PATCH 63/79] added missing condition to init check --- noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index cc70c238f29..6ef4ac1ca2f 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -149,7 +149,7 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { }; // Initialization checks are not included in contracts that don't have initializers. - let init_check = if module_has_initializer & !fn_has_noinitcheck(f) { + let init_check = if module_has_initializer & !is_fn_initializer(f) & !fn_has_noinitcheck(f) { create_init_check(f) } else { quote {} From 60597037efa7a5ec45de90136d6afb5394e57594 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 08:46:13 +0000 Subject: [PATCH 64/79] fixed note type computation --- .../aztec-nr/aztec/src/macros/notes/mod.nr | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index b6f3ae916ff..8b421793b82 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -1,11 +1,9 @@ use std::{ - meta::{type_of, unquote}, collections::umap::UHashMap, + meta::{type_of, unquote, typ::fresh_type_variable}, collections::umap::UHashMap, hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} }; -use protocol_types::{meta::flatten_to_fields, utils::field::field_from_bytes}; +use protocol_types::{meta::{flatten_to_fields, pack_from_fields}, utils::field::field_from_bytes}; use crate::note::{note_header::NoteHeader, note_getter_options::PropertySelector, note_interface::NoteInterface}; -use protocol_types::meta::pack_from_fields; -use std::meta::typ::fresh_type_variable; comptime global NOTE_HEADER_TYPE = type_of(NoteHeader::empty()); @@ -14,19 +12,14 @@ comptime mut global NOTES: UHashMap Field { let name_as_str_quote = name.as_str_quote(); - let hash: [u8; 32] = unquote!( + unquote!( quote { let bytes = $name_as_str_quote.as_bytes(); - std::hash::keccak256(bytes, bytes.len() as u32) + let hash = protocol_types::hash::poseidon2_hash_bytes(bytes); + let hash_bytes = hash.to_be_bytes::<4>(); + field_from_bytes(hash_bytes, true) } - ); - - let mut selector_be_bytes = [0; 4]; - for i in 0..4 { - selector_be_bytes[i] = hash[i]; - } - - field_from_bytes(selector_be_bytes, true) + ) } comptime fn generate_note_interface( From c4b15ceb87697e65bf74ebc611793afd437d79b4 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 08:50:36 +0000 Subject: [PATCH 65/79] unused imports --- noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 8b421793b82..6c2569115dd 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -2,7 +2,7 @@ use std::{ meta::{type_of, unquote, typ::fresh_type_variable}, collections::umap::UHashMap, hash::{BuildHasherDefault, poseidon2::Poseidon2Hasher} }; -use protocol_types::{meta::{flatten_to_fields, pack_from_fields}, utils::field::field_from_bytes}; +use protocol_types::meta::{flatten_to_fields, pack_from_fields}; use crate::note::{note_header::NoteHeader, note_getter_options::PropertySelector, note_interface::NoteInterface}; comptime global NOTE_HEADER_TYPE = type_of(NoteHeader::empty()); @@ -17,7 +17,7 @@ comptime fn compute_note_type_id(name: Quoted) -> Field { let bytes = $name_as_str_quote.as_bytes(); let hash = protocol_types::hash::poseidon2_hash_bytes(bytes); let hash_bytes = hash.to_be_bytes::<4>(); - field_from_bytes(hash_bytes, true) + protocol_types::utils::field::field_from_bytes(hash_bytes, true) } ) } From 8d68266938c7000a4a82b1d4efb7c2564e4d965f Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 11:01:20 +0000 Subject: [PATCH 66/79] correctly generate compute_note_hash_and_nullifier --- .../aztec-nr/aztec/src/macros/mod.nr | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index a2c94ce007f..7bf9e19ed35 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -109,15 +109,23 @@ comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { acc + len }); - let if_statements = notes.map( - | (typ, (_, _, _)): (Type, (StructDefinition, u32, Field)) | { - quote { - if note_type_id == $typ::get_note_type_id() { - aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::deserialize_content, note_header, compute_nullifier, serialized_note) - } + let mut if_statements_list = &[]; + + for i in 0..notes.len() { + let (typ, (_, _, _)) = notes[i]; + let if_or_else_if = if i == 0 { + quote { if } + } else { + quote { else if } + }; + if_statements_list = if_statements_list.push_back(quote { + $if_or_else_if note_type_id == $typ::get_note_type_id() { + aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::deserialize_content, note_header, compute_nullifier, serialized_note) } + }); } - ).join(quote{}); + + let if_statements = if_statements_list.join(quote {}); quote { let note_header = aztec::prelude::NoteHeader::new(contract_address, nonce, storage_slot); From ec5a41db0b6d2aecae1c0fc5c1f61bf9b88c2877 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 14:46:14 +0000 Subject: [PATCH 67/79] e2e fixes --- .../aztec-nr/value-note/src/value_note.nr | 4 +- .../crowdfunding_contract/src/main.nr | 6 +- .../aztec.js/src/contract/batch_call.ts | 4 +- .../aztec.js/src/contract/contract.test.ts | 4 +- .../contract/contract_function_interaction.ts | 4 +- yarn-project/aztec.js/src/index.ts | 2 +- .../src/contract-interface-gen/typescript.ts | 70 ++++++++++--------- .../circuit-types/src/interfaces/pxe.ts | 9 ++- .../end-to-end/src/e2e_event_logs.test.ts | 10 +-- yarn-project/foundation/src/abi/decoder.ts | 51 +++++++------- .../pxe/src/pxe_service/pxe_service.ts | 24 ++----- .../simulator/src/client/simulator.test.ts | 4 +- .../src/client/unconstrained_execution.ts | 11 +-- 13 files changed, 100 insertions(+), 103 deletions(-) diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 7a6911994bd..62c5b7875d0 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -8,8 +8,10 @@ use dep::aztec::{ global VALUE_NOTE_LEN: u32 = 3; // 3 plus a header. // docs:start:value-note-def -#[derive(Serialize)] +// ValueNote is used as fn parameter in the Claim contract, so it has to implement the Serialize trait. +// It is important that the order of these annotations is preserved so that derive(Serialize) runs AFTER the note macro, which injects the note header. #[note] +#[derive(Serialize)] pub struct ValueNote { value: Field, // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index 1d68a991b96..bd34f60917d 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -24,8 +24,8 @@ contract Crowdfunding { #[event] #[derive(Serialize)] struct WithdrawalProcessed { - who: Field, - amount: Field, + who: AztecAddress, + amount: u64, } // docs:start:storage @@ -102,6 +102,6 @@ contract Crowdfunding { #[public] #[internal] fn _publish_donation_receipts(amount: u64, to: AztecAddress) { - WithdrawalProcessed { amount: amount as Field, who: to.to_field() }.emit(encode_event(&mut context)); + WithdrawalProcessed { amount, who: to }.emit(encode_event(&mut context)); } } diff --git a/yarn-project/aztec.js/src/contract/batch_call.ts b/yarn-project/aztec.js/src/contract/batch_call.ts index 19fb03999f6..eeda122ec52 100644 --- a/yarn-project/aztec.js/src/contract/batch_call.ts +++ b/yarn-project/aztec.js/src/contract/batch_call.ts @@ -1,5 +1,5 @@ import { type FunctionCall, type TxExecutionRequest } from '@aztec/circuit-types'; -import { FunctionType, decodeReturnValues } from '@aztec/foundation/abi'; +import { FunctionType, decodeFromAbi } from '@aztec/foundation/abi'; import { type Wallet } from '../account/index.js'; import { BaseContractInteraction, type SendMethodOptions } from './base_contract_interaction.js'; @@ -95,7 +95,7 @@ export class BatchCall extends BaseContractInteraction { ? simulatedTx.privateReturnValues?.nested?.[resultIndex].values : simulatedTx.publicOutput?.publicReturnValues?.[resultIndex].values; - results[callIndex] = rawReturnValues ? decodeReturnValues(call.returnTypes, rawReturnValues) : []; + results[callIndex] = rawReturnValues ? decodeFromAbi(call.returnTypes, rawReturnValues) : []; }); return results; } diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index ec677ed6ecd..57b54e210d8 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -1,7 +1,7 @@ import { type Tx, type TxExecutionRequest, type TxHash, type TxReceipt } from '@aztec/circuit-types'; import { AztecAddress, CompleteAddress, EthAddress } from '@aztec/circuits.js'; import { type L1ContractAddresses } from '@aztec/ethereum'; -import { type ContractArtifact, type DecodedReturn, FunctionType } from '@aztec/foundation/abi'; +import { type AbiDecoded, type ContractArtifact, FunctionType } from '@aztec/foundation/abi'; import { type NodeInfo } from '@aztec/types/interfaces'; import { type MockProxy, mock } from 'jest-mock-extended'; @@ -127,7 +127,7 @@ describe('Contract Class', () => { wallet.createTxExecutionRequest.mockResolvedValue(mockTxRequest); wallet.getContractInstance.mockResolvedValue(contractInstance); wallet.sendTx.mockResolvedValue(mockTxHash); - wallet.simulateUnconstrained.mockResolvedValue(mockUnconstrainedResultValue as any as DecodedReturn); + wallet.simulateUnconstrained.mockResolvedValue(mockUnconstrainedResultValue as any as AbiDecoded); wallet.getTxReceipt.mockResolvedValue(mockTxReceipt); wallet.getNodeInfo.mockResolvedValue(mockNodeInfo); wallet.proveTx.mockResolvedValue(mockTx); diff --git a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts index ca9daf825e5..8cf48a01389 100644 --- a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts +++ b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts @@ -4,7 +4,7 @@ import { type FunctionAbi, FunctionSelector, FunctionType, - decodeReturnValues, + decodeFromAbi, encodeArguments, } from '@aztec/foundation/abi'; @@ -110,6 +110,6 @@ export class ContractFunctionInteraction extends BaseContractInteraction { ? simulatedTx.privateReturnValues?.nested?.[0].values : simulatedTx.publicOutput?.publicReturnValues?.[0].values; - return rawReturnValues ? decodeReturnValues(this.functionDao.returnTypes, rawReturnValues) : []; + return rawReturnValues ? decodeFromAbi(this.functionDao.returnTypes, rawReturnValues) : []; } } diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 3c012b20f28..dba2233180c 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -144,7 +144,7 @@ export { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/c // TODO: These kinds of things have no place on our public api. // External devs will almost certainly have their own methods of doing these things. // If we want to use them in our own "aztec.js consuming code", import them from foundation as needed. -export { encodeArguments } from '@aztec/foundation/abi'; +export { encodeArguments, decodeFromAbi, type AbiType } from '@aztec/foundation/abi'; export { toBigIntBE } from '@aztec/foundation/bigint-buffer'; export { sha256 } from '@aztec/foundation/crypto'; export { makeFetch } from '@aztec/foundation/json-rpc/client'; diff --git a/yarn-project/builder/src/contract-interface-gen/typescript.ts b/yarn-project/builder/src/contract-interface-gen/typescript.ts index 056ef1154b3..a703990bc61 100644 --- a/yarn-project/builder/src/contract-interface-gen/typescript.ts +++ b/yarn-project/builder/src/contract-interface-gen/typescript.ts @@ -1,7 +1,9 @@ import { type ABIParameter, + type ABIVariable, type ContractArtifact, type FunctionArtifact, + decodeFunctionSignature, getDefaultInitializer, isAztecAddressStruct, isEthAddressStruct, @@ -247,7 +249,7 @@ function generateEvents(events: any[] | undefined) { const eventsMetadata = events.map(event => { const eventName = event.path.split('::').at(-1); - const eventDefProps = event.fields.map((field: any) => `${field.name}: Fr`); + const eventDefProps = event.fields.map((field: ABIVariable) => `${field.name}: ${abiTypeToTypescript(field.type)}`); const eventDef = ` export type ${eventName} = { ${eventDefProps.join('\n')} @@ -255,14 +257,14 @@ function generateEvents(events: any[] | undefined) { `; const fieldNames = event.fields.map((field: any) => `"${field.name}"`); - const eventType = `${eventName}: {decode: (payload: L1EventPayload | undefined) => ${eventName} | undefined, eventSelector: EventSelector, fieldNames: string[] }`; - + const eventType = `${eventName}: {decode: (payload: L1EventPayload | UnencryptedL2Log | undefined) => ${eventName} | undefined, eventSelector: EventSelector, fieldNames: string[] }`; + // Reusing the decodeFunctionSignature + const eventSignature = decodeFunctionSignature(eventName, event.fields); + const eventSelector = `EventSelector.fromSignature('${eventSignature}')`; const eventImpl = `${eventName}: { - decode: this.decodeEvent(${event.fields.length}, EventSelector.fromSignature('${eventName}(${event.fields - .map(() => 'Field') - .join(',')})'), [${fieldNames}]), - eventSelector: EventSelector.fromSignature('${eventName}(${event.fields.map(() => 'Field').join(',')})'), - fieldNames: [${fieldNames}], + decode: this.decodeEvent(${eventSelector}, ${JSON.stringify(event, null, 4)}), + eventSelector: ${eventSelector}, + fieldNames: [${fieldNames}], }`; return { @@ -276,31 +278,32 @@ function generateEvents(events: any[] | undefined) { eventDefs: eventsMetadata.map(({ eventDef }) => eventDef).join('\n'), events: ` // Partial application is chosen is to avoid the duplication of so much codegen. - private static decodeEvent(fieldsLength: number, eventSelector: EventSelector, fields: string[]): (payload: L1EventPayload | undefined) => T | undefined { - return (payload: L1EventPayload | undefined): T | undefined => { - if (payload === undefined) { - return undefined; - } - if (!eventSelector.equals(payload.eventTypeId)) { - return undefined; - } - if (payload.event.items.length !== fieldsLength) { - throw new Error( - 'Something is weird here, we have matching EventSelectors, but the actual payload has mismatched length', - ); - } - - return fields.reduce( - (acc, curr, i) => ({ - ...acc, - [curr]: payload.event.items[i], - }), - {} as T, - ); - }; - } + private static decodeEvent( + eventSelector: EventSelector, + eventType: AbiType, + ): (payload: L1EventPayload | UnencryptedL2Log | undefined) => T | undefined { + return (payload: L1EventPayload | UnencryptedL2Log | undefined): T | undefined => { + if (payload === undefined) { + return undefined; + } + + if (payload instanceof L1EventPayload) { + if (!eventSelector.equals(payload.eventTypeId)) { + return undefined; + } + return decodeFromAbi([eventType], payload.event.items) as T; + } else { + let items = []; + for (let i = 0; i < payload.data.length; i += 32) { + items.push(new Fr(payload.data.subarray(i, i + 32))); + } + + return decodeFromAbi([eventType], items) as T; + } + }; + } - public static get events(): { ${eventsMetadata.map(({ eventType }) => eventType).join(', ')} } { + public static get events(): { ${eventsMetadata.map(({ eventType }) => eventType).join(', ')} } { return { ${eventsMetadata.map(({ eventImpl }) => eventImpl).join(',\n')} }; @@ -334,6 +337,7 @@ export function generateTypescriptContractInterface(input: ContractArtifact, art /* eslint-disable */ import { + type AbiType, AztecAddress, type AztecAddressLike, CompleteAddress, @@ -345,6 +349,7 @@ import { type ContractMethod, type ContractStorageLayout, type ContractNotes, + decodeFromAbi, DeployMethod, EthAddress, type EthAddressLike, @@ -358,6 +363,7 @@ import { NoteSelector, Point, type PublicKey, + type UnencryptedL2Log, type Wallet, type WrappedFieldLike, } from '@aztec/aztec.js'; diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index c494114350a..fc5a347f158 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -16,7 +16,12 @@ import { type NodeInfo } from '@aztec/types/interfaces'; import { type AuthWitness } from '../auth_witness.js'; import { type L2Block } from '../l2_block.js'; -import { type GetUnencryptedLogsResponse, type L1EventPayload, type LogFilter } from '../logs/index.js'; +import { + type GetUnencryptedLogsResponse, + type L1EventPayload, + type LogFilter, + type UnencryptedL2Log, +} from '../logs/index.js'; import { type IncomingNotesFilter } from '../notes/incoming_notes_filter.js'; import { type ExtendedNote, type OutgoingNotesFilter, type UniqueNote } from '../notes/index.js'; import { type SiblingPath } from '../sibling_path/sibling_path.js'; @@ -427,7 +432,7 @@ export interface PXE { * The shape of the event generated on the Contract. */ export interface EventMetadata { - decode(payload: L1EventPayload): T | undefined; + decode(payload: L1EventPayload | UnencryptedL2Log): T | undefined; eventSelector: EventSelector; fieldNames: string[]; } diff --git a/yarn-project/end-to-end/src/e2e_event_logs.test.ts b/yarn-project/end-to-end/src/e2e_event_logs.test.ts index 416f2af3ce2..93c56aa703f 100644 --- a/yarn-project/end-to-end/src/e2e_event_logs.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_logs.test.ts @@ -65,7 +65,7 @@ describe('Logs', () => { expect(decryptedLog0?.payload.contractAddress).toStrictEqual(testLogContract.address); expect(decryptedLog0?.payload.randomness).toStrictEqual(randomness[0]); expect(decryptedLog0?.payload.eventTypeId).toStrictEqual( - EventSelector.fromField(new Fr(0x00000000000000000000000000000000000000000000000000000000d45c041b)), + EventSelector.fromSignature('ExampleEvent0(Field,Field)'), ); // We decode our event into the event type @@ -89,7 +89,7 @@ describe('Logs', () => { expect(decryptedLog1?.payload.contractAddress).toStrictEqual(testLogContract.address); expect(decryptedLog1?.payload.randomness).toStrictEqual(randomness[1]); expect(decryptedLog1?.payload.eventTypeId).toStrictEqual( - EventSelector.fromField(new Fr(0x00000000000000000000000000000000000000000000000000000000031b1167)), + EventSelector.fromSignature('ExampleEvent1((Field),u8)'), ); // We check our second event, which is a different type @@ -98,7 +98,7 @@ describe('Logs', () => { // We expect the fields to have been populated correctly expect(event1?.value2).toStrictEqual(preimage[2]); // We get the last byte here because value3 is of type u8 - expect(event1?.value3).toStrictEqual(new Fr(preimage[3].toBuffer().subarray(31))); + expect(event1?.value3).toStrictEqual(BigInt(preimage[3].toBuffer().subarray(31).readUint8())); // Again, trying to decode another event with mismatching data does not yield anything const badEvent1 = TestLogContract.events.ExampleEvent0.decode(decryptedLog1!.payload); @@ -194,7 +194,7 @@ describe('Logs', () => { .map(preimage => ({ value2: preimage[2], // We get the last byte here because value3 is of type u8 - value3: new Fr(preimage[3].toBuffer().subarray(31)), + value3: BigInt(preimage[3].toBuffer().subarray(31).readUint8()), })) .sort(exampleEvent1Sort), ); @@ -238,7 +238,7 @@ describe('Logs', () => { .map(preimage => ({ value2: preimage[2], // We get the last byte here because value3 is of type u8 - value3: new Fr(preimage[3].toBuffer().subarray(31)), + value3: BigInt(preimage[3].toBuffer().subarray(31).readUint8()), })) .sort(exampleEvent1Sort), ); diff --git a/yarn-project/foundation/src/abi/decoder.ts b/yarn-project/foundation/src/abi/decoder.ts index 1749e357fc6..5828f12cf31 100644 --- a/yarn-project/foundation/src/abi/decoder.ts +++ b/yarn-project/foundation/src/abi/decoder.ts @@ -6,24 +6,24 @@ import { isAztecAddressStruct } from './utils.js'; /** * The type of our decoded ABI. */ -export type DecodedReturn = bigint | boolean | AztecAddress | DecodedReturn[] | { [key: string]: DecodedReturn }; +export type AbiDecoded = bigint | boolean | AztecAddress | AbiDecoded[] | { [key: string]: AbiDecoded }; /** - * Decodes return values from a function call. - * Missing support for integer and string. + * Decodes values using a provided ABI. + * Missing support for signed integer. */ -class ReturnValuesDecoder { - constructor(private returnTypes: AbiType[], private flattened: Fr[]) {} +class AbiDecoder { + constructor(private types: AbiType[], private flattened: Fr[]) {} /** * Decodes a single return value from field to the given type. * @param abiType - The type of the return value. * @returns The decoded return value. */ - private decodeReturn(abiType: AbiType): DecodedReturn { + private decodeNext(abiType: AbiType): AbiDecoded { switch (abiType.kind) { case 'field': - return this.getNextField().toBigInt(); + return this.getNextField(); case 'integer': if (abiType.sign === 'signed') { throw new Error('Unsupported type: signed integer'); @@ -34,18 +34,18 @@ class ReturnValuesDecoder { case 'array': { const array = []; for (let i = 0; i < abiType.length; i += 1) { - array.push(this.decodeReturn(abiType.type)); + array.push(this.decodeNext(abiType.type)); } return array; } case 'struct': { - const struct: { [key: string]: DecodedReturn } = {}; + const struct: { [key: string]: AbiDecoded } = {}; if (isAztecAddressStruct(abiType)) { return new AztecAddress(this.getNextField().toBuffer()); } for (const field of abiType.fields) { - struct[field.name] = this.decodeReturn(field.type); + struct[field.name] = this.decodeNext(field.type); } return struct; } @@ -59,7 +59,7 @@ class ReturnValuesDecoder { case 'tuple': { const array = []; for (const tupleAbiType of abiType.fields) { - array.push(this.decodeReturn(tupleAbiType)); + array.push(this.decodeNext(tupleAbiType)); } return array; } @@ -69,8 +69,8 @@ class ReturnValuesDecoder { } /** - * Gets the next field in the flattened return values. - * @returns The next field in the flattened return values. + * Gets the next field in the flattened buffer. + * @returns The next field in the flattened buffer. */ private getNextField(): Fr { const field = this.flattened.shift(); @@ -81,30 +81,29 @@ class ReturnValuesDecoder { } /** - * Decodes all the return values for the given function ABI. - * Aztec.nr support only single return value - * The return value can however be simple types, structs or arrays + * Decodes all the values for the given ABI. + * The decided value can be simple types, structs or arrays * @returns The decoded return values. */ - public decode(): DecodedReturn { - if (this.returnTypes.length > 1) { - throw new Error('Multiple return values not supported'); + public decode(): AbiDecoded { + if (this.types.length > 1) { + throw new Error('Multiple types not supported'); } - if (this.returnTypes.length === 0) { + if (this.types.length === 0) { return []; } - return this.decodeReturn(this.returnTypes[0]); + return this.decodeNext(this.types[0]); } } /** - * Decodes return values from a function call. - * @param abi - The ABI entry of the function. - * @param returnValues - The decoded return values. + * Decodes values in a flattened Field array using a provided ABI. + * @param abi - The ABI to use as reference. + * @param buffer - The flattened Field array to decode. * @returns */ -export function decodeReturnValues(returnTypes: AbiType[], returnValues: Fr[]) { - return new ReturnValuesDecoder(returnTypes, returnValues.slice()).decode(); +export function decodeFromAbi(typ: AbiType[], buffer: Fr[]) { + return new AbiDecoder(typ, buffer.slice()).decode(); } /** diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 2d7c0cbde1f..b1cfcd20283 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -42,8 +42,8 @@ import { } from '@aztec/circuits.js'; import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash'; import { + type AbiDecoded, type ContractArtifact, - type DecodedReturn, EventSelector, FunctionSelector, encodeArguments, @@ -567,7 +567,7 @@ export class PXEService implements PXE { to: AztecAddress, _from?: AztecAddress, scopes?: AztecAddress[], - ): Promise { + ): Promise { // all simulations must be serialized w.r.t. the synchronizer return await this.jobQueue.put(async () => { // TODO - Should check if `from` has the permission to call the view function. @@ -964,17 +964,11 @@ export class PXEService implements PXE { } if (visibleEvent.payload.event.items.length !== eventMetadata.fieldNames.length) { throw new Error( - 'Something is weird here, we have matching FunctionSelectors, but the actual payload has mismatched length', + 'Something is weird here, we have matching EventSelectors, but the actual payload has mismatched length', ); } - return eventMetadata.fieldNames.reduce( - (acc, curr, i) => ({ - ...acc, - [curr]: visibleEvent.payload.event.items[i], - }), - {} as T, - ); + return eventMetadata.decode(visibleEvent.payload); }) .filter(visibleEvent => visibleEvent !== undefined) as T[]; @@ -1001,17 +995,11 @@ export class PXEService implements PXE { if (unencryptedLogBuf.byteLength !== eventMetadata.fieldNames.length * 32 + 32) { throw new Error( - 'Something is weird here, we have matching FunctionSelectors, but the actual payload has mismatched length', + 'Something is weird here, we have matching EventSelectors, but the actual payload has mismatched length', ); } - return eventMetadata.fieldNames.reduce( - (acc, curr, i) => ({ - ...acc, - [curr]: new Fr(unencryptedLogBuf.subarray(i * 32, i * 32 + 32)), - }), - {} as T, - ); + return eventMetadata.decode(unencryptedLog.log); }) .filter(unencryptedLog => unencryptedLog !== undefined) as T[]; diff --git a/yarn-project/simulator/src/client/simulator.test.ts b/yarn-project/simulator/src/client/simulator.test.ts index 601cb2aa6e6..1e4cbe6d876 100644 --- a/yarn-project/simulator/src/client/simulator.test.ts +++ b/yarn-project/simulator/src/client/simulator.test.ts @@ -55,7 +55,9 @@ describe('Simulator', () => { const storageSlot = TokenBlacklistContractArtifact.storageLayout['balances'].slot; const noteTypeId = TokenBlacklistContractArtifact.notes['TokenNote'].id; - const createNote = (amount = 123n) => new Note([new Fr(amount), ownerMasterNullifierPublicKey.hash(), Fr.random()]); + // Amount is a U128, with a lo and hi limbs + const createNote = (amount = 123n) => + new Note([new Fr(amount), new Fr(0), ownerMasterNullifierPublicKey.hash(), Fr.random()]); it('should compute note hashes and nullifier', async () => { oracle.getFunctionArtifactByName.mockResolvedValue(artifact); diff --git a/yarn-project/simulator/src/client/unconstrained_execution.ts b/yarn-project/simulator/src/client/unconstrained_execution.ts index 1a7b957f799..7fc622c6987 100644 --- a/yarn-project/simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/simulator/src/client/unconstrained_execution.ts @@ -1,9 +1,4 @@ -import { - type DecodedReturn, - type FunctionArtifact, - type FunctionSelector, - decodeReturnValues, -} from '@aztec/foundation/abi'; +import { type AbiDecoded, type FunctionArtifact, type FunctionSelector, decodeFromAbi } from '@aztec/foundation/abi'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { type Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -24,7 +19,7 @@ export async function executeUnconstrainedFunction( functionSelector: FunctionSelector, args: Fr[], log = createDebugLogger('aztec:simulator:unconstrained_execution'), -): Promise { +): Promise { log.verbose(`Executing unconstrained function ${contractAddress}:${functionSelector}(${artifact.name})`); const acir = artifact.bytecode; @@ -42,6 +37,6 @@ export async function executeUnconstrainedFunction( }); const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness); - return decodeReturnValues(artifact.returnTypes, returnWitness); + return decodeFromAbi(artifact.returnTypes, returnWitness); } // docs:end:execute_unconstrained_function From f93834674985322667e91f3851bc9a4f369c37a1 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 14:56:55 +0000 Subject: [PATCH 68/79] fixes --- yarn-project/end-to-end/src/e2e_event_logs.test.ts | 8 ++++++-- yarn-project/foundation/src/abi/decoder.ts | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_event_logs.test.ts b/yarn-project/end-to-end/src/e2e_event_logs.test.ts index 93c56aa703f..404bf7d717d 100644 --- a/yarn-project/end-to-end/src/e2e_event_logs.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_logs.test.ts @@ -177,7 +177,9 @@ describe('Logs', () => { const exampleEvent0Sort = (a: ExampleEvent0, b: ExampleEvent0) => (a.value0 > b.value0 ? 1 : -1); expect(collectedEvent0sWithIncoming.sort(exampleEvent0Sort)).toStrictEqual( - preimage.map(preimage => ({ value0: preimage[0], value1: preimage[1] })).sort(exampleEvent0Sort), + preimage + .map(preimage => ({ value0: preimage[0].toBigInt(), value1: preimage[1].toBigInt() })) + .sort(exampleEvent0Sort), ); expect(collectedEvent0sWithOutgoing.sort(exampleEvent0Sort)).toStrictEqual( @@ -229,7 +231,9 @@ describe('Logs', () => { const exampleEvent0Sort = (a: ExampleEvent0, b: ExampleEvent0) => (a.value0 > b.value0 ? 1 : -1); expect(collectedEvent0s.sort(exampleEvent0Sort)).toStrictEqual( - preimage.map(preimage => ({ value0: preimage[0], value1: preimage[1] })).sort(exampleEvent0Sort), + preimage + .map(preimage => ({ value0: preimage[0].toBigInt(), value1: preimage[1].toBigInt() })) + .sort(exampleEvent0Sort), ); const exampleEvent1Sort = (a: ExampleEvent1, b: ExampleEvent1) => (a.value2 > b.value2 ? 1 : -1); diff --git a/yarn-project/foundation/src/abi/decoder.ts b/yarn-project/foundation/src/abi/decoder.ts index 5828f12cf31..3cba542cb49 100644 --- a/yarn-project/foundation/src/abi/decoder.ts +++ b/yarn-project/foundation/src/abi/decoder.ts @@ -23,7 +23,7 @@ class AbiDecoder { private decodeNext(abiType: AbiType): AbiDecoded { switch (abiType.kind) { case 'field': - return this.getNextField(); + return this.getNextField().toBigInt(); case 'integer': if (abiType.sign === 'signed') { throw new Error('Unsupported type: signed integer'); From 15ef26021fabc53431a10b16f4dbc645a4bae877 Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Mon, 23 Sep 2024 17:04:14 +0200 Subject: [PATCH 69/79] Update noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Beneš --- noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 6c2569115dd..b5861a65673 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -168,7 +168,9 @@ comptime fn generate_note_hiding_point( let mut new_args_list = &[quote {mut self}]; let mut new_generics_list = &[]; let mut new_trait_bounds_list = &[]; - + // TODO(#8648): Generate generators at comptime instead of importing here. + let num_generators_in_generators_nr: u32 = 5; + assert(indexed_fixed_fields.len() <= num_generators_in_generators_nr, "not enough generators"); for i in 0..indexed_fixed_fields.len() { let (field_name, _, index) = indexed_fixed_fields[i]; let arg_type = f"N{i}".quoted_contents(); From bd3f54c1b497ba3b7b3eb33fa52fc5776b02fe24 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 15:04:47 +0000 Subject: [PATCH 70/79] comment --- noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 6c2569115dd..08fecf58a94 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -120,7 +120,7 @@ comptime fn generate_note_properties(s: StructDefinition) -> Quoted { } ).join(quote {,}); - // TODO: Properly handle non-field types + // TODO #8694: Properly handle non-field types https://github.com/AztecProtocol/aztec-packages/issues/8694 let mut properties_list = &[]; for i in 0..non_header_fields.len() { let (name, _) = non_header_fields[i]; From 2f81b7865d706b942bc61a65edd18e8e1bda37ce Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 15:09:32 +0000 Subject: [PATCH 71/79] added more generators --- noir-projects/aztec-nr/aztec/src/generators.nr | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/generators.nr b/noir-projects/aztec-nr/aztec/src/generators.nr index f8cd5e08dc0..8b4b827e3df 100644 --- a/noir-projects/aztec-nr/aztec/src/generators.nr +++ b/noir-projects/aztec-nr/aztec/src/generators.nr @@ -4,23 +4,24 @@ use dep::protocol_types::point::Point; global Ga1 = Point { x: 0x30426e64aee30e998c13c8ceecda3a77807dbead52bc2f3bf0eae851b4b710c1, y: 0x113156a068f603023240c96b4da5474667db3b8711c521c748212a15bc034ea6, is_infinite: false }; global Ga2 = Point { x: 0x2825c79cc6a5cbbeef7d6a8f1b6a12b312aa338440aefeb4396148c89147c049, y: 0x129bfd1da54b7062d6b544e7e36b90736350f6fba01228c41c72099509f5701e, is_infinite: false }; global Ga3 = Point { x: 0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357f, y: 0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35, is_infinite: false }; -// CREATE NEW GENERATORS HERE -global Ga4 = Point { x: 0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357f, y: 0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35, is_infinite: false }; -global Ga5 = Point { x: 0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357f, y: 0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35, is_infinite: false }; +global Ga4 = Point { x: 0x0e0dad2250583f2a9f0acb04ededf1701b85b0393cae753fe7e14b88af81cb52, y: 0x0973b02c5caac339ee4ad5dab51329920f7bf1b6a07e1dabe5df67040b300962, is_infinite: false }; +global Ga5 = Point { x: 0x2f3342e900e8c488a28931aae68970738fdc68afde2910de7b320c00c902087d, y: 0x1bf958dc63cb09d59230603a0269ae86d6f92494da244910351f1132df20fc08, is_infinite: false }; // If you change this update `G_SLOT` in `yarn-project/simulator/src/client/test_utils.ts` as well global G_slot = Point { x: 0x041223147b680850dc82e8a55a952d4df20256fe0593d949a9541ca00f0abf15, y: 0x0a8c72e60d0e60f5d804549d48f3044d06140b98ed717a9b532af630c1530791, is_infinite: false }; mod test { - use crate::generators::{Ga1, Ga2, Ga3, G_slot}; + use crate::generators::{Ga1, Ga2, Ga3, Ga4, Ga5, G_slot}; use dep::protocol_types::point::Point; use std::hash::derive_generators; #[test] fn test_generators() { - let generators: [Point; 4] = derive_generators("aztec_nr_generators".as_bytes(), 0); + let generators: [Point; 6] = derive_generators("aztec_nr_generators".as_bytes(), 0); assert_eq(generators[0], Ga1); assert_eq(generators[1], Ga2); assert_eq(generators[2], Ga3); + assert_eq(generators[4], Ga4); + assert_eq(generators[5], Ga5); assert_eq(generators[3], G_slot); } } From db80913332d7c64c9cf7f3061b8cb8a37fb7762a Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 15:12:44 +0000 Subject: [PATCH 72/79] fmt --- noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index c95f54d90ee..57566150037 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -170,7 +170,7 @@ comptime fn generate_note_hiding_point( let mut new_trait_bounds_list = &[]; // TODO(#8648): Generate generators at comptime instead of importing here. let num_generators_in_generators_nr: u32 = 5; - assert(indexed_fixed_fields.len() <= num_generators_in_generators_nr, "not enough generators"); + assert(indexed_fixed_fields.len() <= num_generators_in_generators_nr, "not enough generators"); for i in 0..indexed_fixed_fields.len() { let (field_name, _, index) = indexed_fixed_fields[i]; let arg_type = f"N{i}".quoted_contents(); From 469abb8f5e98c63942516cbeab079c51b156524d Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 16:10:21 +0000 Subject: [PATCH 73/79] fixed logs --- yarn-project/end-to-end/src/e2e_event_logs.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_event_logs.test.ts b/yarn-project/end-to-end/src/e2e_event_logs.test.ts index 404bf7d717d..f436552613f 100644 --- a/yarn-project/end-to-end/src/e2e_event_logs.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_logs.test.ts @@ -72,8 +72,8 @@ describe('Logs', () => { const event0 = TestLogContract.events.ExampleEvent0.decode(decryptedLog0!.payload); // We check that the event was decoded correctly - expect(event0?.value0).toStrictEqual(preimage[0]); - expect(event0?.value1).toStrictEqual(preimage[1]); + expect(event0?.value0).toStrictEqual(preimage[0].toBigInt()); + expect(event0?.value1).toStrictEqual(preimage[1].toBigInt()); // We check that an event that does not match, is not decoded correctly due to an event type id mismatch const badEvent0 = TestLogContract.events.ExampleEvent1.decode(decryptedLog0!.payload); @@ -183,7 +183,9 @@ describe('Logs', () => { ); expect(collectedEvent0sWithOutgoing.sort(exampleEvent0Sort)).toStrictEqual( - preimage.map(preimage => ({ value0: preimage[0], value1: preimage[1] })).sort(exampleEvent0Sort), + preimage + .map(preimage => ({ value0: preimage[0].toBigInt(), value1: preimage[1].toBigInt() })) + .sort(exampleEvent0Sort), ); expect([...collectedEvent0sWithIncoming, ...collectedEvent0sWithOutgoing].sort(exampleEvent0Sort)).toStrictEqual( From 06dae6fbc10f570307608d780f3664db2503d970 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 19:36:49 +0000 Subject: [PATCH 74/79] fixed partial notes --- .../spam_contract/src/types/token_note.nr | 9 ++-- .../src/types/token_note.nr | 4 +- .../contracts/token_contract/src/main.nr | 2 +- .../simulator/src/client/test_utils.ts | 42 +++++++++++++++---- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr index c4c46da8e3f..0e544373b09 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr @@ -1,11 +1,8 @@ use dep::aztec::{ prelude::{NoteHeader, NullifiableNote, PrivateContext}, - protocol_types::{ - constants::GENERATOR_INDEX__NOTE_NULLIFIER, point::{Point, POINT_LENGTH}, - hash::poseidon2_hash_with_separator, traits::Serialize -}, + protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, note::utils::compute_note_hash_for_nullify, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app, macros::notes::partial_note + keys::getters::get_nsk_app, macros::notes::note }; trait OwnedNote { @@ -13,7 +10,7 @@ trait OwnedNote { fn get_amount(self) -> U128; } // docs:start:TokenNote -#[partial_note(quote { amount })] +#[note] struct TokenNote { // The amount of tokens in the note amount: U128, diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index c51c49ed4a4..f48c5d090be 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator}, note::utils::compute_note_hash_for_nullify, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app, macros::notes::partial_note + keys::getters::get_nsk_app, macros::notes::note }; trait OwnedNote { @@ -10,7 +10,7 @@ trait OwnedNote { fn get_amount(self) -> U128; } -#[partial_note(quote {amount})] +#[note] struct TokenNote { // The amount of tokens in the note amount: U128, diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index c667b753d90..3d8b917d2e1 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -505,7 +505,7 @@ contract Token { context.set_public_teardown_function( context.this_address(), comptime { - FunctionSelector::from_signature("complete_refund(((Field,Field,bool)),((Field,Field,bool)),Field)") + FunctionSelector::from_signature("complete_refund((Field,Field,bool),(Field,Field,bool),Field)") }, [ fee_payer_point.inner.x, fee_payer_point.inner.y, fee_payer_point.inner.is_infinite as Field, user_point.inner.x, user_point.inner.y, user_point.inner.is_infinite as Field, funded_amount diff --git a/yarn-project/simulator/src/client/test_utils.ts b/yarn-project/simulator/src/client/test_utils.ts index 9253a36fcdb..c76c60c17d3 100644 --- a/yarn-project/simulator/src/client/test_utils.ts +++ b/yarn-project/simulator/src/client/test_utils.ts @@ -3,6 +3,34 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { pedersenCommit } from '@aztec/foundation/crypto'; // Copied over from `noir-projects/aztec-nr/aztec/src/generators.nr` +const GENERATORS = [ + new Point( + new Fr(0x30426e64aee30e998c13c8ceecda3a77807dbead52bc2f3bf0eae851b4b710c1n), + new Fr(0x113156a068f603023240c96b4da5474667db3b8711c521c748212a15bc034ea6n), + false, + ), + new Point( + new Fr(0x2825c79cc6a5cbbeef7d6a8f1b6a12b312aa338440aefeb4396148c89147c049n), + new Fr(0x129bfd1da54b7062d6b544e7e36b90736350f6fba01228c41c72099509f5701en), + false, + ), + new Point( + new Fr(0x0edb1e293c3ce91bfc04e3ceaa50d2c541fa9d091c72eb403efb1cfa2cb3357fn), + new Fr(0x1341d675fa030ece3113ad53ca34fd13b19b6e9762046734f414824c4d6ade35n), + false, + ), + new Point( + new Fr(0x0e0dad2250583f2a9f0acb04ededf1701b85b0393cae753fe7e14b88af81cb52n), + new Fr(0x0973b02c5caac339ee4ad5dab51329920f7bf1b6a07e1dabe5df67040b300962n), + false, + ), + new Point( + new Fr(0x2f3342e900e8c488a28931aae68970738fdc68afde2910de7b320c00c902087dn), + new Fr(0x1bf958dc63cb09d59230603a0269ae86d6f92494da244910351f1132df20fc08n), + false, + ), +]; + const G_SLOT = new Point( new Fr(0x041223147b680850dc82e8a55a952d4df20256fe0593d949a9541ca00f0abf15n), new Fr(0x0a8c72e60d0e60f5d804549d48f3044d06140b98ed717a9b532af630c1530791n), @@ -16,14 +44,14 @@ const G_SLOT = new Point( * @returns A note hash. */ export function computeNoteHash(storageSlot: Fr, noteContent: Fr[]): Fr { - // TODO(#7771): update this to do only 1 MSM call - const c = pedersenCommit( - noteContent.map(f => f.toBuffer()), - GeneratorIndex.NOTE_HIDING_POINT, - ); - const noteHidingPointBeforeSlotting = new Point(new Fr(c[0]), new Fr(c[1]), false); - const grumpkin = new Grumpkin(); + const noteHidingPointBeforeSlotting = noteContent + .slice(1) + .reduce( + (acc, item, i) => grumpkin.add(acc, grumpkin.mul(GENERATORS[i], new Fq(item.toBigInt()))), + grumpkin.mul(GENERATORS[0], new Fq(noteContent[0].toBigInt())), + ); + const slotPoint = grumpkin.mul(G_SLOT, new Fq(storageSlot.toBigInt())); const noteHidingPoint = grumpkin.add(noteHidingPointBeforeSlotting, slotPoint); return noteHidingPoint.x; From b2fb913900d5898cd2ee95ca7bbbdca35ba220f4 Mon Sep 17 00:00:00 2001 From: thunkar Date: Mon, 23 Sep 2024 20:13:31 +0000 Subject: [PATCH 75/79] final fixes --- .../end-to-end/src/e2e_fees/private_refunds.test.ts | 6 ++++-- .../e2e_token_contract/private_transfer_recursion.test.ts | 4 ++-- yarn-project/prover-client/package.json | 2 +- yarn-project/simulator/src/client/test_utils.ts | 3 +-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_fees/private_refunds.test.ts b/yarn-project/end-to-end/src/e2e_fees/private_refunds.test.ts index 33f8cafae20..2b6f84a92a2 100644 --- a/yarn-project/end-to-end/src/e2e_fees/private_refunds.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/private_refunds.test.ts @@ -87,7 +87,8 @@ describe('e2e_fees/private_refunds', () => { // the randomness. const refundNoteValue = t.gasSettings.getFeeLimit().sub(new Fr(transactionFee!)); const aliceNpkMHash = t.aliceWallet.getCompleteAddress().publicKeys.masterNullifierPublicKey.hash(); - const aliceRefundNote = new Note([refundNoteValue, aliceNpkMHash, aliceRandomness]); + // Amount has lo and hi limbs, hence the 0. + const aliceRefundNote = new Note([refundNoteValue, Fr.ZERO, aliceNpkMHash, aliceRandomness]); // 5. If the refund flow worked it should have added emitted a note hash of the note we constructed above and we // should be able to add the note to our PXE. Just calling `pxe.addNote(...)` is enough of a check that the note @@ -110,7 +111,8 @@ describe('e2e_fees/private_refunds', () => { // Note that FPC emits randomness as unencrypted log and the tx fee is publicly know so Bob is able to reconstruct // his note just from on-chain data. const bobNpkMHash = t.bobWallet.getCompleteAddress().publicKeys.masterNullifierPublicKey.hash(); - const bobFeeNote = new Note([new Fr(transactionFee!), bobNpkMHash, bobRandomness]); + // Amount has lo and hi limbs, hence the 0. + const bobFeeNote = new Note([new Fr(transactionFee!), Fr.ZERO, bobNpkMHash, bobRandomness]); // 7. Once again we add the note to PXE which computes the note hash and checks that it is in the note hash tree. // TODO(#8238): Implement proper note delivery diff --git a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts index 25535f55b1f..fd905fab2d6 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts @@ -45,7 +45,7 @@ describe('e2e_token_contract private transfer recursion', () => { expect(events[0]).toEqual({ from: accounts[0].address, to: accounts[1].address, - amount: new Fr(totalBalance), + amount: totalBalance, }); }); @@ -71,7 +71,7 @@ describe('e2e_token_contract private transfer recursion', () => { expect(events[0]).toEqual({ from: accounts[0].address, to: accounts[1].address, - amount: new Fr(toSend), + amount: toSend, }); }); diff --git a/yarn-project/prover-client/package.json b/yarn-project/prover-client/package.json index 636bdcac423..9a99cddb3d8 100644 --- a/yarn-project/prover-client/package.json +++ b/yarn-project/prover-client/package.json @@ -96,4 +96,4 @@ "engines": { "node": ">=18" } -} \ No newline at end of file +} diff --git a/yarn-project/simulator/src/client/test_utils.ts b/yarn-project/simulator/src/client/test_utils.ts index c76c60c17d3..169b7388346 100644 --- a/yarn-project/simulator/src/client/test_utils.ts +++ b/yarn-project/simulator/src/client/test_utils.ts @@ -1,6 +1,5 @@ -import { Fq, Fr, GeneratorIndex, Point } from '@aztec/circuits.js'; +import { Fq, Fr, Point } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { pedersenCommit } from '@aztec/foundation/crypto'; // Copied over from `noir-projects/aztec-nr/aztec/src/generators.nr` const GENERATORS = [ From df1f1ef372742bde7983cc510e70a85e0be03a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 23 Sep 2024 20:51:09 +0000 Subject: [PATCH 76/79] Use panic instead of assert(false) --- noir-projects/aztec-nr/aztec/src/macros/mod.nr | 6 ++---- noir-projects/aztec-nr/aztec/src/macros/utils.nr | 12 ++++-------- .../crates/types/src/meta/mod.nr | 6 ++---- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 7bf9e19ed35..23da22f2d1d 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -131,14 +131,12 @@ comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { let note_header = aztec::prelude::NoteHeader::new(contract_address, nonce, storage_slot); $if_statements else { - assert(false, "Unknown note type ID"); - [0, 0, 0, 0] + panic(f"Unknown note type ID") } } } else { quote { - assert(false, "No notes defined"); - [0, 0, 0, 0] + panic(f"No notes defined") } }; diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index 1580a14dae8..59543e106ad 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -6,8 +6,7 @@ pub(crate) comptime fn get_fn_visibility(f: FunctionDefinition) -> Quoted { } else if f.has_named_attribute("public") { quote { public } } else { - assert(false, "Function is neither private nor public"); - std::mem::zeroed() + panic(f"Function is neither private nor public") } } @@ -79,8 +78,7 @@ pub(crate) comptime fn add_to_field_slice(slice_name: Quoted, name: Quoted, typ: $slice_name = $slice_name.append($name.as_bytes().map(| byte: u8 | byte as Field).as_slice()); } } else { - assert(false, f"Cannot add to slice: unsupported type {typ} variable {name}"); - std::mem::zeroed() + panic(f"Cannot add to slice: unsupported type {typ} variable {name}") } } @@ -104,8 +102,7 @@ pub(crate) comptime fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Typ $hasher_name.add_multiple($name.as_bytes().map(| byte: u8 | byte as Field)); } } else { - assert(false, f"Cannot add to hasher: unsupported type {typ} of variable {name}"); - std::mem::zeroed() + panic(f"Cannot add to hasher: unsupported type {typ} of variable {name}") } } @@ -148,8 +145,7 @@ comptime fn signature_of_type(typ: Type) -> Quoted { ).join(quote {,}); f"({field_signatures})".quoted_contents() } else { - assert(false, f"Unsupported type {typ}"); - std::mem::zeroed() + panic(f"Unsupported type {typ}") } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 7c8dc2cf50b..231bd8d320a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -79,8 +79,7 @@ pub comptime fn pack_from_fields( let bytes = byte_list.join(quote {,}); result = quote { [ $bytes ].as_str_unchecked() }; } else { - assert(false, f"Unsupported type for serialization of argument {name} and type {typ}"); - std::mem::zeroed() + panic(f"Unsupported type for serialization of argument {name} and type {typ}") } } else { result = replacement; @@ -130,8 +129,7 @@ pub comptime fn flatten_to_fields(name: Quoted, typ: Type, omit: [Quoted]) -> ([ } aux_vars = aux_vars.push_back(as_bytes); } else { - assert(false, f"Unsupported type for serialization of argument {name} and type {typ}"); - std::mem::zeroed() + panic(f"Unsupported type for serialization of argument {name} and type {typ}") } } (fields, aux_vars) From af652f3d9a630278ae6a546f77d82e7b804c4673 Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 24 Sep 2024 05:42:54 +0000 Subject: [PATCH 77/79] better approach for note hiding point --- .../aztec/src/event/event_interface.nr | 2 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 140 +++++++----------- .../aztec-nr/aztec/src/note/note_header.nr | 2 +- .../ecdsa_public_key_note/src/lib.nr | 10 +- .../contracts/token_contract/src/main.nr | 2 - .../token_contract/src/types/balance_set.nr | 2 +- .../token_contract/src/types/token_note.nr | 2 +- .../src/types/transparent_note.nr | 2 +- .../crates/types/src/abis/event_selector.nr | 2 +- .../crates/types/src/address/aztec_address.nr | 2 +- 10 files changed, 64 insertions(+), 102 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/event/event_interface.nr b/noir-projects/aztec-nr/aztec/src/event/event_interface.nr index ee82d72d293..08498f1373d 100644 --- a/noir-projects/aztec-nr/aztec/src/event/event_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/event/event_interface.nr @@ -1,6 +1,6 @@ use dep::protocol_types::abis::event_selector::EventSelector; -trait EventInterface { +pub trait EventInterface { fn private_to_be_bytes(self, randomness: Field) -> [u8; N * 32 + 64]; fn to_be_bytes(self) -> [u8; N * 32 + 32]; fn get_event_type_id() -> EventSelector; diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 57566150037..e00eecfcdfd 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -27,7 +27,7 @@ comptime fn generate_note_interface( note_type_id: Field, hiding_point_name: Quoted, indexed_fixed_fields: [(Quoted, Type, u32)], - indexed_nullable_fields: [(Quoted, u32)] + indexed_nullable_fields: [(Quoted, Type, u32)] ) -> (Quoted, u32) { let name = s.name(); let typ = s.as_type(); @@ -49,8 +49,8 @@ comptime fn generate_note_interface( &[(quote {header}, quote { aztec::note::note_header::NoteHeader::empty() })] ); - let fixed_fields_args = indexed_fixed_fields.map(| (name, _, _): (Quoted, Type, u32) | quote{self.$name}).push_back(quote {self.get_header().storage_slot}).join(quote {,}); - let nullable_fields_args = indexed_nullable_fields.map(|(name, _): (Quoted, u32)| quote { self.$name }).join(quote {,}); + let fixed_fields_args = indexed_fixed_fields.map(| (name, _, _): (Quoted, Type, u32) | quote{ self.$name }).push_back(quote { self.get_header().storage_slot }).join(quote {,}); + let nullable_fields_args = indexed_nullable_fields.map(|(name, _, _): (Quoted, Type, u32)| quote { self.$name }).join(quote {,}); (quote { impl aztec::note::note_interface::NoteInterface<$content_len> for $name { @@ -155,68 +155,50 @@ pub(crate) comptime fn generate_note_export(s: StructDefinition, note_type_id: F } } +comptime fn generate_multi_scalar_mul(indexed_fields: [(Quoted, Type, u32)]) -> ([Quoted], [Quoted], [Quoted], Quoted) { + let mut generators_list = &[]; + let mut scalars_list = &[]; + let mut args_list = &[]; + let mut aux_vars_list = &[]; + // TODO(#8648): Generate generators at comptime instead of importing here. + for i in 0..indexed_fields.len() { + let (field_name, typ, index) = indexed_fields[i]; + let start_generator_index = index + 1; + let (flattened_field, aux_vars) = flatten_to_fields(field_name, typ, &[]); + for j in 0..flattened_field.len() { + let flattened_as_field = flattened_field[j]; + let generator_index = start_generator_index + j; + generators_list = generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); + scalars_list = scalars_list.push_back(quote { std::hash::from_field_unsafe($flattened_as_field) }); + } + args_list = args_list.push_back(quote { $field_name: $typ }); + aux_vars_list = aux_vars_list.append(aux_vars); + } + + let aux_vars = if aux_vars_list.len() > 0 { + let joint = aux_vars_list.join(quote {;}); + quote { $joint; } + } else { + quote {} + }; + (generators_list, scalars_list, args_list, aux_vars) +} + comptime fn generate_note_hiding_point( s: StructDefinition, indexed_fixed_fields: [(Quoted, Type, u32)], - indexed_nullable_fields: [(Quoted, u32)] + indexed_nullable_fields: [(Quoted, Type, u32)] ) -> (Quoted, Quoted) { let name = s.name(); let hiding_point_name = f"{name}HidingPoint".quoted_contents(); - let mut new_generators_list = &[]; - let mut new_scalars_list = &[]; - let mut new_args_list = &[quote {mut self}]; - let mut new_generics_list = &[]; - let mut new_trait_bounds_list = &[]; - // TODO(#8648): Generate generators at comptime instead of importing here. - let num_generators_in_generators_nr: u32 = 5; - assert(indexed_fixed_fields.len() <= num_generators_in_generators_nr, "not enough generators"); - for i in 0..indexed_fixed_fields.len() { - let (field_name, _, index) = indexed_fixed_fields[i]; - let arg_type = f"N{i}".quoted_contents(); - let generator_index = index + 1; - new_generators_list = new_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); - new_scalars_list = new_scalars_list.push_back(quote { std::hash::from_field_unsafe($field_name.to_field()) }); - new_args_list = new_args_list.push_back(quote { $field_name: $arg_type }); - new_generics_list = new_generics_list.push_back(quote { $arg_type }); - new_trait_bounds_list = new_trait_bounds_list.push_back(quote { $arg_type: aztec::protocol_types::traits::ToField }); - } + let (new_generators_list, new_scalars_list, new_args_list, new_aux_vars) = generate_multi_scalar_mul(indexed_fixed_fields); - new_args_list = new_args_list.push_back(quote { storage_slot: Field }); + let new_args = &[quote {mut self}].append(new_args_list).push_back(quote { storage_slot: Field }).join(quote {,}); let new_generators = new_generators_list.push_back(quote { aztec::generators::G_slot }).join(quote {,}); let new_scalars = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(storage_slot) }).join(quote {,}); - let new_args = new_args_list.join(quote {,}); - - let new_generics = if new_generics_list.len() > 0 { - let generics = new_generics_list.join(quote {,}); - quote {<$generics>} - } else { - quote {} - }; - - let new_trait_bounds = if new_trait_bounds_list.len() > 0 { - let bounds = new_trait_bounds_list.join(quote {,}); - quote {where $bounds} - } else { - quote {} - }; - let mut finalize_generators_list = &[]; - let mut finalize_scalars_list = &[]; - let mut finalize_args_list = &[]; - let mut finalize_generics_list = &[]; - let mut finalize_trait_bounds_list = &[]; - - for i in 0..indexed_nullable_fields.len() { - let (field_name, index) = indexed_nullable_fields[i]; - let arg_type = f"N{i}".quoted_contents(); - finalize_args_list = finalize_args_list.push_back(quote { $field_name: $arg_type }); - let generator_index = index + 1; - finalize_generators_list = finalize_generators_list.push_back(f"aztec::generators::Ga{generator_index}".quoted_contents()); - finalize_scalars_list = finalize_scalars_list.push_back(quote { std::hash::from_field_unsafe($field_name.to_field()) }); - finalize_generics_list = finalize_generics_list.push_back(quote { $arg_type }); - finalize_trait_bounds_list = finalize_trait_bounds_list.push_back(quote { $arg_type: aztec::protocol_types::traits::ToField }); - } + let (finalize_generators_list, finalize_scalars_list, finalize_args_list, finalize_aux_vars) = generate_multi_scalar_mul(indexed_nullable_fields); let finalize_args = if finalize_args_list.len() > 0 { &[quote {self}].append(finalize_args_list).join(quote {,}) @@ -228,6 +210,7 @@ comptime fn generate_note_hiding_point( let finalize_generators = finalize_generators_list.join(quote {,}); let finalize_scalars = finalize_scalars_list.join(quote {,}); quote { + $finalize_aux_vars let point = std::embedded_curve_ops::multi_scalar_mul( [$finalize_generators], [$finalize_scalars] @@ -238,27 +221,14 @@ comptime fn generate_note_hiding_point( quote { self.inner.x } }; - let finalize_name = if finalize_generics_list.len() > 0 { - let generics = finalize_generics_list.join(quote {,}); - quote {finalize<$generics>} - } else { - quote {finalize} - }; - - let finalize_trait_bounds = if finalize_trait_bounds_list.len() > 0 { - let bounds = finalize_trait_bounds_list.join(quote {,}); - quote {where $bounds} - } else { - quote {} - }; - (quote { struct $hiding_point_name { inner: aztec::protocol_types::point::Point } impl $hiding_point_name { - fn new$new_generics($new_args) -> $hiding_point_name $new_trait_bounds { + fn new($new_args) -> $hiding_point_name { + $new_aux_vars let point = std::embedded_curve_ops::multi_scalar_mul( [$new_generators], [$new_scalars] @@ -273,7 +243,7 @@ comptime fn generate_note_hiding_point( } - fn $finalize_name($finalize_args) -> Field $finalize_trait_bounds { + fn finalize($finalize_args) -> Field { $finalize_body } } @@ -323,7 +293,7 @@ comptime fn register_note(note: StructDefinition, note_serialized_len: u32, note comptime fn index_note_fields( s: StructDefinition, nullable_fields: [Quoted] -) -> ([(Quoted, Type, u32)], [(Quoted, u32)]) { +) -> ([(Quoted, Type, u32)], [(Quoted, Type, u32)]) { let mut indexed_fixed_fields = &[]; let mut indexed_nullable_fields = &[]; let mut counter: u32 = 0; @@ -333,39 +303,36 @@ comptime fn index_note_fields( if nullable_fields.all(| field | field != name) { indexed_fixed_fields = indexed_fixed_fields.push_back((name, typ, counter)); } else { - indexed_nullable_fields = indexed_nullable_fields.push_back((name, counter)); + indexed_nullable_fields = indexed_nullable_fields.push_back((name, typ, counter)); } } - counter+=1; + let (flattened, _) = flatten_to_fields(name, typ, &[]); + counter+=flattened.len(); } (indexed_fixed_fields, indexed_nullable_fields) } -comptime fn common_note_annotation( - s: StructDefinition, - indexed_fixed_fields: [(Quoted, Type, u32)], - indexed_nullable_fields: [(Quoted, u32)] -) -> (Quoted, Quoted, Field) { +comptime fn common_note_annotation(s: StructDefinition) -> (Quoted, Field) { // Automatically inject header if not present let filtered_header = s.fields().filter(| (_, typ): (Quoted, Type) | typ == NOTE_HEADER_TYPE); if (filtered_header.len() == 0) { let new_fields = s.fields().push_back((quote { header }, NOTE_HEADER_TYPE)); s.set_fields(new_fields); } - let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, indexed_fixed_fields, indexed_nullable_fields); let note_properties = generate_note_properties(s); let note_type_id = compute_note_type_id(s.name()); (quote { $note_properties - $note_hiding_point - }, hiding_point_name, note_type_id) + }, note_type_id) } #[varargs] pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, nullable_fields); - let (common, hiding_point_name, note_type_id) = common_note_annotation(s, indexed_fixed_fields, indexed_nullable_fields); + + let (common, note_type_id) = common_note_annotation(s); + let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, indexed_fixed_fields, indexed_nullable_fields); let (note_interface_impl, note_serialized_len) = generate_note_interface( s, note_type_id, @@ -378,6 +345,7 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> quote { $common + $note_hiding_point $note_interface_impl $partial_note_impl } @@ -385,7 +353,8 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> pub comptime fn note(s: StructDefinition) -> Quoted { let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, &[]); - let (common, hiding_point_name, note_type_id) = common_note_annotation(s, indexed_fixed_fields, indexed_nullable_fields); + let (common, note_type_id) = common_note_annotation(s); + let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, indexed_fixed_fields, indexed_nullable_fields); let (note_interface_impl, note_serialized_len) = generate_note_interface( s, note_type_id, @@ -397,14 +366,13 @@ pub comptime fn note(s: StructDefinition) -> Quoted { quote { $common + $note_hiding_point $note_interface_impl } } pub comptime fn note_custom_interface(s: StructDefinition) -> Quoted { - let (indexed_fixed_fields, indexed_nullable_fields)= index_note_fields(s, &[]); - let (common, _, note_type_id) = common_note_annotation(s, indexed_fixed_fields, indexed_nullable_fields); - + let (common, note_type_id) = common_note_annotation(s); let serialized_len_type = fresh_type_variable(); let note_interface_impl = s.as_type().get_trait_impl(quote { NoteInterface<$serialized_len_type> }.as_trait_constraint()); let name = s.name(); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_header.nr b/noir-projects/aztec-nr/aztec/src/note/note_header.nr index bf71981024e..0308a9a5b6e 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_header.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_header.nr @@ -2,7 +2,7 @@ use dep::protocol_types::{address::AztecAddress, traits::{Empty, Serialize}}; global NOTE_HEADER_LENGTH: u32 = 4; -struct NoteHeader { +pub struct NoteHeader { contract_address: AztecAddress, nonce: Field, storage_slot: Field, diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index 45136b85160..cec2dab9a5e 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -93,13 +93,9 @@ impl NoteInterface for EcdsaPublicKeyNote { comptime { let bytes = "EcdsaPublicKeyNote".as_bytes(); - let hash = std::hash::keccak256(bytes, bytes.len() as u32); - let mut selector_be_bytes = [0; 4]; - for i in 0..4 { - selector_be_bytes[i] = hash[i]; - } - - aztec::protocol_types::utils::field::field_from_bytes(selector_be_bytes, true) + let hash = aztec::protocol_types::hash::poseidon2_hash_bytes(bytes); + let hash_bytes = hash.to_be_bytes::<4>(); + aztec::protocol_types::utils::field::field_from_bytes(hash_bytes, true) } } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 3d8b917d2e1..a5ec69962f3 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -30,8 +30,6 @@ contract Token { utils::comparison::Comparator, protocol_types::{point::Point, traits::Serialize} }; - use std::embedded_curve_ops::EmbeddedCurvePoint; - // docs:start:import_authwit use dep::authwit::auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public, compute_authwit_nullifier}; // docs:end:import_authwit diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr index 27586c5c2ac..c768d432277 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balance_set.nr @@ -7,7 +7,7 @@ use dep::aztec::{ }; use crate::types::token_note::OwnedNote; -struct BalanceSet { +pub struct BalanceSet { set: PrivateSet, } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index a57ad749c7f..365724e6868 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -12,7 +12,7 @@ trait OwnedNote { // docs:start:TokenNote #[partial_note(quote {amount})] -struct TokenNote { +pub struct TokenNote { // The amount of tokens in the note amount: U128, // The nullifying public key hash is used with the nsk_app to ensure that the note can be privately spent. diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index 826fbca2a2d..c0dbd3662f1 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -10,7 +10,7 @@ use dep::aztec::{ // Owner of the tokens provides a "secret_hash" as an argument to the public "shield" function and then the tokens // can be redeemed in private by presenting the preimage of the "secret_hash" (the secret). #[note] -struct TransparentNote { +pub struct TransparentNote { amount: Field, secret_hash: Field, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr index 0a1bbf3444d..b456c2fd03f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/event_selector.nr @@ -3,7 +3,7 @@ use crate::traits::{Serialize, Deserialize, FromField, ToField, Empty}; global SELECTOR_SIZE: u32 = 4; -struct EventSelector { +pub struct EventSelector { // 1st 4-bytes (big-endian leftmost) of abi-encoding of an event. inner: u32, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr index db9787ffbce..06605d2c553 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr @@ -6,7 +6,7 @@ use crate::{ }; // Aztec address -struct AztecAddress { +pub struct AztecAddress { inner : Field } From 08fb04e25cc37eb5731ad529d67e77b3b3b2cc35 Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 24 Sep 2024 06:13:41 +0000 Subject: [PATCH 78/79] fixed test --- .../end-to-end/src/e2e_token_contract/transfer_private.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts index 170a5568153..5865ac3343a 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts @@ -46,7 +46,7 @@ describe('e2e_token_contract transfer private', () => { expect(events[0]).toEqual({ from: accounts[0].address, to: accounts[1].address, - amount: new Fr(amount), + amount: amount, }); }); From ecac29d515f223267000470fbb911106b54be01c Mon Sep 17 00:00:00 2001 From: thunkar Date: Tue, 24 Sep 2024 08:23:53 +0000 Subject: [PATCH 79/79] final fixes? --- .../src/e2e_token_contract/private_transfer_recursion.test.ts | 2 +- yarn-project/simulator/src/client/test_utils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts index fd905fab2d6..cdb65ecca6a 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts @@ -1,4 +1,4 @@ -import { BatchCall, EventType, Fr } from '@aztec/aztec.js'; +import { BatchCall, EventType } from '@aztec/aztec.js'; import { TokenContract } from '@aztec/noir-contracts.js'; import { TokenContractTest } from './token_contract_test.js'; diff --git a/yarn-project/simulator/src/client/test_utils.ts b/yarn-project/simulator/src/client/test_utils.ts index 169b7388346..af7fa0345d9 100644 --- a/yarn-project/simulator/src/client/test_utils.ts +++ b/yarn-project/simulator/src/client/test_utils.ts @@ -47,7 +47,7 @@ export function computeNoteHash(storageSlot: Fr, noteContent: Fr[]): Fr { const noteHidingPointBeforeSlotting = noteContent .slice(1) .reduce( - (acc, item, i) => grumpkin.add(acc, grumpkin.mul(GENERATORS[i], new Fq(item.toBigInt()))), + (acc, item, i) => grumpkin.add(acc, grumpkin.mul(GENERATORS[i + 1], new Fq(item.toBigInt()))), grumpkin.mul(GENERATORS[0], new Fq(noteContent[0].toBigInt())), );