From 79f875d8235f6e286c1dcedfa32ffa4c1818e773 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 7 May 2026 15:11:30 -0400 Subject: [PATCH 1/6] new contracts snapshots infra, includes expand snaps --- cspell.json | 4 +- noir-projects/bootstrap.sh | 2 +- .../noir-contract-snapshots/.gitignore | 2 + .../noir-contract-snapshots/Cargo.toml | 16 + .../noir-contract-snapshots/README.md | 59 + .../noir-contract-snapshots/bootstrap.sh | 45 + .../noir-contract-snapshots/build.rs | 110 + .../noir-contract-snapshots/src/lib.rs | 2 + .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../authorize_once_from_wrong_type/Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../authorize_once_on_utility_fn/Nargo.toml | 2 +- .../authorize_once_on_utility_fn/src/main.nr | 0 .../aztec_macro_too_many_args/Nargo.toml | 2 +- .../aztec_macro_too_many_args/src/main.nr | 0 .../compile_failure/bob_token/Nargo.toml | 8 + .../compile_failure}/bob_token/src/main.nr | 0 .../duplicate_storage/Nargo.toml | 2 +- .../duplicate_storage/src/main.nr | 0 .../event_selector_collision/Nargo.toml | 2 +- .../event_selector_collision/src/main.nr | 0 .../external_and_internal_together/Nargo.toml | 2 +- .../src/main.nr | 0 .../incorrect_storage_struct_name/Nargo.toml | 2 +- .../incorrect_storage_struct_name/src/main.nr | 0 .../initializer_on_non_external_fn/Nargo.toml | 2 +- .../src/main.nr | 0 .../initializer_on_utility_fn/Nargo.toml | 2 +- .../initializer_on_utility_fn/src/main.nr | 0 .../compile_failure}/invalid_event/Nargo.toml | 2 +- .../invalid_event/src/invalid_event.nr | 0 .../invalid_event/src/main.nr | 0 .../invalid_external_function_type/Nargo.toml | 2 +- .../src/main.nr | 0 .../invalid_internal_function_type/Nargo.toml | 2 +- .../src/main.nr | 0 .../compile_failure}/invalid_note/Nargo.toml | 2 +- .../invalid_note/src/invalid_note.nr | 0 .../compile_failure}/invalid_note/src/main.nr | 0 .../marked_private_unconstrained/Nargo.toml | 2 +- .../marked_private_unconstrained/src/main.nr | 0 .../marked_public_unconstrained/Nargo.toml | 2 +- .../marked_public_unconstrained/src/main.nr | 0 ...constrained-MarkedPublicUnconstrained.json | 1 + .../noinitcheck_on_non_external_fn/Nargo.toml | 2 +- .../src/main.nr | 0 .../noinitcheck_on_utility_fn/Nargo.toml | 2 +- .../noinitcheck_on_utility_fn/src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../non_deserializable/Nargo.toml | 2 +- .../non_deserializable/src/main.nr | 0 .../non_serializable/Nargo.toml | 2 +- .../non_serializable/src/main.nr | 0 .../only_self_on_non_external_fn/Nargo.toml | 2 +- .../only_self_on_non_external_fn/src/main.nr | 0 .../only_self_on_utility_fn/Nargo.toml | 2 +- .../only_self_on_utility_fn/src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../pub_private_external_fn/Nargo.toml | 2 +- .../pub_private_external_fn/src/main.nr | 0 .../pub_public_external_fn/Nargo.toml | 2 +- .../pub_public_external_fn/src/main.nr | 0 .../pub_utility_external_fn/Nargo.toml | 2 +- .../pub_utility_external_fn/src/main.nr | 0 .../public_allow_phase_change/Nargo.toml | 2 +- .../public_allow_phase_change/src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../reserved_public_dispatch/Nargo.toml | 2 +- .../reserved_public_dispatch/src/main.nr | 0 .../Nargo.toml | 2 +- .../src/main.nr | 0 .../user_defined_offchain_receive/Nargo.toml | 2 +- .../user_defined_offchain_receive/src/main.nr | 0 .../utility_not_unconstrained/Nargo.toml | 2 +- .../utility_not_unconstrained/src/main.nr | 0 .../view_on_non_external_fn/Nargo.toml | 2 +- .../view_on_non_external_fn/src/main.nr | 0 .../view_on_utility_fn/Nargo.toml | 2 +- .../view_on_utility_fn/src/main.nr | 0 .../authorize_once_before_external/Nargo.toml | 2 +- .../src/main.nr | 0 ..._external-AuthorizeOnceBeforeExternal.json | 1 + ...ernal-AuthorizeOnceBeforeExternal.json.bak | 1 + .../tests/snapshots.rs | 107 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 67 + .../snapshots__stderr.snap | 27 + .../snapshots__stderr.snap | 27 + .../snapshots__stderr.snap | 27 + .../snapshots__stderr.snap | 27 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 17 + .../bob_token/snapshots__stderr.snap | 304 + .../duplicate_storage/snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 19 + .../invalid_event/snapshots__stderr.snap | 24 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 17 + .../invalid_note/snapshots__stderr.snap | 35 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 17 + .../non_deserializable/snapshots__stderr.snap | 77 + .../non_serializable/snapshots__stderr.snap | 77 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 15 + .../snapshots__stderr.snap | 15 + .../snapshots__stderr.snap | 15 + .../snapshots__stderr.snap | 15 + .../snapshots__stderr.snap | 15 + .../snapshots__stderr.snap | 25 + .../snapshots__stderr.snap | 26 + .../snapshots__stderr.snap | 25 + .../snapshots__stderr.snap | 26 + .../snapshots__stderr.snap | 41 + .../snapshots__stderr.snap | 41 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 23 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 17 + .../snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 17 + .../view_on_utility_fn/snapshots__stderr.snap | 19 + .../snapshots__stderr.snap | 5 + .../amm_contract/snapshots__expanded.snap | 2920 ++++++ .../snapshots__expanded.snap | 1655 ++++ .../snapshots__expanded.snap | 7788 +++++++++++++++++ .../snapshots__expanded.snap | 2146 +++++ .../token_contract/snapshots__expanded.snap | 4965 +++++++++++ .../noir-contracts-comp-failures/README.md | 37 - .../noir-contracts-comp-failures/bootstrap.sh | 146 - .../contracts/.gitignore | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 5 - .../expected_error | 0 .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../aztec_macro_too_many_args/expected_error | 1 - .../contracts/bob_token/Nargo.toml | 8 - .../contracts/bob_token/expected_error | 38 - .../duplicate_storage/expected_error | 1 - .../event_selector_collision/expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../initializer_on_utility_fn/expected_error | 1 - .../contracts/invalid_event/expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../contracts/invalid_note/expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../noinitcheck_on_utility_fn/expected_error | 1 - .../expected_error | 1 - .../non_deserializable/expected_error | 6 - .../contracts/non_serializable/expected_error | 6 - .../expected_error | 1 - .../only_self_on_utility_fn/expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../expected_error | 2 - .../expected_error | 2 - .../expected_error | 2 - .../expected_error | 2 - .../expected_error | 3 - .../expected_error | 3 - .../pub_private_external_fn/expected_error | 1 - .../pub_public_external_fn/expected_error | 1 - .../pub_utility_external_fn/expected_error | 1 - .../public_allow_phase_change/expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../reserved_public_dispatch/expected_error | 1 - .../expected_error | 1 - .../expected_error | 1 - .../utility_not_unconstrained/expected_error | 1 - .../view_on_non_external_fn/expected_error | 1 - .../view_on_utility_fn/expected_error | 1 - pied! | 43 + 240 files changed, 21466 insertions(+), 359 deletions(-) create mode 100644 noir-projects/noir-contract-snapshots/.gitignore create mode 100644 noir-projects/noir-contract-snapshots/Cargo.toml create mode 100644 noir-projects/noir-contract-snapshots/README.md create mode 100755 noir-projects/noir-contract-snapshots/bootstrap.sh create mode 100644 noir-projects/noir-contract-snapshots/build.rs create mode 100644 noir-projects/noir-contract-snapshots/src/lib.rs rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/allow_phase_change_on_non_external_fn/Nargo.toml (68%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/allow_phase_change_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/allow_phase_change_on_utility_fn/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/allow_phase_change_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorization_selector_collision/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorization_selector_collision/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_from_wrong_type/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_from_wrong_type/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_missing_from_param/Nargo.toml (68%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_missing_from_param/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_missing_nonce_param/Nargo.toml (68%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_missing_nonce_param/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_nonce_wrong_type/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_nonce_wrong_type/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_on_non_external_fn/Nargo.toml (68%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_on_utility_fn/Nargo.toml (66%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/authorize_once_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/aztec_macro_too_many_args/Nargo.toml (66%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/aztec_macro_too_many_args/src/main.nr (100%) create mode 100644 noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/Nargo.toml rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/bob_token/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/duplicate_storage/Nargo.toml (70%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/duplicate_storage/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/event_selector_collision/Nargo.toml (71%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/event_selector_collision/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/external_and_internal_together/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/external_and_internal_together/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/incorrect_storage_struct_name/Nargo.toml (72%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/incorrect_storage_struct_name/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/initializer_on_non_external_fn/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/initializer_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/initializer_on_utility_fn/Nargo.toml (66%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/initializer_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_event/Nargo.toml (70%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_event/src/invalid_event.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_event/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_external_function_type/Nargo.toml (72%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_external_function_type/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_internal_function_type/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_internal_function_type/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_note/Nargo.toml (69%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_note/src/invalid_note.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/invalid_note/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/marked_private_unconstrained/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/marked_private_unconstrained/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/marked_public_unconstrained/Nargo.toml (66%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/marked_public_unconstrained/src/main.nr (100%) create mode 100644 noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/noinitcheck_on_non_external_fn/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/noinitcheck_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/noinitcheck_on_utility_fn/Nargo.toml (66%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/noinitcheck_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/noinitcheck_without_initializer/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/noinitcheck_without_initializer/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/non_deserializable/Nargo.toml (70%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/non_deserializable/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/non_serializable/Nargo.toml (70%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/non_serializable/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/only_self_on_non_external_fn/Nargo.toml (66%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/only_self_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/only_self_on_utility_fn/Nargo.toml (65%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/only_self_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_private_external_fn_call/Nargo.toml (74%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_private_external_fn_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_private_internal_fn_call/Nargo.toml (74%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_private_internal_fn_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_public_external_fn_call/Nargo.toml (74%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_public_external_fn_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_public_internal_fn_call/Nargo.toml (74%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_public_internal_fn_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_utility_external_fn_call/Nargo.toml (74%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_direct_utility_external_fn_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_incorrectly_performed_private_call/Nargo.toml (74%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_incorrectly_performed_private_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_incorrectly_performed_private_static_call/Nargo.toml (75%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_incorrectly_performed_private_static_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_incorrectly_performed_public_call/Nargo.toml (74%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_incorrectly_performed_public_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_incorrectly_performed_public_static_call/Nargo.toml (75%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_incorrectly_performed_public_static_call/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_non_state_var_in_storage/Nargo.toml (73%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_non_state_var_in_storage/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_owned_state_var_in_storage/Nargo.toml (73%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/panic_on_owned_state_var_in_storage/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/pub_private_external_fn/Nargo.toml (65%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/pub_private_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/pub_public_external_fn/Nargo.toml (65%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/pub_public_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/pub_utility_external_fn/Nargo.toml (65%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/pub_utility_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/public_allow_phase_change/Nargo.toml (66%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/public_allow_phase_change/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/public_function_selector_collision/Nargo.toml (73%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/public_function_selector_collision/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/reserved_emit_public_init_nullifier/Nargo.toml (68%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/reserved_emit_public_init_nullifier/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/reserved_public_dispatch/Nargo.toml (65%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/reserved_public_dispatch/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/unmacroified_function_in_contract/Nargo.toml (68%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/unmacroified_function_in_contract/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/user_defined_offchain_receive/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/user_defined_offchain_receive/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/utility_not_unconstrained/Nargo.toml (66%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/utility_not_unconstrained/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/view_on_non_external_fn/Nargo.toml (65%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/view_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/view_on_utility_fn/Nargo.toml (64%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_failure}/view_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_success}/authorize_once_before_external/Nargo.toml (67%) rename noir-projects/{noir-contracts-comp-failures/contracts => noir-contract-snapshots/test_programs/compile_success}/authorize_once_before_external/src/main.nr (100%) create mode 100644 noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json create mode 100644 noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots.rs create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/expand/amm_contract/snapshots__expanded.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap create mode 100644 noir-projects/noir-contract-snapshots/tests/snapshots/expand/token_contract/snapshots__expanded.snap delete mode 100644 noir-projects/noir-contracts-comp-failures/README.md delete mode 100755 noir-projects/noir-contracts-comp-failures/bootstrap.sh delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/.gitignore delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/authorize_once_before_external/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/bob_token/Nargo.toml delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/bob_token/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/invalid_event/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/invalid_note/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/non_serializable/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/expected_error delete mode 100644 noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/expected_error create mode 100644 pied! diff --git a/cspell.json b/cspell.json index 9766afc1ea5a..f792d7920a47 100644 --- a/cspell.json +++ b/cspell.json @@ -71,6 +71,7 @@ "cimg", "ciphertext", "ciphertexts", + "clippy", "clonedeep", "clonedeepwith", "cmd", @@ -171,6 +172,7 @@ "includable", "incrementation", "indexeddb", + "INSTA", "interruptible", "IPFS", "isequal", @@ -367,8 +369,8 @@ "unfinalized", "uniquified", "uniquify", - "unlinkability", "unkonstrained", + "unlinkability", "unnullify", "unpadded", "unprefixed", diff --git a/noir-projects/bootstrap.sh b/noir-projects/bootstrap.sh index 9bd80aeea54a..cadced1662e0 100755 --- a/noir-projects/bootstrap.sh +++ b/noir-projects/bootstrap.sh @@ -26,7 +26,7 @@ function build { } function test_cmds { - parallel -k ./{}/bootstrap.sh test_cmds ::: noir-protocol-circuits noir-contracts aztec-nr noir-contracts-comp-failures + parallel -k ./{}/bootstrap.sh test_cmds ::: noir-protocol-circuits noir-contracts aztec-nr noir-contract-snapshots } function test { diff --git a/noir-projects/noir-contract-snapshots/.gitignore b/noir-projects/noir-contract-snapshots/.gitignore new file mode 100644 index 000000000000..ca98cd96efdc --- /dev/null +++ b/noir-projects/noir-contract-snapshots/.gitignore @@ -0,0 +1,2 @@ +/target/ +Cargo.lock diff --git a/noir-projects/noir-contract-snapshots/Cargo.toml b/noir-projects/noir-contract-snapshots/Cargo.toml new file mode 100644 index 000000000000..edc56c445319 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "noir-contract-snapshots" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +path = "src/lib.rs" + +[[test]] +name = "snapshots" +path = "tests/snapshots.rs" +harness = true + +[dev-dependencies] +insta = "1" diff --git a/noir-projects/noir-contract-snapshots/README.md b/noir-projects/noir-contract-snapshots/README.md new file mode 100644 index 000000000000..fb8614eeb502 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/README.md @@ -0,0 +1,59 @@ +## Noir Contract Snapshots + +`cargo insta` snapshot tests for noir contracts. Two test categories live here: + +- **`expand/`** — runs `nargo expand` on a curated set of aztec-nr contracts (mirrors what CI benchmarks already exercise) and snapshots the expanded source. Surface for catching macro regressions that pass typechecking but silently change generated code. +- **`compile_failure/`** — drives `nargo compile` on intentionally invalid aztec-nr contracts and snapshots the full stderr. + +### Layout + +``` +Cargo.toml +build.rs # generates one #[test] per case at build time +tests/ + snapshots.rs # run_compile_failure / run_expand helpers + snapshots/ + compile_failure//*.snap # committed + expand//*.snap # committed +test_programs/ + compile_failure//{Nargo.toml,src/main.nr} +``` + +`expand` cases are *not* duplicated under `test_programs/`. They live in their canonical home under `noir-contracts/contracts/{app,test}/` and are referenced by relative path from `build.rs` (`EXPAND_CASES`). + +### Prerequisites + +`nargo` must be built. From the repo root: + +```sh +(cd noir && ./bootstrap.sh) +``` + +By default the test harness looks for `nargo` at `../../noir/noir-repo/target/release/nargo`. Override with `NARGO=/path/to/nargo cargo test`. + +### Running + +```sh +cargo test # run all snapshot tests +cargo test --test snapshots compile_failure # run one module +cargo test --test snapshots test_token # run one test (substring match) +``` + +### Updating snapshots + +Failing assertions write `.snap.new` siblings. Review them by reading the file, or use the review UI: + +```sh +cargo insta review # interactive, recommended +cargo insta accept # accept all pending snapshots +cargo insta test --accept # run + accept in one step (needed + # when the .snap doesn't exist yet) +``` + +CI rejects `INSTA_UPDATE`; any drift must be resolved locally and committed. + +### Adding a case + +`expand`: append `(name, relative_path)` to `EXPAND_CASES` in `build.rs`, then `cargo insta test --accept`. + +`compile_failure`: drop a contract under `test_programs/compile_failure//` (`Nargo.toml` + `src/main.nr`), then `cargo insta test --accept`. Case directory names must use `_`, not `-`. diff --git a/noir-projects/noir-contract-snapshots/bootstrap.sh b/noir-projects/noir-contract-snapshots/bootstrap.sh new file mode 100755 index 000000000000..721f5eb41295 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/bootstrap.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +source $(git rev-parse --show-toplevel)/ci3/source_bootstrap + +# nargo binary path relative to the crate root (this directory) +export NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} + +# Build the snapshot test binaries (compiles build.rs codegen too) and run Rust lints. +function build { + echo_header "noir-contract-snapshots build" + denoise "cargo build --tests" + denoise "cargo fmt --check" + denoise "cargo clippy --all-targets" +} + +# Run the snapshot tests. CI rejects INSTA_UPDATE so any drift between +# committed snapshots and reality must be resolved intentionally by a developer. +function test { + echo_header "noir-contract-snapshots test" + if [ "${CI:-0}" = "1" ] && [ -n "${INSTA_UPDATE:-}" ] && [ "${INSTA_UPDATE}" != "no" ]; then + echo "INSTA_UPDATE is not permitted in CI. Run 'cargo insta accept' locally and commit." >&2 + exit 1 + fi + INSTA_UPDATE=no cargo test --quiet +} + +function test_cmds { + if [ "${TARGET_BRANCH:-}" = "merge-train/fairies" ]; then + hash=disabled-cache + else + hash=$(hash_str \ + $(../../noir/bootstrap.sh hash) \ + $(cache_content_hash \ + ^noir-projects/noir-contract-snapshots \ + ^noir-projects/noir-contracts/contracts/app \ + ^noir-projects/noir-contracts/contracts/test \ + ^noir-projects/aztec-nr)) + fi + echo "$hash ./noir-projects/noir-contract-snapshots/bootstrap.sh test" +} + +case "$cmd" in + *) + default_cmd_handler "$@" + ;; +esac diff --git a/noir-projects/noir-contract-snapshots/build.rs b/noir-projects/noir-contract-snapshots/build.rs new file mode 100644 index 000000000000..32f4f73bf0be --- /dev/null +++ b/noir-projects/noir-contract-snapshots/build.rs @@ -0,0 +1,110 @@ +use std::env; +use std::fs::{self, File}; +use std::io::Write; +use std::path::{Path, PathBuf}; + +/// Contracts whose `nargo expand` output is snapshotted. The set is kept +/// aligned with the contracts already exercised by CI benchmarks so that +/// macro-induced diffs and benchmark deltas show up on the same review. +/// +/// To add a case: append an entry here and run +/// `cargo insta test --accept -p noir-contract-snapshots`. +const EXPAND_CASES: &[(&str, &str)] = &[ + ( + "token_contract", + "../noir-contracts/contracts/app/token_contract", + ), + ( + "amm_contract", + "../noir-contracts/contracts/app/amm_contract", + ), + ( + "storage_proof_test_contract", + "../noir-contracts/contracts/test/storage_proof_test_contract", + ), + ( + "avm_test_contract", + "../noir-contracts/contracts/test/avm_test_contract", + ), + ( + "avm_gadgets_test_contract", + "../noir-contracts/contracts/test/avm_gadgets_test_contract", + ), +]; + +fn main() { + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let dest = out_dir.join("tests.rs"); + let mut f = File::create(&dest).unwrap(); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=test_programs"); + for (_, rel) in EXPAND_CASES { + let abs = manifest_dir.join(rel); + println!("cargo:rerun-if-changed={}", abs.display()); + } + + write_dir_scanned_module( + &mut f, + &manifest_dir, + "compile_failure", + "run_compile_failure", + ); + write_dir_scanned_module( + &mut f, + &manifest_dir, + "compile_success", + "run_compile_success", + ); + write_expand_module(&mut f, &manifest_dir); +} + +fn write_dir_scanned_module(f: &mut File, manifest_dir: &Path, module: &str, helper: &str) { + let test_dir = manifest_dir.join(format!("test_programs/{module}")); + let mut cases: Vec<(String, PathBuf)> = fs::read_dir(&test_dir) + .unwrap_or_else(|e| { + panic!("could not read {}: {e}", test_dir.display()); + }) + .filter_map(Result::ok) + .filter(|e| e.path().is_dir() && e.path().join("Nargo.toml").exists()) + .map(|e| (e.file_name().into_string().unwrap(), e.path())) + .collect(); + cases.sort_by(|a, b| a.0.cmp(&b.0)); + + writeln!(f, "mod {module} {{").unwrap(); + for (name, path) in cases { + if name.contains('-') { + panic!("{module} case '{name}' must use '_' instead of '-'"); + } + writeln!( + f, + " #[test]\n fn test_{name}() {{\n super::{helper}(\"{name}\", std::path::PathBuf::from(r\"{path}\"));\n }}", + name = name, + path = path.display() + ) + .unwrap(); + } + writeln!(f, "}}").unwrap(); +} + +fn write_expand_module(f: &mut File, manifest_dir: &Path) { + writeln!(f, "mod expand {{").unwrap(); + for (name, rel) in EXPAND_CASES { + let path = manifest_dir.join(rel); + if !path.join("Nargo.toml").exists() { + panic!( + "expand case '{name}' has no Nargo.toml at {}", + path.display() + ); + } + writeln!( + f, + " #[test]\n fn test_{name}() {{\n super::run_expand(\"{name}\", std::path::PathBuf::from(r\"{path}\"));\n }}", + name = name, + path = path.display() + ) + .unwrap(); + } + writeln!(f, "}}").unwrap(); +} diff --git a/noir-projects/noir-contract-snapshots/src/lib.rs b/noir-projects/noir-contract-snapshots/src/lib.rs new file mode 100644 index 000000000000..ee7fc1b5c1f7 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/src/lib.rs @@ -0,0 +1,2 @@ +// This crate exists only to host integration tests under `tests/`. +// See `tests/snapshots.rs` and `build.rs` for the snapshot harness. diff --git a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/Nargo.toml similarity index 68% rename from noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/Nargo.toml index d2f5cfdc1eab..da4774a995f2 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/Nargo.toml index b3882cc6718e..67924e498857 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/Nargo.toml index 40ed4eabd259..1f269b35f385 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/Nargo.toml index 7130df19571a..26dc88d27a96 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/Nargo.toml similarity index 68% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/Nargo.toml index e3c0421eff43..59aafcbdb88d 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/Nargo.toml similarity index 68% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/Nargo.toml index 35c56f6dc0ef..ff272f0651e4 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/Nargo.toml index ba1ea98efb15..3ee987f8d6ad 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/Nargo.toml similarity index 68% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/Nargo.toml index 31296f301ec6..e58946a6d681 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/Nargo.toml similarity index 66% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/Nargo.toml index ac377a90737c..ecc202de402f 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/Nargo.toml similarity index 66% rename from noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/Nargo.toml index 291f3c46342c..7b828f3c6b14 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/Nargo.toml new file mode 100644 index 000000000000..906fff22a0eb --- /dev/null +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "bob_token" +type = "contract" +authors = [""] + +[dependencies] +aztec = { path = "../../../../aztec-nr/aztec" } +balance_set = { path = "../../../../aztec-nr/balance-set" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/bob_token/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/bob_token/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/Nargo.toml similarity index 70% rename from noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/Nargo.toml index 9a28991054e9..1d0b0ee4ebed 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/Nargo.toml similarity index 71% rename from noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/Nargo.toml index 1ba8876ac6c4..5a93463ca0e9 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/Nargo.toml index 8f052fb53c2c..1eae6b6af3c8 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/Nargo.toml similarity index 72% rename from noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/Nargo.toml index 68a469c38437..86f7c26acbc0 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/Nargo.toml index d9076ac44554..14405987b386 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/Nargo.toml similarity index 66% rename from noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/Nargo.toml index 5849c6d94ea0..70a86d6d1ba3 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_event/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/Nargo.toml similarity index 70% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_event/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/Nargo.toml index fd5c446ab345..7004854044c4 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/invalid_event/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_event/src/invalid_event.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/src/invalid_event.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_event/src/invalid_event.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/src/invalid_event.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_event/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_event/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/Nargo.toml similarity index 72% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/Nargo.toml index 7e8025f4774d..fe12bc8fb0b1 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/Nargo.toml index 0d007ec76ca0..23b910e04b73 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_note/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/Nargo.toml similarity index 69% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_note/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/Nargo.toml index a94a89957382..f17604c48746 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/invalid_note/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_note/src/invalid_note.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/src/invalid_note.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_note/src/invalid_note.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/src/invalid_note.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_note/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/invalid_note/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/Nargo.toml index f72f5810797a..4c0448e82d09 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } \ No newline at end of file +aztec = { path = "../../../../aztec-nr/aztec" } \ No newline at end of file diff --git a/noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/Nargo.toml similarity index 66% rename from noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/Nargo.toml index b77dd5e5b4a7..01d1135d3b57 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json new file mode 100644 index 000000000000..59ae2162c3bf --- /dev/null +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json @@ -0,0 +1 @@ +{"noir_version":"1.0.0-beta.20+ad02a20cd80b3e8a6189722b11a625998e578435","name":"MarkedPublicUnconstrained","functions":[{"name":"offchain_receive","hash":"12116004815156287947","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]},"visibility":"private"}],"return_type":null,"error_types":{"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"}}},"bytecode":"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","debug_symbols":"tZnRbhs5DEX/xc95ECmJEvMrQVG4qVsYMJzATRZYBPn3JTO6st1CgtdOX6KTxHNMcUhJ9rytvm++vf78ut3/ePq1un94W307bHe77c+vu6fH9cv2aW9/fVsF/yFcV/fxzkZd3YuNMbSR2shtjG1MbcxtlDaWNtY2Nl9qvtR8qfmyva7YKPZ39ZHbaH4ihwywdyAPUQqgArRBCQACMCACEiADYC4wF5gLzBXmCnOFucJcYa4wV5grzBXmCrPCrDArzAqzwqzNXIJflR0IwAB/jTgIoADs3Tk4aAMKAAIwIALs3dkvpwwQQAG4uThoAw4AN6uDmaMHzxGQABkggAKoAG3gtbkAAWCOMEeYvUCjp8UrdIECcLNH6EX6AV6lC/jlHnOyFydysBcnFyZtkAPAwkjJgQERkAAZIIACcLPHk7WBBAAB3OyBSQQkgJurgwAKoAK0gTfIAgRws8/UG2SBBMgAM2dPgjfIAhVg5swG3iALEIABEZAAGeBmz6E3yAIVoA28QbInyhske7F5gywQAW72bHiDLCCAAqgAXaB6Ey3g5urAgAhIAF/pgoMACsAXO3LQBt5Wwg4EYEAE+BIqDm72t/C2WqAAKkAbeFstQAA3q0MEmLl4GN5WCwjAzMXf3dtqAW3gbbUAARgQAW6ODhkggAJwc3LQBt5WCxDAr8oOBVABfpXPy/trAQJ4PD5B768FEiADBFAAFWDm6vfL+2sBAjDAzfL+frfCJvn15bDZ+B55smvaXvq8Pmz2L6v7/etud7f6Z717/XjRr+f1/mN8WR/sv6bc7L/baMIf293G6f3ueHUYX0rBNt12ubFoV1A4l9BYknxx/lCkVLqgnF/P4+tjxgxiqccAiv6PWWjts7DlaziLNJbkXLU5sgQ5KnI8U+SxgoWRTLbDR1fIxTHYMaHHoDyMYaKww1RsCjsnhaGijhW2pzdDORWUcvE0So8h2647jIEm9zQy4XZEjnmQy7lBe13FUEeGSWEmYhgSRb3iftp2gkTYuj1OxMShft76UCgfJ5Ho4hi0TyKrhqtqKgQoJNBYQWXSoyqoKtKSuiOfdzlN6pIK9bXKTglDhc6SiSC0ni41crlBU19pKA8VPFkvmRMczHl4T5lnKx4fl+1M4zDipDBqd2Tbtk7C4HPHvDK0VwaHsWO2aqbcF83jTU3hysLQcWGU2T2J1O9JiiMFT6KQnHsusqaroiApiMLW8ZEiTla9lPtmXMZ1EWfbOQn3VU9P7+n5Xhpn9Zn7DcnxxBAvj4J7ZSU+afY/ophUJ3HFPkSRaBzHxBFL7PtQDXUch/xdBwmlnlOhEoe9Fic1qlmRET2t0T8c00jicQ2UROOuT7PdWY6HvjS8M1ND6kk9W71+M8z29xCx9KSQyngeEwdHzIMzXxUF177+VRnXaJkdG0Nfya1MxvOQT8iF3JwLuTkXcnsucrg9FzPHZbmYGm7OhQVf+zyErur2i3OR/67jwnzmm/M53ZO0zyNO1vGsn7Anzeqz9E+qKYxPsbODRqw4JrDdkqvOKon6KTafHEF/U0i89awis905KLrdkjneEyXPPifK8ZNm5SsdfSqmq2NHubXCp/m8qC5mx3nOWDCEZfx5tUyK0x5wIBX2ZCMOPjRPDZVxCrbHHXqVofR51HLFB3d7RNXP8jGMP/FOz1rST7AqJNed104dcVzf5RN2xFJuX8HLzfU9NYxX8C/26/pxezh77PjuqsN2/W23ab/+eN0/nvz35d9n/AePLZ8PT4+b76+HjZuOzy7tx0O1b5Wr8pe7lX1/+2Bn8DvhYr/51+8P1QpGA31591j+Aw=="},{"name":"sync_state","hash":"5670089859456161743","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"return_type":null,"error_types":{"361444214588792908":{"error_kind":"string","string":"attempt to multiply with overflow"},"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"1064022259863234536":{"error_kind":"fmtstring","length":101,"item_types":[{"kind":"integer","sign":"unsigned","width":32}]},"1998584279744703196":{"error_kind":"string","string":"attempt to subtract with overflow"},"5421095327929394772":{"error_kind":"string","string":"attempt to bit-shift with overflow"},"5449178635769758673":{"error_kind":"fmtstring","length":61,"item_types":[{"kind":"field"},{"kind":"field"}]},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"9791669845391776238":{"error_kind":"string","string":"0 has a square root; you cannot claim it is not square"},"9885968605480832328":{"error_kind":"string","string":"Attempted to read past the length of a CapsuleArray"},"10791800398362570014":{"error_kind":"string","string":"extend_from_bounded_vec out of bounds"},"10835969307644359280":{"error_kind":"fmtstring","length":40,"item_types":[]},"11021520179822076911":{"error_kind":"string","string":"Attempted to delete past the length of a CapsuleArray"},"12820178569648940736":{"error_kind":"fmtstring","length":48,"item_types":[{"kind":"field"},{"kind":"field"}]},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"},"17110599087403377004":{"error_kind":"fmtstring","length":98,"item_types":[]},"17655676068928457687":{"error_kind":"string","string":"Reader did not read all data"}}},"bytecode":"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","debug_symbols":"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"}],"outputs":{"structs":{"functions":[{"kind":"struct","path":"MarkedPublicUnconstrained::offchain_receive_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"MarkedPublicUnconstrained::offchain_receive_parameters","fields":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]},{"kind":"struct","path":"MarkedPublicUnconstrained::sync_state_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"MarkedPublicUnconstrained::sync_state_parameters","fields":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}]},"globals":{}},"file_map":{"6":{"source":"use crate::{cmp::Eq, convert::From, runtime::is_unconstrained, static_assert};\n\n/// A `BoundedVec` is a growable storage similar to a built-in vector except that it\n/// is bounded with a maximum possible length. `BoundedVec` is also not\n/// subject to the same restrictions vectors are (notably, nested vectors are disallowed).\n///\n/// Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by\n/// pushing an additional element is also more efficient - the length only needs to be increased\n/// by one.\n///\n/// For these reasons `BoundedVec` should generally be preferred over vectors when there\n/// is a reasonable maximum bound that can be placed on the vector.\n///\n/// Example:\n///\n/// ```noir\n/// let mut vector: BoundedVec = BoundedVec::new();\n/// for i in 0..5 {\n/// vector.push(i);\n/// }\n/// assert(vector.len() == 5);\n/// assert(vector.max_len() == 10);\n/// ```\npub struct BoundedVec {\n storage: [T; MaxLen],\n len: u32,\n}\n\nimpl BoundedVec {\n /// Creates a new, empty vector of length zero.\n ///\n /// Since this container is backed by an array internally, it still needs an initial value\n /// to give each element. To resolve this, each element is zeroed internally. This value\n /// is guaranteed to be inaccessible unless `get_unchecked` is used.\n ///\n /// Example:\n ///\n /// ```noir\n /// let empty_vector: BoundedVec = BoundedVec::new();\n /// assert(empty_vector.len() == 0);\n /// ```\n ///\n /// Note that whenever calling `new` the maximum length of the vector should always be specified\n /// via a type signature:\n ///\n /// ```noir\n /// fn good() -> BoundedVec {\n /// // Ok! MaxLen is specified with a type annotation\n /// let v1: BoundedVec = BoundedVec::new();\n /// let v2 = BoundedVec::new();\n ///\n /// // Ok! MaxLen is known from the type of `good`'s return value\n /// v2\n /// }\n ///\n /// fn bad() {\n /// // Error: Type annotation needed\n /// // The compiler can't infer `MaxLen` from the following code:\n /// let mut v3 = BoundedVec::new();\n /// v3.push(5);\n /// }\n /// ```\n ///\n /// This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions\n /// but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a\n /// constraint failure at runtime when the vec is pushed to.\n pub fn new() -> Self {\n let zeroed = crate::mem::zeroed();\n BoundedVec { storage: [zeroed; MaxLen], len: 0 }\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this\n /// will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// let last = v.get(v.len() - 1);\n /// assert(first != last);\n /// }\n /// ```\n pub fn get(&self, index: u32) -> T {\n assert(index < self.len, \"Attempted to read past end of BoundedVec\");\n self.get_unchecked(index)\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero, without\n /// performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element,\n /// it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn sum_of_first_three(v: BoundedVec) -> u32 {\n /// // Always ensure the length is larger than the largest\n /// // index passed to get_unchecked\n /// assert(v.len() > 2);\n /// let first = v.get_unchecked(0);\n /// let second = v.get_unchecked(1);\n /// let third = v.get_unchecked(2);\n /// first + second + third\n /// }\n /// ```\n pub fn get_unchecked(&self, index: u32) -> T {\n self.storage[index]\n }\n\n /// Writes an element to the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// assert(first != 42);\n /// v.set(0, 42);\n /// let new_first = v.get(0);\n /// assert(new_first == 42);\n /// }\n /// ```\n pub fn set(&mut self, index: u32, value: T) {\n assert(index < self.len, \"Attempted to write past end of BoundedVec\");\n self.set_unchecked(index, value)\n }\n\n /// Writes an element to the vector at the given index, starting from zero, without performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element, it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn set_unchecked_example() {\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([1, 2]);\n ///\n /// // Here we're safely writing within the valid range of `vec`\n /// // `vec` now has the value [42, 2]\n /// vec.set_unchecked(0, 42);\n ///\n /// // We can then safely read this value back out of `vec`.\n /// // Notice that we use the checked version of `get` which would prevent reading unsafe values.\n /// assert_eq(vec.get(0), 42);\n ///\n /// // We've now written past the end of `vec`.\n /// // As this index is still within the maximum potential length of `v`,\n /// // it won't cause a constraint failure.\n /// vec.set_unchecked(2, 42);\n /// println(vec);\n ///\n /// // This will write past the end of the maximum potential length of `vec`,\n /// // it will then trigger a constraint failure.\n /// vec.set_unchecked(5, 42);\n /// println(vec);\n /// }\n /// ```\n pub fn set_unchecked(&mut self, index: u32, value: T) {\n self.storage[index] = value;\n }\n\n /// Pushes an element to the end of the vector. This increases the length\n /// of the vector by one.\n ///\n /// Panics if the new length of the vector will be greater than the max length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// v.push(1);\n /// v.push(2);\n ///\n /// // Panics with failed assertion \"push out of bounds\"\n /// v.push(3);\n /// ```\n pub fn push(&mut self, elem: T) {\n assert(self.len < MaxLen, \"push out of bounds\");\n\n self.storage[self.len] = elem;\n self.len += 1;\n }\n\n /// Returns the current length of this vector\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// assert(v.len() == 0);\n ///\n /// v.push(100);\n /// assert(v.len() == 1);\n ///\n /// v.push(200);\n /// v.push(300);\n /// v.push(400);\n /// assert(v.len() == 4);\n ///\n /// let _ = v.pop();\n /// let _ = v.pop();\n /// assert(v.len() == 2);\n /// ```\n pub fn len(&self) -> u32 {\n self.len\n }\n\n /// Returns the maximum length of this vector. This is always\n /// equal to the `MaxLen` parameter this vector was initialized with.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.max_len() == 5);\n /// v.push(10);\n /// assert(v.max_len() == 5);\n /// ```\n pub fn max_len(_self: &BoundedVec) -> u32 {\n MaxLen\n }\n\n /// Returns the internal array within this vector.\n ///\n /// Since arrays in Noir are immutable, mutating the returned storage array will not mutate\n /// the storage held internally by this vector.\n ///\n /// Note that uninitialized elements may be zeroed out!\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.storage() == [0, 0, 0, 0, 0]);\n ///\n /// v.push(57);\n /// assert(v.storage() == [57, 0, 0, 0, 0]);\n /// ```\n pub fn storage(self) -> [T; MaxLen] {\n self.storage\n }\n\n /// Pushes each element from the given array to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([2, 4]);\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_array(&mut self, array: [T; Len]) {\n let new_len = self.len + array.len();\n assert(new_len <= MaxLen, \"extend_from_array out of bounds\");\n for i in 0..array.len() {\n self.storage[self.len + i] = array[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the given vector to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_vector([2, 4].as_vector());\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_vector(&mut self, vector: [T]) {\n let new_len = self.len + vector.len();\n assert(new_len <= MaxLen, \"extend_from_vector out of bounds\");\n for i in 0..vector.len() {\n self.storage[self.len + i] = vector[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the other vector to this vector. The length of\n /// the other vector is left unchanged.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// ```noir\n /// let mut v1: BoundedVec = BoundedVec::new();\n /// let mut v2: BoundedVec = BoundedVec::new();\n ///\n /// v2.extend_from_array([1, 2, 3]);\n /// v1.extend_from_bounded_vec(v2);\n ///\n /// assert(v1.storage() == [1, 2, 3, 0, 0]);\n /// assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]);\n /// ```\n pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) {\n let append_len = vec.len();\n let new_len = self.len + append_len;\n assert(new_len <= MaxLen, \"extend_from_bounded_vec out of bounds\");\n\n if is_unconstrained() {\n for i in 0..append_len {\n self.storage[self.len + i] = vec.get_unchecked(i);\n }\n } else {\n // The source vector can be longer than the destination, or vice versa;\n // regardless we will only ever be able to read or write whichever is\n // the shorter max length of the two. We asserted that the actual content fits,\n // but the capacity of the source vector could be higher.\n let max = crate::cmp::min(Len, MaxLen);\n\n // Save the last item in case we have to do a fixup on an already full array.\n let last = if MaxLen > 0 {\n self.storage[MaxLen - 1]\n } else {\n crate::mem::zeroed()\n };\n\n for src in 0..max {\n // Since we are iterating to the static capacity of the arrays,\n // the destination could be out of bounds. If that's the case,\n // overwrite the last item, which we'll fixup in the end.\n // NB using cmp::min resulted in more opcodes here.\n let mut dst = self.len + src;\n if dst >= MaxLen { dst = MaxLen - 1; };\n // Assigning the source or zeroed to avoid having to merge arrays in SSA.\n self.storage[dst] = if src < append_len {\n vec.get_unchecked(src)\n } else {\n last\n }\n }\n\n // Fixup the last item if we have to.\n if MaxLen > 0 {\n self.storage[MaxLen - 1] = if (self.len + append_len == MaxLen) & (append_len > 0) {\n vec.get_unchecked(append_len - 1)\n } else {\n last\n }\n }\n }\n self.len = new_len;\n }\n\n /// Creates a new vector, populating it with values derived from an array input.\n /// The maximum length of the vector is determined based on the type signature.\n ///\n /// Example:\n ///\n /// ```noir\n /// let bounded_vec: BoundedVec = BoundedVec::from_array([1, 2, 3])\n /// ```\n pub fn from_array(array: [T; Len]) -> Self {\n static_assert(Len <= MaxLen, \"from array out of bounds\");\n let mut vec: BoundedVec = BoundedVec::new();\n vec.extend_from_array(array);\n vec\n }\n\n /// Pops the element at the end of the vector. This will decrease the length\n /// of the vector by one.\n ///\n /// Panics if the vector is empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.push(1);\n /// v.push(2);\n ///\n /// let two = v.pop();\n /// let one = v.pop();\n ///\n /// assert(two == 2);\n /// assert(one == 1);\n ///\n /// // error: cannot pop from an empty vector\n /// let _ = v.pop();\n /// ```\n pub fn pop(&mut self) -> T {\n assert(self.len > 0, \"cannot pop from an empty vector\");\n self.len -= 1;\n\n let elem = self.storage[self.len];\n self.storage[self.len] = crate::mem::zeroed();\n elem\n }\n\n /// Returns true if the given predicate returns true for any element\n /// in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.extend_from_array([2, 4, 6]);\n ///\n /// let all_even = !v.any(|elem: u32| elem % 2 != 0);\n /// assert(all_even);\n /// ```\n pub fn any(self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n if is_unconstrained() {\n for i in 0..self.len {\n ret |= predicate(self.storage[i]);\n }\n } else {\n let mut exceeded_len = false;\n for i in 0..MaxLen {\n exceeded_len |= i == self.len;\n if !exceeded_len {\n ret |= predicate(self.storage[i]);\n }\n }\n }\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.map(|value| value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element\n /// in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.mapi(|i, value| i + value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(i, self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Calls a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_each(|value| result.push(value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Calls a closure on each element in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_eachi(|i, value| result.push(i + value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(i, self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function will zero out any elements at or past index `len` of `array`.\n /// This incurs an extra runtime cost of O(MaxLen). If you are sure your array is\n /// zeroed after that index, you can use [`from_parts_unchecked`][Self::from_parts_unchecked] to remove the extra loop.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n /// ```\n pub fn from_parts(mut array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n let zeroed = crate::mem::zeroed();\n\n if is_unconstrained() {\n for i in len..MaxLen {\n array[i] = zeroed;\n }\n } else {\n for i in 0..MaxLen {\n if i >= len {\n array[i] = zeroed;\n }\n }\n }\n\n BoundedVec { storage: array, len }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function is unsafe because it expects all elements past the `len` index\n /// of `array` to be zeroed, but does not check for this internally. Use `from_parts`\n /// for a safe version of this function which does zero out any indices past the\n /// given length. Invalidating this assumption can notably cause `BoundedVec::eq`\n /// to give incorrect results since it will check even elements past `len`.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n ///\n /// // invalid use!\n /// let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n /// let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n ///\n /// // both vecs have length 3 so we'd expect them to be equal, but this\n /// // fails because elements past the length are still checked in eq\n /// assert_eq(vec1, vec2); // fails\n /// ```\n pub fn from_parts_unchecked(array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n BoundedVec { storage: array, len }\n }\n}\n\nimpl Eq for BoundedVec\nwhere\n T: Eq,\n{\n fn eq(self, other: BoundedVec) -> bool {\n // TODO: https://github.com/noir-lang/noir/issues/4837\n //\n // We make the assumption that the user has used the proper interface for working with `BoundedVec`s\n // rather than directly manipulating the internal fields as this can result in an inconsistent internal state.\n if self.len == other.len {\n self.storage == other.storage\n } else {\n false\n }\n }\n}\n\nimpl From<[T; Len]> for BoundedVec {\n fn from(array: [T; Len]) -> BoundedVec {\n BoundedVec::from_array(array)\n }\n}\n\nmod bounded_vec_tests {\n\n mod get {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_elements_past_end_of_vec() {\n let vec: BoundedVec = BoundedVec::new();\n\n let _ = vec.get(0);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_beyond_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let _ = vec.get(3);\n }\n\n #[test]\n fn get_works_within_bounds() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(2), 3);\n assert_eq(vec.get(4), 5);\n }\n\n #[test]\n fn get_unchecked_works() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(0), 1);\n assert_eq(vec.get_unchecked(2), 3);\n }\n\n #[test]\n fn get_unchecked_works_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(4), 0);\n }\n }\n\n mod set {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn set_updates_values_properly() {\n let mut vec = BoundedVec::from_array([0, 0, 0, 0, 0]);\n\n vec.set(0, 42);\n assert_eq(vec.storage, [42, 0, 0, 0, 0]);\n\n vec.set(1, 43);\n assert_eq(vec.storage, [42, 43, 0, 0, 0]);\n\n vec.set(2, 44);\n assert_eq(vec.storage, [42, 43, 44, 0, 0]);\n\n vec.set(1, 10);\n assert_eq(vec.storage, [42, 10, 44, 0, 0]);\n\n vec.set(0, 0);\n assert_eq(vec.storage, [0, 10, 44, 0, 0]);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_writing_elements_past_end_of_vec() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.set(0, 42);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_setting_beyond_length() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.set(3, 4);\n }\n\n #[test]\n fn set_unchecked_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(0, 10);\n assert_eq(vec.get(0), 10);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn set_unchecked_operations_past_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(3, 40);\n assert_eq(vec.get(3), 40);\n }\n\n #[test]\n fn set_preserves_other_elements() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n vec.set(2, 30);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 30);\n assert_eq(vec.get(3), 4);\n assert_eq(vec.get(4), 5);\n }\n }\n\n mod any {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn returns_false_if_predicate_not_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, false, false]);\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn returns_true_if_predicate_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, true, true]);\n let result = vec.any(|value| value);\n\n assert(result);\n }\n\n #[test]\n fn returns_false_on_empty_boundedvec() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn any_with_complex_predicates() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n assert(vec.any(|x| x > 3));\n assert(!vec.any(|x| x > 10));\n assert(vec.any(|x| x % 2 == 0)); // has a even number\n assert(vec.any(|x| x == 3)); // has a specific value\n }\n\n #[test]\n fn any_with_partial_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n assert(vec.any(|x| x == 1));\n assert(vec.any(|x| x == 2));\n assert(!vec.any(|x| x == 3));\n }\n }\n\n mod map {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-map-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| value * 2);\n // docs:end:bounded-vec-map-example\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.map(|value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn map_with_conditional_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.map(|x| if x % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([1, 4, 3, 8]);\n assert_eq(result, expected);\n }\n\n #[test]\n fn map_preserves_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|x| x * 2);\n\n assert_eq(result.len(), vec.len());\n assert_eq(result.max_len(), vec.max_len());\n }\n\n #[test]\n fn map_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.map(|x| x * 2);\n assert_eq(result, vec);\n assert_eq(result.len(), 0);\n assert_eq(result.max_len(), 5);\n }\n }\n\n mod mapi {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-mapi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| i + value * 2);\n // docs:end:bounded-vec-mapi-example\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.mapi(|_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn mapi_with_index_branching_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.mapi(|i, x| if i % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([2, 2, 6, 4]);\n assert_eq(result, expected);\n }\n }\n\n mod for_each {\n use crate::collections::bounded_vec::BoundedVec;\n\n // map in terms of for_each\n fn for_each_map(\n input: BoundedVec,\n f: fn[Env](T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_each(|x| output_ref.push(f(x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-each-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_each(|value| { *acc_ref += value; });\n // docs:end:bounded-vec-for-each-example\n assert_eq(acc, 6);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| value * 2);\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_each_map(vec, |value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_each_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_each(|_| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_each_with_side_effects() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let mut seen = BoundedVec::::new();\n let seen_ref = &mut seen;\n vec.for_each(|x| seen_ref.push(x));\n assert_eq(seen, vec);\n }\n }\n\n mod for_eachi {\n use crate::collections::bounded_vec::BoundedVec;\n\n // mapi in terms of for_eachi\n fn for_eachi_mapi(\n input: BoundedVec,\n f: fn[Env](u32, T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_eachi(|i, x| output_ref.push(f(i, x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-eachi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_eachi(|i, value| { *acc_ref += i * value; });\n // docs:end:bounded-vec-for-eachi-example\n\n // 0 * 1 + 1 * 2 + 2 * 3\n assert_eq(acc, 8);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| i + value * 2);\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_eachi_mapi(vec, |_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_eachi_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_eachi(|_, _| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_eachi_with_index_tracking() {\n let vec: BoundedVec = BoundedVec::from_array([10, 20, 30]);\n let mut indices = BoundedVec::::new();\n let indices_ref = &mut indices;\n vec.for_eachi(|i, _| indices_ref.push(i));\n\n let expected = BoundedVec::from_array([0, 1, 2]);\n assert_eq(indices, expected);\n }\n\n }\n\n mod from_array {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty() {\n let empty_array: [Field; 0] = [];\n let bounded_vec = BoundedVec::from_array([]);\n\n assert_eq(bounded_vec.max_len(), 0);\n assert_eq(bounded_vec.len(), 0);\n assert_eq(bounded_vec.storage(), empty_array);\n }\n\n #[test]\n fn equal_len() {\n let array = [1, 2, 3];\n let bounded_vec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 3);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.storage(), array);\n }\n\n #[test]\n fn max_len_greater_then_array_len() {\n let array = [1, 2, 3];\n let bounded_vec: BoundedVec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n assert_eq(bounded_vec.get(2), 3);\n }\n\n #[test(should_fail_with = \"from array out of bounds\")]\n fn max_len_lower_then_array_len() {\n let _: BoundedVec = BoundedVec::from_array([0; 3]);\n }\n\n #[test]\n fn from_array_preserves_order() {\n let array = [5, 3, 1, 4, 2];\n let vec: BoundedVec = BoundedVec::from_array(array);\n for i in 0..array.len() {\n assert_eq(vec.get(i), array[i]);\n }\n }\n\n #[test]\n fn from_array_with_different_types() {\n let bool_array = [true, false, true];\n let bool_vec: BoundedVec = BoundedVec::from_array(bool_array);\n assert_eq(bool_vec.len(), 3);\n assert_eq(bool_vec.get(0), true);\n assert_eq(bool_vec.get(1), false);\n }\n }\n\n mod trait_from {\n use crate::collections::bounded_vec::BoundedVec;\n use crate::convert::From;\n\n #[test]\n fn simple() {\n let array = [1, 2];\n let bounded_vec: BoundedVec = BoundedVec::from(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 2);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n }\n }\n\n mod trait_eq {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty_equality() {\n let bounded_vec1: BoundedVec = BoundedVec::new();\n let bounded_vec2: BoundedVec = BoundedVec::new();\n\n assert_eq(bounded_vec1, bounded_vec2);\n }\n\n #[test]\n fn inequality() {\n let mut bounded_vec1: BoundedVec = BoundedVec::new();\n let mut bounded_vec2: BoundedVec = BoundedVec::new();\n bounded_vec1.push(1);\n bounded_vec2.push(2);\n\n assert(bounded_vec1 != bounded_vec2);\n }\n }\n\n mod from_parts {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn from_parts() {\n // docs:start:from-parts\n let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // Any elements past the given length are zeroed out, so these\n // two BoundedVecs will be completely equal\n let vec1: BoundedVec = BoundedVec::from_parts([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts([1, 2, 3, 2], 3);\n assert_eq(vec1, vec2);\n // docs:end:from-parts\n }\n\n #[test]\n fn from_parts_unchecked() {\n // docs:start:from-parts-unchecked\n let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // invalid use!\n let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n\n // both vecs have length 3 so we'd expect them to be equal, but this\n // fails because elements past the length are still checked in eq\n assert(vec1 != vec2);\n // docs:end:from-parts-unchecked\n }\n }\n\n mod push_pop {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn push_and_pop_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n assert_eq(vec.len(), 0);\n\n vec.push(1);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 1);\n\n vec.push(2);\n assert_eq(vec.len(), 2);\n assert_eq(vec.get(1), 2);\n\n let popped = vec.pop();\n assert_eq(popped, 2);\n assert_eq(vec.len(), 1);\n\n let popped2 = vec.pop();\n assert_eq(popped2, 1);\n assert_eq(vec.len(), 0);\n }\n\n #[test(should_fail_with = \"push out of bounds\")]\n fn push_to_full_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n vec.push(3); // should panic\n }\n\n #[test(should_fail_with = \"cannot pop from an empty vector\")]\n fn pop_from_empty_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n let _ = vec.pop(); // should panic\n }\n\n #[test]\n fn push_pop_cycle() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // push to full\n vec.push(1);\n vec.push(2);\n vec.push(3);\n assert_eq(vec.len(), 3);\n\n // pop all\n assert_eq(vec.pop(), 3);\n assert_eq(vec.pop(), 2);\n assert_eq(vec.pop(), 1);\n assert_eq(vec.len(), 0);\n\n // push again\n vec.push(4);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 4);\n }\n }\n\n mod extend {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn extend_from_array() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3]);\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3].as_vector());\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec() {\n // The source deliberately has a higher capacity,\n // to make sure we are not trying to assign out-of-bounds.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_limit() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_full_and_empty() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_zero_len() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_last_zeroed() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get_unchecked(3), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_empty_self() {\n // self.len == 0 with Len > MaxLen: the loop doesn't reach\n // the last storage slot, so the fixup must write it.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_equal_capacity() {\n // Len == MaxLen, fills to capacity.\n let mut vec1: BoundedVec = BoundedVec::new();\n vec1.push(1);\n let vec2: BoundedVec = BoundedVec::from_array([2, 3, 4]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 4);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n assert_eq(vec1.get(3), 4);\n }\n\n #[test(should_fail_with = \"extend_from_array out of bounds\")]\n fn extend_array_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3, 4]); // should panic\n }\n\n #[test(should_fail_with = \"extend_from_vector out of bounds\")]\n fn extend_vector_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3, 4].as_vector()); // S]should panic\n }\n\n #[test(should_fail_with = \"extend_from_bounded_vec out of bounds\")]\n fn extend_bounded_vec_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n let other: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n vec.extend_from_bounded_vec(other); // should panic\n }\n\n #[test]\n fn extend_with_empty_collections() {\n let mut vec: BoundedVec = BoundedVec::new();\n let original_len = vec.len();\n\n vec.extend_from_array([]);\n assert_eq(vec.len(), original_len);\n\n vec.extend_from_vector([].as_vector());\n assert_eq(vec.len(), original_len);\n\n let empty: BoundedVec = BoundedVec::new();\n vec.extend_from_bounded_vec(empty);\n assert_eq(vec.len(), original_len);\n }\n }\n\n mod storage {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn storage_consistency() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // test initial storage state\n assert_eq(vec.storage(), [0, 0, 0, 0, 0]);\n\n vec.push(1);\n vec.push(2);\n\n // test storage after modifications\n assert_eq(vec.storage(), [1, 2, 0, 0, 0]);\n\n // storage doesn't change length\n assert_eq(vec.len(), 2);\n assert_eq(vec.max_len(), 5);\n }\n\n #[test]\n fn storage_after_pop() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n let _ = vec.pop();\n // after pop, the last element should be zeroed\n assert_eq(vec.storage(), [1, 2, 0]);\n assert_eq(vec.len(), 2);\n }\n\n #[test]\n fn vector_immutable() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let storage = vec.storage();\n\n assert_eq(storage, [1, 2, 3]);\n\n // Verify that the original vector is unchanged\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n }\n}\n","path":"std/collections/bounded_vec.nr","function_locations":[{"start":2599,"name":"BoundedVec::new"},{"start":3202,"name":"BoundedVec::get"},{"start":4110,"name":"BoundedVec::get_unchecked"},{"start":4693,"name":"BoundedVec::set"},{"start":6221,"name":"BoundedVec::set_unchecked"},{"start":6759,"name":"BoundedVec::push"},{"start":7367,"name":"BoundedVec::len"},{"start":7808,"name":"BoundedVec::max_len"},{"start":8406,"name":"BoundedVec::storage"},{"start":8962,"name":"BoundedVec::extend_from_array"},{"start":9733,"name":"BoundedVec::extend_from_vector"},{"start":10678,"name":"BoundedVec::extend_from_bounded_vec"},{"start":13073,"name":"BoundedVec::from_array"},{"start":13816,"name":"BoundedVec::pop"},{"start":14439,"name":"BoundedVec::any"},{"start":15355,"name":"BoundedVec::map"},{"start":16355,"name":"BoundedVec::mapi"},{"start":17313,"name":"BoundedVec::for_each"},{"start":18118,"name":"BoundedVec::for_eachi"},{"start":19117,"name":"BoundedVec::from_parts"},{"start":20766,"name":"BoundedVec::from_parts_unchecked"},{"start":20978,"name":">::eq"},{"start":21549,"name":" for BoundedVec>::from"},{"start":21832,"name":"bounded_vec_tests::get::panics_when_reading_elements_past_end_of_vec"},{"start":22067,"name":"bounded_vec_tests::get::panics_when_reading_beyond_length"},{"start":22242,"name":"bounded_vec_tests::get::get_works_within_bounds"},{"start":22501,"name":"bounded_vec_tests::get::get_unchecked_works"},{"start":22745,"name":"bounded_vec_tests::get::get_unchecked_works_past_len"},{"start":23018,"name":"bounded_vec_tests::set::set_updates_values_properly"},{"start":23656,"name":"bounded_vec_tests::set::panics_when_writing_elements_past_end_of_vec"},{"start":23891,"name":"bounded_vec_tests::set::panics_when_setting_beyond_length"},{"start":24066,"name":"bounded_vec_tests::set::set_unchecked_operations"},{"start":24398,"name":"bounded_vec_tests::set::set_unchecked_operations_past_len"},{"start":24662,"name":"bounded_vec_tests::set::set_preserves_other_elements"},{"start":25130,"name":"bounded_vec_tests::any::returns_false_if_predicate_not_satisfied"},{"start":25384,"name":"bounded_vec_tests::any::returns_true_if_predicate_satisfied"},{"start":25633,"name":"bounded_vec_tests::any::returns_false_on_empty_boundedvec"},{"start":25844,"name":"bounded_vec_tests::any::any_with_complex_predicates"},{"start":26207,"name":"bounded_vec_tests::any::any_with_partial_vector"},{"start":26594,"name":"bounded_vec_tests::map::applies_function_correctly"},{"start":27016,"name":"bounded_vec_tests::map::applies_function_that_changes_return_type"},{"start":27364,"name":"bounded_vec_tests::map::does_not_apply_function_past_len"},{"start":27737,"name":"bounded_vec_tests::map::map_with_conditional_logic"},{"start":28061,"name":"bounded_vec_tests::map::map_preserves_length"},{"start":28353,"name":"bounded_vec_tests::map::map_on_empty_vector"},{"start":28727,"name":"bounded_vec_tests::mapi::applies_function_correctly"},{"start":29160,"name":"bounded_vec_tests::mapi::applies_function_that_changes_return_type"},{"start":29517,"name":"bounded_vec_tests::mapi::does_not_apply_function_past_len"},{"start":29899,"name":"bounded_vec_tests::mapi::mapi_with_index_branching_logic"},{"start":30458,"name":"bounded_vec_tests::for_each::for_each_map"},{"start":30688,"name":"bounded_vec_tests::for_each::smoke_test"},{"start":31096,"name":"bounded_vec_tests::for_each::applies_function_correctly"},{"start":31430,"name":"bounded_vec_tests::for_each::applies_function_that_changes_return_type"},{"start":31788,"name":"bounded_vec_tests::for_each::does_not_apply_function_past_len"},{"start":32169,"name":"bounded_vec_tests::for_each::for_each_on_empty_vector"},{"start":32455,"name":"bounded_vec_tests::for_each::for_each_with_side_effects"},{"start":33012,"name":"bounded_vec_tests::for_eachi::for_eachi_mapi"},{"start":33249,"name":"bounded_vec_tests::for_eachi::smoke_test"},{"start":33705,"name":"bounded_vec_tests::for_eachi::applies_function_correctly"},{"start":34049,"name":"bounded_vec_tests::for_eachi::applies_function_that_changes_return_type"},{"start":34417,"name":"bounded_vec_tests::for_eachi::does_not_apply_function_past_len"},{"start":34804,"name":"bounded_vec_tests::for_eachi::for_eachi_on_empty_vector"},{"start":35097,"name":"bounded_vec_tests::for_eachi::for_eachi_with_index_tracking"},{"start":35574,"name":"bounded_vec_tests::from_array::empty"},{"start":35884,"name":"bounded_vec_tests::from_array::equal_len"},{"start":36201,"name":"bounded_vec_tests::from_array::max_len_greater_then_array_len"},{"start":36672,"name":"bounded_vec_tests::from_array::max_len_lower_then_array_len"},{"start":36815,"name":"bounded_vec_tests::from_array::from_array_preserves_order"},{"start":37104,"name":"bounded_vec_tests::from_array::from_array_with_different_types"},{"start":37541,"name":"bounded_vec_tests::trait_from::simple"},{"start":37979,"name":"bounded_vec_tests::trait_eq::empty_equality"},{"start":38228,"name":"bounded_vec_tests::trait_eq::inequality"},{"start":38637,"name":"bounded_vec_tests::from_parts::from_parts"},{"start":39227,"name":"bounded_vec_tests::from_parts::from_parts_unchecked"},{"start":40009,"name":"bounded_vec_tests::push_pop::push_and_pop_operations"},{"start":40635,"name":"bounded_vec_tests::push_pop::push_to_full_vector"},{"start":40909,"name":"bounded_vec_tests::push_pop::pop_from_empty_vector"},{"start":41078,"name":"bounded_vec_tests::push_pop::push_pop_cycle"},{"start":41724,"name":"bounded_vec_tests::extend::extend_from_array"},{"start":42070,"name":"bounded_vec_tests::extend::extend_from_vector"},{"start":42434,"name":"bounded_vec_tests::extend::extend_from_bounded_vec"},{"start":43055,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_limit"},{"start":43569,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_full_and_empty"},{"start":44073,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_zero_len"},{"start":44367,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_last_zeroed"},{"start":44792,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_empty_self"},{"start":45359,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_equal_capacity"},{"start":45946,"name":"bounded_vec_tests::extend::extend_array_beyond_max_len"},{"start":46224,"name":"bounded_vec_tests::extend::extend_vector_beyond_max_len"},{"start":46527,"name":"bounded_vec_tests::extend::extend_bounded_vec_beyond_max_len"},{"start":46813,"name":"bounded_vec_tests::extend::extend_with_empty_collections"},{"start":47413,"name":"bounded_vec_tests::storage::storage_consistency"},{"start":47915,"name":"bounded_vec_tests::storage::storage_after_pop"},{"start":48233,"name":"bounded_vec_tests::storage::vector_immutable"}]},"16":{"source":"use crate::field::field_less_than;\nuse crate::runtime::is_unconstrained;\n\n// The low and high decomposition of the field modulus\npub(crate) global PLO: Field = 53438638232309528389504892708671455233;\npub(crate) global PHI: Field = 64323764613183177041862057485226039389;\n\npub(crate) global TWO_POW_128: Field = 0x100000000000000000000000000000000;\n\n// Decomposes a single field into two 16 byte fields.\nfn compute_decomposition(x: Field) -> (Field, Field) {\n // Here's we're taking advantage of truncating 128 bit limbs from the input field\n // and then subtracting them from the input such the field division is equivalent to integer division.\n let low = (x as u128) as Field;\n let high = (x - low) / TWO_POW_128;\n\n (low, high)\n}\n\npub(crate) unconstrained fn decompose_hint(x: Field) -> (Field, Field) {\n compute_decomposition(x)\n}\n\nunconstrained fn lte_hint(x: Field, y: Field) -> bool {\n if x == y {\n true\n } else {\n field_less_than(x, y)\n }\n}\n\n// Assert that (alo > blo && ahi >= bhi) || (alo <= blo && ahi > bhi)\nfn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) {\n let (alo, ahi) = a;\n let (blo, bhi) = b;\n // Safety: borrow is enforced to be boolean due to its type.\n // if borrow is 0, it asserts that (alo > blo && ahi >= bhi)\n // if borrow is 1, it asserts that (alo <= blo && ahi > bhi)\n unsafe {\n let borrow = lte_hint(alo, blo);\n\n let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128;\n let rhi = ahi - bhi - (borrow as Field);\n\n rlo.assert_max_bit_size::<128>();\n rhi.assert_max_bit_size::<128>();\n }\n}\n\n/// Decompose a single field into two 16 byte fields.\npub fn decompose(x: Field) -> (Field, Field) {\n if is_unconstrained() {\n compute_decomposition(x)\n } else {\n // Safety: decomposition is properly checked below\n unsafe {\n // Take hints of the decomposition\n let (xlo, xhi) = decompose_hint(x);\n\n // Range check the limbs\n xlo.assert_max_bit_size::<128>();\n xhi.assert_max_bit_size::<128>();\n\n // Check that the decomposition is correct\n assert_eq(x, xlo + TWO_POW_128 * xhi);\n\n // Assert that the decomposition of P is greater than the decomposition of x\n assert_gt_limbs((PLO, PHI), (xlo, xhi));\n (xlo, xhi)\n }\n }\n}\n\npub fn assert_gt(a: Field, b: Field) {\n if is_unconstrained() {\n assert(\n // Safety: already unconstrained\n unsafe { field_less_than(b, a) },\n );\n } else {\n // Decompose a and b\n let a_limbs = decompose(a);\n let b_limbs = decompose(b);\n\n // Assert that a_limbs is greater than b_limbs\n assert_gt_limbs(a_limbs, b_limbs)\n }\n}\n\npub fn assert_lt(a: Field, b: Field) {\n assert_gt(b, a);\n}\n\npub fn gt(a: Field, b: Field) -> bool {\n if is_unconstrained() {\n // Safety: unsafe in unconstrained\n unsafe {\n field_less_than(b, a)\n }\n } else if a == b {\n false\n } else {\n // Safety: Take a hint of the comparison and verify it\n unsafe {\n if field_less_than(a, b) {\n assert_gt(b, a);\n false\n } else {\n assert_gt(a, b);\n true\n }\n }\n }\n}\n\npub fn lt(a: Field, b: Field) -> bool {\n gt(b, a)\n}\n\nmod tests {\n // TODO: Allow imports from \"super\"\n use crate::field::bn254::{assert_gt, decompose, gt, lt, lte_hint, PHI, PLO, TWO_POW_128};\n\n #[test]\n fn check_decompose() {\n assert_eq(decompose(TWO_POW_128), (0, 1));\n assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1));\n assert_eq(decompose(0x1234567890), (0x1234567890, 0));\n }\n\n #[test]\n unconstrained fn check_lte_hint() {\n assert(lte_hint(0, 1));\n assert(lte_hint(0, 0x100));\n assert(lte_hint(0x100, TWO_POW_128 - 1));\n assert(!lte_hint(0 - 1, 0));\n\n assert(lte_hint(0, 0));\n assert(lte_hint(0x100, 0x100));\n assert(lte_hint(0 - 1, 0 - 1));\n }\n\n #[test]\n fn check_gt() {\n assert(gt(1, 0));\n assert(gt(0x100, 0));\n assert(gt((0 - 1), (0 - 2)));\n assert(gt(TWO_POW_128, 0));\n assert(!gt(0, 0));\n assert(!gt(0, 0x100));\n assert(gt(0 - 1, 0 - 2));\n assert(!gt(0 - 2, 0 - 1));\n assert_gt(0 - 1, 0);\n }\n\n #[test]\n fn check_plo_phi() {\n assert_eq(PLO + PHI * TWO_POW_128, 0);\n let p_bytes = crate::field::modulus_le_bytes();\n let mut p_low: Field = 0;\n let mut p_high: Field = 0;\n\n let mut offset = 1;\n for i in 0..16 {\n p_low += (p_bytes[i] as Field) * offset;\n p_high += (p_bytes[i + 16] as Field) * offset;\n offset *= 256;\n }\n assert_eq(p_low, PLO);\n assert_eq(p_high, PHI);\n }\n\n #[test]\n fn check_decompose_edge_cases() {\n assert_eq(decompose(0), (0, 0));\n assert_eq(decompose(TWO_POW_128 - 1), (TWO_POW_128 - 1, 0));\n assert_eq(decompose(TWO_POW_128 + 1), (1, 1));\n assert_eq(decompose(TWO_POW_128 * 2), (0, 2));\n assert_eq(decompose(TWO_POW_128 * 2 + 0x1234567890), (0x1234567890, 2));\n }\n\n #[test]\n fn check_decompose_large_values() {\n let large_field = 0xffffffffffffffff;\n let (lo, hi) = decompose(large_field);\n assert_eq(large_field, lo + TWO_POW_128 * hi);\n\n let large_value = large_field - TWO_POW_128;\n let (lo2, hi2) = decompose(large_value);\n assert_eq(large_value, lo2 + TWO_POW_128 * hi2);\n }\n\n #[test]\n fn check_lt_comprehensive() {\n assert(lt(0, 1));\n assert(!lt(1, 0));\n assert(!lt(0, 0));\n assert(!lt(42, 42));\n\n assert(lt(TWO_POW_128 - 1, TWO_POW_128));\n assert(!lt(TWO_POW_128, TWO_POW_128 - 1));\n }\n}\n","path":"std/field/bn254.nr","function_locations":[{"start":456,"name":"compute_decomposition"},{"start":818,"name":"decompose_hint"},{"start":906,"name":"lte_hint"},{"start":1116,"name":"assert_gt_limbs"},{"start":1725,"name":"decompose"},{"start":2431,"name":"assert_gt"},{"start":2837,"name":"assert_lt"},{"start":2901,"name":"gt"},{"start":3405,"name":"lt"},{"start":3607,"name":"tests::check_decompose"},{"start":3857,"name":"tests::check_lte_hint"},{"start":4164,"name":"tests::check_gt"},{"start":4494,"name":"tests::check_plo_phi"},{"start":4989,"name":"tests::check_decompose_edge_cases"},{"start":5349,"name":"tests::check_decompose_large_values"},{"start":5710,"name":"tests::check_lt_comprehensive"}]},"17":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [bool; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [bool; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [bool; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = false if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = true.\n pub fn sgn0(self) -> bool {\n (self as u8) % 2 == 1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [bool; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [bool; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [bool] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [bool] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_be_bits();\n assert_eq(bits, [false, false, false, false, false, false, true, false]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_le_bits();\n assert_eq(bits, [false, true, false, false, false, false, false, false]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_field.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_val.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [bool; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [false; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [bool; 8] = 1.to_le_bits();\n let expected: [bool; 8] = [true, false, false, false, false, false, false, false];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [bool; 8] = 4.to_le_bits();\n let expected: [bool; 8] = [false, false, true, false, false, false, false, false];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), false);\n assert_eq(2.sgn0(), false);\n assert_eq(4.sgn0(), false);\n assert_eq(100.sgn0(), false);\n\n assert_eq(1.sgn0(), true);\n assert_eq(3.sgn0(), true);\n assert_eq(5.sgn0(), true);\n assert_eq(101.sgn0(), true);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [bool; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits(bits: [bool; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits(bits: [bool; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1]);\n p_minus_1_bits[254 - 1] = false;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(!p_plus_4_bits[254 - 3]);\n p_plus_4_bits[254 - 3] = true;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_be_bits();\n assert(p_plus_4_converted_bits[254 - 3]);\n p_plus_4_converted_bits[254 - 3] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_be_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0]);\n p_minus_1_bits[0] = false;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(!p_plus_4_bits[2]);\n p_plus_4_bits[2] = true;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_le_bits();\n assert(p_plus_4_converted_bits[2]);\n p_plus_4_converted_bits[2] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_le_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n}\n","path":"std/field/mod.nr","function_locations":[{"start":380,"name":"Field::assert_max_bit_size"},{"start":1196,"name":"Field::to_le_bits"},{"start":2387,"name":"Field::to_be_bits"},{"start":3562,"name":"Field::to_le_bytes"},{"start":5033,"name":"Field::to_be_bytes"},{"start":5904,"name":"Field::to_le_radix"},{"start":6362,"name":"Field::to_be_radix"},{"start":7053,"name":"Field::pow_32"},{"start":7455,"name":"Field::sgn0"},{"start":7538,"name":"Field::lt"},{"start":7918,"name":"Field::from_le_bytes"},{"start":8476,"name":"Field::from_be_bytes"},{"start":8757,"name":"__assert_max_bit_size"},{"start":8885,"name":"__to_le_radix"},{"start":9013,"name":"__to_be_radix"},{"start":9734,"name":"__to_le_bits"},{"start":10452,"name":"__to_be_bits"},{"start":10527,"name":"modulus_num_bits"},{"start":10603,"name":"modulus_be_bits"},{"start":10679,"name":"modulus_le_bits"},{"start":10755,"name":"modulus_be_bytes"},{"start":10831,"name":"modulus_le_bytes"},{"start":10992,"name":"__field_less_than"},{"start":11068,"name":"field_less_than"},{"start":11210,"name":"bytes32_to_field"},{"start":11617,"name":"lt_fallback"},{"start":12579,"name":"tests::test_to_be_bits"},{"start":12852,"name":"tests::test_to_le_bits"},{"start":13127,"name":"tests::test_to_be_bytes"},{"start":13433,"name":"tests::test_to_le_bytes"},{"start":13739,"name":"tests::test_to_be_radix"},{"start":14321,"name":"tests::test_to_le_radix"},{"start":14921,"name":"tests::test_to_le_radix_1"},{"start":15374,"name":"tests::test_to_le_radix_brillig_1"},{"start":15728,"name":"tests::test_to_le_radix_3"},{"start":16039,"name":"tests::test_to_le_radix_brillig_3"},{"start":16467,"name":"tests::test_to_le_radix_512"},{"start":16876,"name":"tests::not_enough_limbs_brillig"},{"start":17072,"name":"tests::not_enough_limbs"},{"start":17214,"name":"tests::test_field_less_than"},{"start":17469,"name":"tests::test_large_field_values_unconstrained"},{"start":17922,"name":"tests::test_large_field_values"},{"start":18369,"name":"tests::test_decomposition_edge_cases"},{"start":18959,"name":"tests::test_pow_32"},{"start":19288,"name":"tests::test_sgn0"},{"start":19710,"name":"tests::test_bit_decomposition_overflow"},{"start":19992,"name":"tests::test_byte_decomposition_overflow"},{"start":20209,"name":"tests::test_to_from_be_bytes_bn254_edge_cases"},{"start":22160,"name":"tests::test_to_from_le_bytes_bn254_edge_cases"},{"start":24245,"name":"tests::from_le_bits"},{"start":24792,"name":"tests::from_be_bits"},{"start":25038,"name":"tests::test_to_from_be_bits_bn254_edge_cases"},{"start":26971,"name":"tests::test_to_from_le_bits_bn254_edge_cases"}]},"18":{"source":"// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\nuse crate::static_assert;\n\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated(\"This function has been moved to std::hash::keccakf1600\")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you're working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n \"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\n }\n let generators = derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n crate::assert_constant(separator);\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators(\"pedersen_hash_length\".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n crate::assert_constant(starting_index);\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\npub fn poseidon2_permutation(input: [Field; N]) -> [Field; N] {\n static_assert(\n N == POSEIDON2_CONFIG_STATE_SIZE,\n f\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\",\n );\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal(input: [Field; N]) -> [Field; N] {}\n\n#[foreign(poseidon2_config_state_size)]\ncomptime fn poseidon2_config_state_size() -> u32 {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n /// Returns the hash value without consuming the hasher.\n /// Override this for more efficient implementations that avoid copying.\n /// TODO: deprecate finish() and replace it\n fn finish_ref(&self) -> Field {\n (*self).finish()\n }\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault;\n\nimpl BuildHasher for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl Default for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for [T]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n },\n );\n}\n","path":"std/hash/mod.nr","function_locations":[{"start":572,"name":"sha256_compression"},{"start":707,"name":"keccakf1600"},{"start":882,"name":"keccak::keccakf1600"},{"start":1044,"name":"blake2s"},{"start":1142,"name":"blake3"},{"start":1629,"name":"__blake3"},{"start":1747,"name":"pedersen_commitment"},{"start":1976,"name":"pedersen_commitment_with_separator"},{"start":2380,"name":"pedersen_hash"},{"start":2537,"name":"pedersen_hash_with_separator"},{"start":3531,"name":"derive_generators"},{"start":3890,"name":"__derive_generators"},{"start":3968,"name":"poseidon2_permutation"},{"start":4324,"name":"poseidon2_permutation_internal"},{"start":4417,"name":"poseidon2_config_state_size"},{"start":4728,"name":"derive_hash"},{"start":5953,"name":">::build_hasher"},{"start":6085,"name":">::default"},{"start":6217,"name":"::hash"},{"start":6347,"name":"::hash"},{"start":6487,"name":"::hash"},{"start":6627,"name":"::hash"},{"start":6767,"name":"::hash"},{"start":6908,"name":"::hash"},{"start":7047,"name":"::hash"},{"start":7193,"name":"::hash"},{"start":7340,"name":"::hash"},{"start":7487,"name":"::hash"},{"start":7635,"name":"::hash"},{"start":7782,"name":"::hash"},{"start":7914,"name":"::hash"},{"start":8103,"name":"::hash"},{"start":8343,"name":"::hash"},{"start":8559,"name":"::hash"},{"start":8822,"name":"::hash"},{"start":9132,"name":"::hash"},{"start":9528,"name":"assert_pedersen"}]},"41":{"source":"use crate::cmp::{Eq, Ord, Ordering};\nuse crate::default::Default;\nuse crate::hash::{Hash, Hasher};\n\n/// Represents a value of type T or its absence.\n/// Use `Option::some(value)` to construct a value or `Option::none()` to record the absence of one.\npub struct Option {\n _is_some: bool,\n _value: T,\n}\n\nimpl Option {\n /// Constructs a None value\n pub fn none() -> Self {\n Self { _is_some: false, _value: crate::mem::zeroed() }\n }\n\n /// Constructs a Some wrapper around the given value\n pub fn some(_value: T) -> Self {\n Self { _is_some: true, _value }\n }\n\n /// True if this Option is None\n pub fn is_none(&self) -> bool {\n !self._is_some\n }\n\n /// True if this Option is Some\n pub fn is_some(&self) -> bool {\n self._is_some\n }\n\n /// Asserts `self.is_some()` and returns the wrapped value.\n pub fn unwrap(self) -> T {\n assert(self._is_some);\n self._value\n }\n\n /// Returns the inner value without asserting `self.is_some()`\n /// Note that if `self` is `None`, there is no guarantee what value will be returned,\n /// only that it will be of type `T`.\n pub fn unwrap_unchecked(self) -> T {\n self._value\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.\n pub fn unwrap_or(self, default: T) -> T {\n if self._is_some {\n self._value\n } else {\n default\n }\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return\n /// a default value.\n pub fn unwrap_or_else(self, default: fn[Env]() -> T) -> T {\n if self._is_some {\n self._value\n } else {\n default()\n }\n }\n\n /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value\n pub fn expect(self, message: fmtstr) -> T {\n assert(self.is_some(), message);\n self._value\n }\n\n /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.\n pub fn map(self, f: fn[Env](T) -> U) -> Option {\n if self._is_some {\n Option::some(f(self._value))\n } else {\n Option::none()\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.\n pub fn map_or(self, default: U, f: fn[Env](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.\n pub fn map_or_else(self, default: fn[Env1]() -> U, f: fn[Env2](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default()\n }\n }\n\n /// Returns None if self is None. Otherwise, this returns `other`.\n pub fn and(self, other: Self) -> Self {\n if self.is_none() {\n Option::none()\n } else {\n other\n }\n }\n\n /// If self is None, this returns None. Otherwise, this calls the given function\n /// with the Some value contained within self, and returns the result of that call.\n ///\n /// In some languages this function is called `flat_map` or `bind`.\n pub fn and_then(self, f: fn[Env](T) -> Option) -> Option {\n if self._is_some {\n f(self._value)\n } else {\n Option::none()\n }\n }\n\n /// If self is Some, return self. Otherwise, return `other`.\n pub fn or(self, other: Self) -> Self {\n if self._is_some {\n self\n } else {\n other\n }\n }\n\n /// If self is Some, return self. Otherwise, return `default()`.\n pub fn or_else(self, default: fn[Env]() -> Self) -> Self {\n if self._is_some {\n self\n } else {\n default()\n }\n }\n\n // If only one of the two Options is Some, return that option.\n // Otherwise, if both options are Some or both are None, None is returned.\n pub fn xor(self, other: Self) -> Self {\n if self._is_some {\n if other._is_some {\n Option::none()\n } else {\n self\n }\n } else if other._is_some {\n other\n } else {\n Option::none()\n }\n }\n\n /// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.\n /// Otherwise, this returns `None`\n pub fn filter(self, predicate: fn[Env](T) -> bool) -> Self {\n if self._is_some {\n if predicate(self._value) {\n self\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n }\n\n /// Flattens an Option> into a Option.\n /// This returns None if the outer Option is None. Otherwise, this returns the inner Option.\n pub fn flatten(option: Option>) -> Option {\n if option._is_some {\n option._value\n } else {\n Option::none()\n }\n }\n}\n\nimpl Default for Option {\n fn default() -> Self {\n Option::none()\n }\n}\n\nimpl Eq for Option\nwhere\n T: Eq,\n{\n fn eq(self, other: Self) -> bool {\n if self._is_some == other._is_some {\n if self._is_some {\n self._value == other._value\n } else {\n true\n }\n } else {\n false\n }\n }\n}\n\nimpl Hash for Option\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self._is_some.hash(state);\n if self._is_some {\n self._value.hash(state);\n }\n }\n}\n\n// For this impl we're declaring Option::none < Option::some\nimpl Ord for Option\nwhere\n T: Ord,\n{\n fn cmp(self, other: Self) -> Ordering {\n if self._is_some {\n if other._is_some {\n self._value.cmp(other._value)\n } else {\n Ordering::greater()\n }\n } else if other._is_some {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n","path":"std/option.nr","function_locations":[{"start":389,"name":"Option::none"},{"start":553,"name":"Option::some"},{"start":672,"name":"Option::is_none"},{"start":774,"name":"Option::is_some"},{"start":898,"name":"Option::unwrap"},{"start":1196,"name":"Option::unwrap_unchecked"},{"start":1368,"name":"Option::unwrap_or"},{"start":1668,"name":"Option::unwrap_or_else"},{"start":1969,"name":"Option::expect"},{"start":2190,"name":"Option::map"},{"start":2490,"name":"Option::map_or"},{"start":2784,"name":"Option::map_or_else"},{"start":3009,"name":"Option::and"},{"start":3446,"name":"Option::and_then"},{"start":3669,"name":"Option::or"},{"start":3902,"name":"Option::or_else"},{"start":4192,"name":"Option::xor"},{"start":4636,"name":"Option::filter"},{"start":5065,"name":"Option::flatten"},{"start":5242,"name":">::default"},{"start":5357,"name":">::eq"},{"start":5706,"name":">::hash"},{"start":5975,"name":">::cmp"}]},"42":{"source":"/// Halt the program at runtime with the given error message.\n///\n/// The provided error message must be either a `str` or a `fmtstr`.\npub fn panic(message: T) -> U\nwhere\n T: StringLike,\n{\n assert(false, message);\n crate::mem::zeroed()\n}\n\ntrait StringLike {}\n\nimpl StringLike for str {}\nimpl StringLike for fmtstr {}\n","path":"std/panic.nr","function_locations":[{"start":196,"name":"panic"}]},"59":{"source":"use crate::oracle::capsules;\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// A dynamically sized array backed by PXE's non-volatile database (called capsules). Values are persisted until\n/// deleted, so they can be e.g. stored during simulation of a transaction and later retrieved during witness\n/// generation. All values are scoped per contract address, so external contracts cannot access them.\npub struct CapsuleArray {\n contract_address: AztecAddress,\n /// The base slot is where the array length is stored in capsules. Array elements are stored in consecutive slots\n /// after the base slot. For example, with base slot 5: the length is at slot 5, the first element (index 0) is at\n /// slot 6, the second element (index 1) is at slot 7, and so on.\n base_slot: Field,\n /// Scope for capsule isolation. Capsule operations are scoped to the given address, allowing multiple independent\n /// namespaces within the same contract.\n scope: AztecAddress,\n}\n\nimpl CapsuleArray {\n /// Returns a CapsuleArray scoped to a specific address.\n ///\n /// Array elements are stored in contiguous slots\n /// following the base slot, so there should be sufficient space between array base slots to accommodate elements.\n /// A reasonable strategy is to make the base slot a hash of a unique value.\n pub unconstrained fn at(contract_address: AztecAddress, base_slot: Field, scope: AztecAddress) -> Self {\n Self { contract_address, base_slot, scope }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n // An uninitialized array defaults to a length of 0.\n capsules::load(self.contract_address, self.base_slot, self.scope).unwrap_or(0) as u32\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let current_length = self.len();\n\n // The slot corresponding to the index `current_length` is the first slot immediately after the end of the\n // array, which is where we want to place the new value.\n capsules::store(\n self.contract_address,\n self.slot_at(current_length),\n value,\n self.scope,\n );\n\n // Then we simply update the length.\n let new_length = current_length + 1;\n capsules::store(\n self.contract_address,\n self.base_slot,\n new_length,\n self.scope,\n );\n }\n\n /// Retrieves the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n assert(index < self.len(), \"Attempted to read past the length of a CapsuleArray\");\n\n capsules::load(self.contract_address, self.slot_at(index), self.scope).unwrap()\n }\n\n /// Deletes the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n let current_length = self.len();\n assert(index < current_length, \"Attempted to delete past the length of a CapsuleArray\");\n\n // In order to be able to remove elements at arbitrary indices, we need to shift the entire contents of the\n // array past the removed element one slot backward so that we don't end up with a gap and preserve the\n // contiguous slots. We can skip this when deleting the last element however.\n if index != current_length - 1 {\n // The source and destination regions overlap, but `copy` supports this.\n capsules::copy(\n self.contract_address,\n self.slot_at(index + 1),\n self.slot_at(index),\n current_length - index - 1,\n self.scope,\n );\n }\n\n // We can now delete the last element (which has either been copied to the slot immediately before it, or was\n // the element we meant to delete in the first place) and update the length.\n capsules::delete(\n self.contract_address,\n self.slot_at(current_length - 1),\n self.scope,\n );\n capsules::store(\n self.contract_address,\n self.base_slot,\n current_length - 1,\n self.scope,\n );\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. The order in which values\n /// are processed is arbitrary.\n ///\n /// ## Array Mutation\n ///\n /// It is safe to delete the current element (and only the current element) from inside the callback via `remove`:\n /// ```noir\n /// array.for_each(|index, value| {\n /// if some_condition(value) {\n /// array.remove(index); // safe only for this index\n /// }\n /// }\n /// ```\n ///\n /// If all elements in the array need to iterated over and then removed, then using `for_each` results in optimal\n /// efficiency.\n ///\n /// It is **not** safe to push new elements into the array from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n // Iterating over all elements is simple, but we want to do it in such a way that a) deleting the current\n // element is safe to do, and b) deleting *all* elements is optimally efficient. This is because CapsuleArrays\n // are typically used to hold pending tasks, so iterating them while clearing completed tasks (sometimes\n // unconditionally, resulting in a full clear) is a very common access pattern.\n //\n // The way we achieve this is by iterating backwards: each element can always be deleted since it won't change\n // any preceding (lower) indices, and if every element is deleted then every element will (in turn) be the last\n // element. This results in an optimal full clear since `remove` will be able to skip the `capsules::copy` call\n // to shift any elements past the deleted one (because there will be none).\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n\n unconstrained fn slot_at(self, index: u32) -> Field {\n // Elements are stored immediately after the base slot, so we add 1 to it to compute the slot for the first\n // element.\n self.base_slot + 1 + index as Field\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::CapsuleArray;\n\n global SLOT: Field = 1230;\n\n #[test]\n unconstrained fn empty_array() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array: CapsuleArray = CapsuleArray::at(contract_address, SLOT, scope);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn empty_array_read() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n let _: Field = array.get(0);\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn read_past_len() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(5);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 8);\n assert_eq(array.get(2), 9);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We store all values that we were called with and check that all (value, index) tuples are present. Note\n // that we do not care about the order in which each tuple was passed to the closure.\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all_no_copy() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We test that the aztec_utl_copyCapsule was never called, which is the expensive operation we want to\n // avoid.\n let mock = std::test::OracleMock::mock(\"aztec_utl_copyCapsule\");\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(mock.times_called(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_scopes_are_isolated() {\n let mut env = TestEnvironment::new();\n let scope_a = env.create_light_account();\n let scope_b = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array_a = CapsuleArray::at(contract_address, SLOT, scope_a);\n let array_b = CapsuleArray::at(contract_address, SLOT, scope_b);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/capsules/mod.nr","function_locations":[{"start":1478,"name":"CapsuleArray::at"},{"start":1641,"name":"CapsuleArray::len"},{"start":1935,"name":"CapsuleArray::push"},{"start":2748,"name":"CapsuleArray::get"},{"start":3083,"name":"CapsuleArray::remove"},{"start":5345,"name":"CapsuleArray::for_each"},{"start":6413,"name":"CapsuleArray::slot_at"},{"start":6789,"name":"test::empty_array"},{"start":7263,"name":"test::empty_array_read"},{"start":7638,"name":"test::array_push"},{"start":8156,"name":"test::read_past_len"},{"start":8559,"name":"test::array_remove_last"},{"start":8997,"name":"test::array_remove_some"},{"start":9729,"name":"test::array_remove_all"},{"start":10296,"name":"test::for_each_called_with_all_elements"},{"start":11389,"name":"test::for_each_remove_some"},{"start":12081,"name":"test::for_each_remove_all"},{"start":12619,"name":"test::for_each_remove_all_no_copy"},{"start":13383,"name":"test::different_scopes_are_isolated"}]},"70":{"source":"use crate::oracle::{execution::get_utility_context, storage::storage_read};\nuse crate::protocol::{abis::block_header::BlockHeader, address::AztecAddress, traits::Packable};\n\n// If you'll modify this struct don't forget to update utility_context.ts as well.\npub struct UtilityContext {\n block_header: BlockHeader,\n contract_address: AztecAddress,\n}\n\nimpl UtilityContext {\n pub unconstrained fn new() -> Self {\n get_utility_context()\n }\n\n pub unconstrained fn at(contract_address: AztecAddress) -> Self {\n // We get a context with default contract address, and then we construct the final context with the provided\n // contract address.\n let default_context = get_utility_context();\n\n Self { block_header: default_context.block_header, contract_address }\n }\n\n pub fn block_header(self) -> BlockHeader {\n self.block_header\n }\n\n pub fn block_number(self) -> u32 {\n self.block_header.block_number()\n }\n\n pub fn timestamp(self) -> u64 {\n self.block_header.timestamp()\n }\n\n pub fn this_address(self) -> AztecAddress {\n self.contract_address\n }\n\n pub fn version(self) -> Field {\n self.block_header.version()\n }\n\n pub fn chain_id(self) -> Field {\n self.block_header.chain_id()\n }\n\n pub unconstrained fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n storage_read(self.block_header, self.this_address(), storage_slot)\n }\n\n pub unconstrained fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/utility_context.nr","function_locations":[{"start":416,"name":"UtilityContext::new"},{"start":523,"name":"UtilityContext::at"},{"start":855,"name":"UtilityContext::block_header"},{"start":927,"name":"UtilityContext::block_number"},{"start":1011,"name":"UtilityContext::timestamp"},{"start":1104,"name":"UtilityContext::this_address"},{"start":1177,"name":"UtilityContext::version"},{"start":1257,"name":"UtilityContext::chain_id"},{"start":1404,"name":"UtilityContext::raw_storage_read"},{"start":1596,"name":"UtilityContext::storage_read"}]},"75":{"source":"use crate::oracle::ephemeral;\nuse crate::protocol::traits::{Deserialize, Serialize};\n\n/// A dynamically sized array that exists only during a single contract call frame.\n///\n/// Ephemeral arrays are backed by in-memory storage on the PXE side rather than a persistent database. Each contract\n/// call frame gets its own isolated slot space of ephemeral arrays. Child simulations cannot see the parent's\n/// ephemeral arrays, and vice versa.\n///\n/// Each logical array operation (push, pop, get, etc.) is a single oracle call, making ephemeral arrays significantly\n/// cheaper than capsule arrays.\n///\n/// ## Use Cases\n///\n/// Ephemeral arrays are designed for passing data between PXE (TypeScript) and contracts (Noir) during simulation,\n/// for example, note validation requests or event validation responses. This data type is appropriate for data that\n/// is not supposed to be persisted.\n///\n/// For data that needs to persist across simulations, contract calls, etc, use\n/// [`CapsuleArray`](crate::capsules::CapsuleArray) instead.\npub struct EphemeralArray {\n pub slot: Field,\n}\n\nimpl EphemeralArray {\n /// Returns a handle to an ephemeral array at the given slot, which may already contain data (e.g. populated\n /// by an oracle).\n pub unconstrained fn at(slot: Field) -> Self {\n Self { slot }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n ephemeral::len_oracle(self.slot)\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n let _ = ephemeral::push_oracle(self.slot, serialized);\n }\n\n /// Removes and returns the last element. Panics if the array is empty.\n pub unconstrained fn pop(self) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::pop_oracle(self.slot);\n Deserialize::deserialize(serialized)\n }\n\n /// Retrieves the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::get_oracle(self.slot, index);\n Deserialize::deserialize(serialized)\n }\n\n /// Overwrites the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn set(self, index: u32, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n ephemeral::set_oracle(self.slot, index, serialized);\n }\n\n /// Removes the element at `index`, shifting subsequent elements backward. Panics if out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n ephemeral::remove_oracle(self.slot, index);\n }\n\n /// Removes all elements from the array and returns self for chaining (e.g. `EphemeralArray::at(slot).clear()`\n /// to get a guaranteed-empty array at a given slot).\n pub unconstrained fn clear(self) -> Self {\n ephemeral::clear_oracle(self.slot);\n self\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. Iteration proceeds\n /// backwards so that it is safe to remove the current element (and only the current element) inside the\n /// callback.\n ///\n /// It is **not** safe to push new elements from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use crate::test::mocks::MockStruct;\n use super::EphemeralArray;\n\n global SLOT: Field = 1230;\n global OTHER_SLOT: Field = 5670;\n\n #[test]\n unconstrained fn empty_array() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn empty_array_read() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.get(0);\n });\n }\n\n #[test(should_fail_with = \"is empty\")]\n unconstrained fn empty_array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.pop();\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn read_past_len() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.push(10);\n\n let popped: Field = array.pop();\n assert_eq(popped, 10);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test]\n unconstrained fn array_set() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.set(0, 99);\n assert_eq(array.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.remove(0);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_slots_are_isolated() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array_a = EphemeralArray::at(SLOT);\n let array_b = EphemeralArray::at(OTHER_SLOT);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn works_with_multi_field_type() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n\n let a = MockStruct::new(5, 6);\n let b = MockStruct::new(7, 8);\n array.push(a);\n array.push(b);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), a);\n assert_eq(array.get(1), b);\n\n let popped: MockStruct = array.pop();\n assert_eq(popped, b);\n assert_eq(array.len(), 1);\n });\n }\n\n #[test]\n unconstrained fn clear_returns_self() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(array.len(), 0);\n\n array.push(42);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 42);\n });\n }\n\n #[test]\n unconstrained fn clear_wipes_previous_data() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n array.push(1);\n array.push(2);\n array.push(3);\n assert_eq(array.len(), 3);\n\n // Clear the same slot, previous data should be gone.\n let fresh: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(fresh.len(), 0);\n fresh.push(4);\n assert_eq(fresh.get(0), 4);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/ephemeral/mod.nr","function_locations":[{"start":1305,"name":"EphemeralArray::at"},{"start":1438,"name":"EphemeralArray::len"},{"start":1618,"name":"EphemeralArray::push"},{"start":1888,"name":"EphemeralArray::pop"},{"start":2176,"name":"EphemeralArray::get"},{"start":2475,"name":"EphemeralArray::set"},{"start":2743,"name":"EphemeralArray::remove"},{"start":3022,"name":"EphemeralArray::clear"},{"start":3593,"name":"EphemeralArray::for_each"},{"start":3983,"name":"test::empty_array"},{"start":4280,"name":"test::empty_array_read"},{"start":4550,"name":"test::empty_array_pop"},{"start":4783,"name":"test::array_push"},{"start":5122,"name":"test::read_past_len"},{"start":5376,"name":"test::array_pop"},{"start":5783,"name":"test::array_set"},{"start":6081,"name":"test::array_remove_last"},{"start":6376,"name":"test::array_remove_some"},{"start":6847,"name":"test::array_remove_all"},{"start":7273,"name":"test::for_each_called_with_all_elements"},{"start":8009,"name":"test::for_each_remove_some"},{"start":8561,"name":"test::for_each_remove_all"},{"start":8960,"name":"test::different_slots_are_isolated"},{"start":9534,"name":"test::works_with_multi_field_type"},{"start":10148,"name":"test::clear_returns_self"},{"start":10535,"name":"test::clear_wipes_previous_data"}]},"77":{"source":"use crate::{event::EventSelector, messages::logs::event::MAX_EVENT_SERIALIZED_LEN};\nuse crate::protocol::{\n constants::DOM_SEP__EVENT_COMMITMENT,\n hash::{poseidon2_hash_with_separator, poseidon2_hash_with_separator_bounded_vec},\n traits::{Serialize, ToField},\n};\n\npub trait EventInterface {\n fn get_event_type_id() -> EventSelector;\n}\n\n/// A private event's commitment is a value stored on-chain which is used to verify that the event was indeed emitted.\n///\n/// It requires a `randomness` value that must be produced alongside the event in order to perform said validation.\n/// This random value prevents attacks in which someone guesses plausible events (e.g. 'Alice transfers to Bob an\n/// amount of 10'), since they will not be able to test for existence of their guessed events without brute-forcing the\n/// entire `Field` space by guessing `randomness` values.\npub fn compute_private_event_commitment(event: Event, randomness: Field) -> Field\nwhere\n Event: EventInterface + Serialize,\n{\n poseidon2_hash_with_separator(\n [randomness, Event::get_event_type_id().to_field()].concat(event.serialize()),\n DOM_SEP__EVENT_COMMITMENT,\n )\n}\n\n/// Unconstrained variant of [`compute_private_event_commitment`] which takes the event in serialized form.\n///\n/// This function is unconstrained as the mechanism it uses to compute the commitment would be very inefficient in a\n/// constrained environment (due to the hashing of a dynamically sized array). This is not an issue as it is typically\n/// invoked when processing event messages, which is an unconstrained operation.\npub unconstrained fn compute_private_serialized_event_commitment(\n serialized_event: BoundedVec,\n randomness: Field,\n event_type_id: Field,\n) -> Field {\n let mut commitment_preimage =\n BoundedVec::<_, 2 + MAX_EVENT_SERIALIZED_LEN>::from_array([randomness, event_type_id]);\n commitment_preimage.extend_from_bounded_vec(serialized_event);\n\n poseidon2_hash_with_separator_bounded_vec(commitment_preimage, DOM_SEP__EVENT_COMMITMENT)\n}\n\nmod test {\n use crate::event::event_interface::{\n compute_private_event_commitment, compute_private_serialized_event_commitment, EventInterface,\n };\n use crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN;\n use crate::protocol::traits::{Serialize, ToField};\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn max_size_serialized_event_commitment() {\n let serialized_event = BoundedVec::from_array([0; MAX_EVENT_SERIALIZED_LEN]);\n let _ = compute_private_serialized_event_commitment(serialized_event, 0, 0);\n }\n\n #[test]\n unconstrained fn event_commitment_equivalence() {\n let event = MockEvent::new(VALUE).build_event();\n\n assert_eq(\n compute_private_event_commitment(event, RANDOMNESS),\n compute_private_serialized_event_commitment(\n BoundedVec::from_array(event.serialize()),\n RANDOMNESS,\n MockEvent::get_event_type_id().to_field(),\n ),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_interface.nr","function_locations":[{"start":1013,"name":"compute_private_event_commitment"},{"start":1803,"name":"compute_private_serialized_event_commitment"},{"start":2570,"name":"test::max_size_serialized_event_commitment"},{"start":2814,"name":"test::event_commitment_equivalence"}]},"79":{"source":"use crate::protocol::{hash::poseidon2_hash_bytes, traits::{Deserialize, Empty, FromField, Serialize, ToField}};\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct EventSelector {\n // Low 32 bits of the poseidon2 hash of the event signature.\n inner: u32,\n}\n\nimpl FromField for EventSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for EventSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for EventSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl EventSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n EventSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_selector.nr","function_locations":[{"start":337,"name":"::from_field"},{"start":449,"name":"::to_field"},{"start":542,"name":"::empty"},{"start":647,"name":"EventSelector::from_u32"},{"start":751,"name":"EventSelector::from_signature"},{"start":985,"name":"EventSelector::zero"}]},"92":{"source":"use crate::protocol::{\n address::aztec_address::AztecAddress,\n constants::{DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, DOM_SEP__ECDH_FIELD_MASK, DOM_SEP__ECDH_SUBKEY},\n hash::poseidon2_hash_with_separator,\n point::Point,\n scalar::Scalar,\n traits::{FromField, ToField},\n};\nuse std::{embedded_curve_ops::multi_scalar_mul, ops::Neg};\n\n/// Computes a standard ECDH shared secret: secret * public_key = shared_secret.\n///\n/// The input secret is known only to one party. The output shared secret can be derived given knowledge of\n/// `public_key`'s key-pair and the public ephemeral secret, using this same function (with reversed inputs).\n///\n/// E.g.: Epk = esk * G // ephemeral key-pair\n/// Pk = sk * G // recipient key-pair\n/// Shared secret S = esk * Pk = sk * Epk\n///\n/// See also: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman\npub fn derive_ecdh_shared_secret(secret: Scalar, public_key: Point) -> Point {\n // TODO(F-553): Drop the `.to_embedded()` / `.into()` round-trip once the custom `Point` wrapper is removed and we\n // use `EmbeddedCurvePoint` directly.\n multi_scalar_mul([public_key.to_embedded()], [secret]).into()\n}\n\n/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.\n///\n/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`\npub(crate) fn compute_app_siloed_shared_secret(shared_secret: Point, contract_address: AztecAddress) -> Field {\n poseidon2_hash_with_separator(\n [shared_secret.x, shared_secret.y, contract_address.to_field()],\n DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET,\n )\n}\n\n/// Derives an indexed subkey from an app-siloed shared secret, used for AES key/IV derivation.\n///\n/// `s_i = h(DOM_SEP__ECDH_SUBKEY + i, s_app)`\npub(crate) fn derive_shared_secret_subkey(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_SUBKEY + index)\n}\n\n/// Derives an indexed field mask from an app-siloed shared secret, used for masking ciphertext fields.\n///\n/// `m_i = h(DOM_SEP__ECDH_FIELD_MASK + i, s_app)`\npub(crate) fn derive_shared_secret_field_mask(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_FIELD_MASK + index)\n}\n\n#[test]\nunconstrained fn test_consistency_with_typescript() {\n let secret = Scalar {\n lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,\n hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,\n };\n let point = Point {\n x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,\n y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,\n is_infinite: false,\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret, point);\n\n // This is just pasted from a test run. The original typescript code from which this could be generated seems to\n // have been deleted by someone, and soon the typescript code for encryption and decryption won't be needed, so\n // this will have to do.\n let hard_coded_shared_secret = Point {\n x: 0x15d55a5b3b2caa6a6207f313f05c5113deba5da9927d6421bcaa164822b911bc,\n y: 0x0974c3d0825031ae933243d653ebb1a0b08b90ee7f228f94c5c74739ea3c871e,\n is_infinite: false,\n };\n assert_eq(shared_secret, hard_coded_shared_secret);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_from_address_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let mut pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let mut pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let address_b = AztecAddress::from_field(pk_b.x);\n\n // We were lazy in deriving the secret keys, and didn't check the resulting y-coordinates of the pk_a or pk_b to be\n // less than half the field modulus. If needed, we negate the pk's so that they yield valid address points. (We\n // could also have negated the secrets, but there's no negate method for EmbeddedCurvesScalar).\n pk_a = if (AztecAddress::from_field(pk_a.x).to_address_point().unwrap().inner == pk_a) {\n pk_a\n } else {\n pk_a.neg()\n };\n pk_b = if (address_b.to_address_point().unwrap().inner == pk_b) {\n pk_b\n } else {\n pk_b.neg()\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, address_b.to_address_point().unwrap().inner);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_app_siloed_shared_secret_differs_per_contract() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(Scalar { lo: 0x3456, hi: 0x4567 }).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n\n let contract_a = AztecAddress::from_field(0xAAAA);\n let contract_b = AztecAddress::from_field(0xBBBB);\n\n let s_app_a = compute_app_siloed_shared_secret(shared_secret, contract_a);\n let s_app_b = compute_app_siloed_shared_secret(shared_secret, contract_b);\n\n assert(s_app_a != s_app_b, \"app-siloed secrets must differ for different contracts\");\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/keys/ecdh_shared_secret.nr","function_locations":[{"start":954,"name":"derive_ecdh_shared_secret"},{"start":1485,"name":"compute_app_siloed_shared_secret"},{"start":1876,"name":"derive_shared_secret_subkey"},{"start":2194,"name":"derive_shared_secret_field_mask"},{"start":2336,"name":"test_consistency_with_typescript"},{"start":3450,"name":"test_shared_secret_computation_in_both_directions"},{"start":4017,"name":"test_shared_secret_computation_from_address_in_both_directions"},{"start":5278,"name":"test_app_siloed_shared_secret_differs_per_contract"}]},"97":{"source":"// Not all log levels are currently used, but we provide the full set so that new call sites can use any level. Because\n// of that we tag all with `#[allow(dead_code)]` to prevent warnings.\n//\n// All wrappers resolve function paths at comptime via `resolve_fn` so that the emitted `Quoted` code works both inside\n// aztec-nr (where `crate::` = aztec) and inside macro-generated contract code (where `crate::` = the contract).\n\nuse std::meta::ctstring::AsCtString;\n\ncomptime fn log_prefix(msg: str) -> CtString {\n \"[aztec-nr] \".as_ctstring().append_str(msg)\n}\n\n// --- No-args variants (direct call) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log });\n quote { $f($msg) }\n}\n\n// --- Format variants (return lambda for runtime args) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n// See module-level comment for why this is needed.\ncomptime fn resolve_fn(path: Quoted) -> TypedExpr {\n path.as_expr().unwrap().resolve(Option::none())\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/logging.nr","function_locations":[{"start":525,"name":"log_prefix"},{"start":717,"name":"aztecnr_fatal_log"},{"start":943,"name":"aztecnr_error_log"},{"start":1168,"name":"aztecnr_warn_log"},{"start":1392,"name":"aztecnr_info_log"},{"start":1619,"name":"aztecnr_verbose_log"},{"start":1847,"name":"aztecnr_debug_log"},{"start":2073,"name":"aztecnr_trace_log"},{"start":2367,"name":"aztecnr_fatal_log_format"},{"start":2622,"name":"aztecnr_error_log_format"},{"start":2876,"name":"aztecnr_warn_log_format"},{"start":3129,"name":"aztecnr_info_log_format"},{"start":3385,"name":"aztecnr_verbose_log_format"},{"start":3642,"name":"aztecnr_debug_log_format"},{"start":3897,"name":"aztecnr_trace_log_format"},{"start":4151,"name":"resolve_fn"}]},"99":{"source":"use crate::logging;\nuse crate::macros::{notes::NOTES, utils::get_trait_impl_method};\n\n/// Generates two contract library methods called `_compute_note_hash` and `_compute_note_nullifier`, plus a\n/// (deprecated) wrapper called `_compute_note_hash_and_nullifier`, which are used for note discovery (i.e. these are\n/// of the `aztec::messages::discovery::ComputeNoteHash` and `aztec::messages::discovery::ComputeNoteNullifier` types).\npub(crate) comptime fn generate_contract_library_methods_compute_note_hash_and_nullifier() -> Quoted {\n let compute_note_hash = generate_contract_library_method_compute_note_hash();\n let compute_note_nullifier = generate_contract_library_method_compute_note_nullifier();\n\n quote {\n $compute_note_hash\n $compute_note_nullifier\n\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n #[allow(dead_code)]\n unconstrained fn _compute_note_hash_and_nullifier(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n note_nonce: Field,\n ) -> Option {\n _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash| {\n\n let siloed_note_hash = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash);\n let unique_note_hash = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash);\n \n let inner_nullifier = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness);\n\n aztec::messages::discovery::NoteHashAndNullifier {\n note_hash,\n inner_nullifier,\n }\n })\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_hash() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the note hash (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_note_hash = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_note_hash },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n Option::some($compute_note_hash(note, owner, storage_slot, randomness))\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed).\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_nullifier() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the inner nullifier (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_nullifier_unconstrained = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_nullifier_unconstrained },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n // The message discovery process finds settled notes, that is, notes that were created in\n // prior transactions and are therefore already part of the note hash tree. The note hash\n // for nullification is hence the unique note hash.\n $compute_nullifier_unconstrained(note, owner, unique_note_hash)\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data.\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec/compute_note_hash_and_nullifier.nr","function_locations":[{"start":534,"name":"generate_contract_library_methods_compute_note_hash_and_nullifier"},{"start":2449,"name":"generate_contract_library_method_compute_note_hash"},{"start":7674,"name":"generate_contract_library_method_compute_note_nullifier"}]},"100":{"source":"mod compute_note_hash_and_nullifier;\n\nuse crate::{\n macros::{\n calls_generation::{\n external_functions::{generate_external_function_calls, generate_external_function_self_calls_structs},\n internal_functions::generate_call_internal_struct,\n },\n dispatch::generate_public_dispatch,\n emit_public_init_nullifier::generate_emit_public_init_nullifier,\n internals_functions_generation::{create_fn_abi_exports, process_functions},\n storage::STORAGE_LAYOUT_NAME,\n utils::{is_fn_contract_library_method, is_fn_external, is_fn_internal, is_fn_test, module_has_storage},\n },\n messages::discovery::CustomMessageHandler,\n};\n\nuse compute_note_hash_and_nullifier::generate_contract_library_methods_compute_note_hash_and_nullifier;\n\n/// Configuration for the [`aztec`] macro.\n///\n/// This type lets users override different parts of the default aztec-nr contract behavior, such\n/// as message handling. These are advanced features that require careful understanding of\n/// the behavior of these systems.\n///\n/// ## Examples\n///\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyContract { ... }\n/// ```\npub struct AztecConfig {\n custom_message_handler: Option>,\n}\n\nimpl AztecConfig {\n /// Creates a new `AztecConfig` with default values.\n ///\n /// Calling `new` is equivalent to invoking the [`aztec`] macro with no parameters. The different methods\n /// (e.g. [`AztecConfig::custom_message_handler`]) can then be used to change the default behavior.\n pub comptime fn new() -> Self {\n Self { custom_message_handler: Option::none() }\n }\n\n /// Sets a handler for custom messages.\n ///\n /// This enables contracts to process non-standard messages (i.e. any with a message type that is not in\n /// [`crate::messages::msg_type`]).\n ///\n /// `handler` must be a function that conforms to the\n /// [`crate::messages::discovery::CustomMessageHandler`] type signature.\n pub comptime fn custom_message_handler(_self: Self, handler: CustomMessageHandler<()>) -> Self {\n Self { custom_message_handler: Option::some(handler) }\n }\n}\n\n/// Enables aztec-nr features on a `contract`.\n///\n/// All aztec-nr contracts should have this macro invoked on them, as it is the one that processes all contract\n/// functions, notes, storage, generates interfaces for external calls, and creates the message processing\n/// boilerplate.\n///\n/// ## Examples\n///\n/// Most contracts can simply invoke the macro with no parameters, resulting in default aztec-nr behavior:\n/// ```noir\n/// #[aztec]\n/// contract MyContract { ... }\n/// ```\n///\n/// Advanced contracts can use [`AztecConfig`] to customize parts of its behavior, such as message\n/// processing.\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyAdvancedContract { ... }\n/// ```\n#[varargs]\npub comptime fn aztec(m: Module, args: [AztecConfig]) -> Quoted {\n let num_args = args.len();\n let config = if num_args == 0 {\n AztecConfig::new()\n } else if num_args == 1 {\n args[0]\n } else {\n panic(f\"#[aztec] expects 0 or 1 arguments, got {num_args}\")\n };\n\n // Functions that don't have #[external(...)], #[contract_library_method], or #[test] are not allowed in contracts.\n check_each_fn_macroified(m);\n\n // We generate new functions prefixed with `__aztec_nr_internals__` and we replace the original functions' bodies\n // with `static_assert(false, ...)` to prevent them from being called directly from within the contract.\n let functions = process_functions(m);\n\n // We generate structs and their implementations necessary for convenient functions calls.\n let interface = generate_contract_interface(m);\n let self_call_structs = generate_external_function_self_calls_structs(m);\n let call_internal_struct = generate_call_internal_struct(m);\n\n // We generate ABI exports for all the external functions in the contract.\n let fn_abi_exports = create_fn_abi_exports(m);\n\n // We generate `_compute_note_hash`, `_compute_note_nullifier` (and the deprecated\n // `_compute_note_hash_and_nullifier` wrapper) and `sync_state` functions only if they are not already implemented.\n // If they are implemented we just insert empty quotes.\n let contract_library_method_compute_note_hash_and_nullifier = if !m.functions().any(|f| {\n // Note that we don't test for `_compute_note_hash` or `_compute_note_nullifier` in order to make this simpler\n // - users must either implement all three or none.\n // Down the line we'll remove this check and use `AztecConfig`.\n f.name() == quote { _compute_note_hash_and_nullifier }\n }) {\n generate_contract_library_methods_compute_note_hash_and_nullifier()\n } else {\n quote {}\n };\n let process_custom_message_option = if config.custom_message_handler.is_some() {\n let handler = config.custom_message_handler.unwrap();\n quote { Option::some($handler) }\n } else {\n quote { Option::>::none() }\n };\n\n let offchain_inbox_sync_option = quote {\n Option::some(aztec::messages::processing::offchain::sync_inbox)\n };\n\n let sync_state_fn_and_abi_export = if !m.functions().any(|f| f.name() == quote { sync_state }) {\n generate_sync_state(process_custom_message_option, offchain_inbox_sync_option)\n } else {\n quote {}\n };\n\n if m.functions().any(|f| f.name() == quote { offchain_receive }) {\n panic(\n \"User-defined 'offchain_receive' is not allowed. The function is auto-injected by the #[aztec] macro. See https://docs.aztec.network/errors/7\",\n );\n }\n let offchain_receive_fn_and_abi_export = generate_offchain_receive();\n\n let (has_public_init_nullifier_fn, emit_public_init_nullifier_fn_body) = generate_emit_public_init_nullifier(m);\n let public_dispatch = generate_public_dispatch(m, has_public_init_nullifier_fn);\n\n quote {\n $interface\n $self_call_structs\n $call_internal_struct\n $functions\n $fn_abi_exports\n $contract_library_method_compute_note_hash_and_nullifier\n $public_dispatch\n $sync_state_fn_and_abi_export\n $emit_public_init_nullifier_fn_body\n $offchain_receive_fn_and_abi_export\n }\n}\n\ncomptime fn generate_contract_interface(m: Module) -> Quoted {\n let calls = generate_external_function_calls(m);\n\n let module_name = m.name();\n\n let has_storage_layout = module_has_storage(m) & STORAGE_LAYOUT_NAME.get(m).is_some();\n let storage_layout_getter = if has_storage_layout {\n let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap();\n quote {\n pub fn storage_layout() -> StorageLayoutFields {\n $storage_layout_name.fields\n }\n }\n } else {\n quote {}\n };\n\n let library_storage_layout_getter = if has_storage_layout {\n quote {\n #[contract_library_method]\n $storage_layout_getter\n }\n } else {\n quote {}\n };\n\n quote {\n pub struct $module_name {\n pub target_contract: aztec::protocol::address::AztecAddress\n }\n\n impl $module_name {\n $calls\n\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> Self {\n Self { target_contract: addr }\n }\n\n pub fn interface() -> Self {\n Self { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $storage_layout_getter\n }\n\n #[contract_library_method]\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> $module_name {\n $module_name { target_contract: addr }\n }\n\n #[contract_library_method]\n pub fn interface() -> $module_name {\n $module_name { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $library_storage_layout_getter\n\n }\n}\n\n/// Generates the `sync_state` utility function that performs message discovery.\ncomptime fn generate_sync_state(process_custom_message_option: Quoted, offchain_inbox_sync_option: Quoted) -> Quoted {\n quote {\n pub struct sync_state_parameters {\n pub scope: aztec::protocol::address::AztecAddress,\n }\n\n #[abi(functions)]\n pub struct sync_state_abi {\n parameters: sync_state_parameters,\n }\n\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn sync_state(scope: aztec::protocol::address::AztecAddress) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::discovery::do_sync_state(\n address,\n _compute_note_hash,\n _compute_note_nullifier,\n $process_custom_message_option,\n $offchain_inbox_sync_option,\n scope,\n );\n }\n }\n}\n\n/// Generates an `offchain_receive` utility function that lets callers add messages to the offchain message inbox.\n///\n/// For more details, see `aztec::messages::processing::offchain::receive`.\ncomptime fn generate_offchain_receive() -> Quoted {\n quote {\n pub struct offchain_receive_parameters {\n pub messages: BoundedVec<\n aztec::messages::processing::offchain::OffchainMessage,\n aztec::messages::processing::offchain::MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL,\n >,\n }\n\n #[abi(functions)]\n pub struct offchain_receive_abi {\n parameters: offchain_receive_parameters,\n }\n\n /// Receives offchain messages into this contract's offchain inbox for subsequent processing.\n ///\n /// Each message is routed to the inbox scoped to its `recipient` field.\n ///\n /// For more details, see `aztec::messages::processing::offchain::receive`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn offchain_receive(\n messages: BoundedVec<\n aztec::messages::processing::offchain::OffchainMessage,\n aztec::messages::processing::offchain::MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL,\n >,\n ) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::processing::offchain::receive(address, messages);\n }\n }\n}\n\n/// Checks that all functions in the module have a context macro applied.\n///\n/// Non-macroified functions are not allowed in contracts. They must all be one of\n/// [`crate::macros::functions::external`], [`crate::macros::functions::internal`] or `test`.\ncomptime fn check_each_fn_macroified(m: Module) {\n for f in m.functions() {\n let name = f.name();\n if !is_fn_external(f) & !is_fn_contract_library_method(f) & !is_fn_internal(f) & !is_fn_test(f) {\n // We don't suggest that #[contract_library_method] is allowed because we don't want to introduce another\n // concept\n panic(\n f\"Function {name} must be marked as either #[external(...)], #[internal(...)], or #[test]\",\n );\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec.nr","function_locations":[{"start":1648,"name":"AztecConfig::new"},{"start":2156,"name":"AztecConfig::custom_message_handler"},{"start":3050,"name":"aztec"},{"start":6527,"name":"generate_contract_interface"},{"start":8389,"name":"generate_sync_state"},{"start":9443,"name":"generate_offchain_receive"},{"start":11087,"name":"check_each_fn_macroified"}]},"126":{"source":"use crate::logging::{aztecnr_debug_log, aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\npub(crate) mod nonce_discovery;\npub(crate) mod partial_notes;\npub(crate) mod private_events;\npub mod private_notes;\npub mod process_message;\n\nuse crate::{\n messages::{\n discovery::process_message::process_message_ciphertext,\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{\n MessageContext, offchain::OffchainInboxSync, OffchainMessageWithContext,\n pending_tagged_log::PendingTaggedLog, validate_and_store_enqueued_notes_and_events,\n },\n },\n oracle::message_processing,\n utils::array,\n};\n\npub struct NoteHashAndNullifier {\n /// The result of [`crate::note::note_interface::NoteHash::compute_note_hash`].\n pub note_hash: Field,\n /// The result of [`crate::note::note_interface::NoteHash::compute_nullifier_unconstrained`].\n ///\n /// This value is unconstrained, as all of message discovery is unconstrained. It is `None` if the nullifier\n /// cannot be computed (e.g. because the nullifier hiding key is not available).\n pub inner_nullifier: Option,\n}\n\n/// A contract's way of computing note hashes.\n///\n/// Each contract in the network is free to compute their note's hash as they see fit - the hash function itself is not\n/// enshrined or standardized. Some aztec-nr functions however do need to know the details of this computation (e.g.\n/// when finding new notes), which is what this type represents.\n///\n/// This function takes a note's packed content, storage slot, note type ID, address of the emitting contract and\n/// randomness, and attempts to compute its inner note hash (not siloed by address nor uniqued by nonce).\n///\n/// ## Transient Notes\n///\n/// This function is meant to always be used on **settled** notes, i.e. those that have been inserted into the trees\n/// and for which the nonce is known. It is never invoked in the context of a transient note, as those are not involved\n/// in message processing.\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract by inspecting all note types in use and the storage layout. This injected function is a\n/// `#[contract_library_method]` called `_compute_note_hash`, and it looks something like this:\n///\n/// ```noir\n/// |packed_note, owner, storage_slot, note_type_id, _contract_address, randomness| {\n/// if note_type_id == MyNoteType::get_id() {\n/// if packed_note.len() != MY_NOTE_TYPE_SERIALIZATION_LENGTH {\n/// Option::none()\n/// } else {\n/// let note = MyNoteType::unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n/// Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n/// }\n/// } else if note_type_id == MyOtherNoteType::get_id() {\n/// ... // Similar to above but calling MyOtherNoteType::unpack\n/// } else {\n/// Option::none() // Unknown note type ID\n/// };\n/// }\n/// ```\npub type ComputeNoteHash = unconstrained fn(/* packed_note */BoundedVec, /*\n owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress, /*\nrandomness */ Field) -> Option;\n\n/// A contract's way of computing note nullifiers.\n///\n/// Like [`ComputeNoteHash`], each contract is free to derive nullifiers as they see fit. This function takes the\n/// unique note hash (used as the note hash for nullification for settled notes), plus the note's packed content and\n/// metadata, and attempts to compute the inner nullifier (not siloed by address).\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract called `_compute_note_nullifier`. It dispatches on `note_type_id` similarly to\n/// [`ComputeNoteHash`], then calls the note's\n/// [`compute_nullifier_unconstrained`](crate::note::note_interface::NoteHash::compute_nullifier_unconstrained) method.\npub type ComputeNoteNullifier = unconstrained fn(/* unique_note_hash */Field, /* packed_note */ BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/* randomness */ Field) -> Option;\n\n/// Deprecated: use [`ComputeNoteHash`] and [`ComputeNoteNullifier`] instead.\npub type ComputeNoteHashAndNullifier = unconstrained fn[Env](/* packed_note */BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/*randomness */ Field, /* note nonce */ Field) -> Option;\n\n/// A handler for custom messages.\n///\n/// Contracts that emit custom messages (i.e. any with a message type that is not in [`crate::messages::msg_type`])\n/// need to use [`crate::macros::AztecConfig::custom_message_handler`] with a function of this type in order to\n/// process them. They will otherwise be **silently ignored**.\npub type CustomMessageHandler = unconstrained fn[Env](\n/* contract_address */AztecAddress,\n/* msg_type_id */ u64,\n/* msg_metadata */ u64,\n/* msg_content */ BoundedVec,\n/* message_context */ MessageContext,\n/* scope */ AztecAddress);\n\n/// Synchronizes the contract's private state with the network.\n///\n/// As blocks are mined, it is possible for a contract's private state to change (e.g. with new notes being created),\n/// but because these changes are private they will be invisible to most actors. This is the function that processes\n/// new transactions in order to discover new notes, events, and other kinds of private state changes.\n///\n/// The private state will be synchronized up to the block that will be used for private transactions (i.e. the anchor\n/// block. This will typically be close to the tip of the chain.\npub unconstrained fn do_sync_state(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n offchain_inbox_sync: Option>,\n scope: AztecAddress,\n) {\n aztecnr_debug_log!(\"Performing state synchronization\");\n\n // First we process all private logs, which can contain different kinds of messages e.g. private notes, partial\n // notes, private events, etc.\n let logs = message_processing::get_pending_tagged_logs(scope);\n logs.for_each(|_i, pending_tagged_log: PendingTaggedLog| {\n if pending_tagged_log.log.len() == 0 {\n aztecnr_warn_log_format!(\"Skipping empty log from tx {0}\")([pending_tagged_log.context.tx_hash]);\n } else {\n aztecnr_debug_log_format!(\"Processing log with tag {0}\")([pending_tagged_log.log.get(0)]);\n\n // We remove the tag from the pending tagged log and process the message ciphertext contained in it.\n let message_ciphertext = array::subbvec(pending_tagged_log.log, 1);\n\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_ciphertext,\n pending_tagged_log.context,\n scope,\n );\n }\n });\n\n if offchain_inbox_sync.is_some() {\n let msgs = offchain_inbox_sync.unwrap()(contract_address, scope);\n msgs.for_each(|_i, msg: OffchainMessageWithContext| {\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n msg.message_ciphertext,\n msg.message_context,\n scope,\n );\n });\n }\n\n // Then we process all pending partial notes, regardless of whether they were found in the current or previous\n // executions.\n partial_notes::fetch_and_process_partial_note_completion_logs(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n scope,\n );\n\n // Finally we validate all notes and events that were found as part of the previous processes, resulting in them\n // being added to PXE's database and retrievable via oracles (get_notes) and our TS API (PXE::getPrivateEvents).\n validate_and_store_enqueued_notes_and_events(scope);\n}\n\nmod test {\n use crate::ephemeral::EphemeralArray;\n use crate::messages::{\n discovery::{CustomMessageHandler, do_sync_state},\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{offchain::OffchainInboxSync, pending_tagged_log::PendingTaggedLog},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n\n #[test]\n unconstrained fn do_sync_state_does_not_panic_on_empty_logs() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n\n let contract_address = AztecAddress { inner: 0xdeadbeef };\n\n env.utility_context_at(contract_address, |_| {\n // Mock the oracle call to return a known base slot, then populate an ephemeral\n // array at that slot so do_sync_state processes a non-empty log list.\n let base_slot = 42;\n let mock = std::test::OracleMock::mock(\"aztec_utl_getPendingTaggedLogs_v2\");\n let _ = mock.returns(base_slot);\n\n let logs: EphemeralArray = EphemeralArray::at(base_slot);\n logs.push(PendingTaggedLog { log: BoundedVec::new(), context: std::mem::zeroed() });\n assert_eq(logs.len(), 1);\n\n let no_handler: Option> = Option::none();\n let no_inbox_sync: Option> = Option::none();\n do_sync_state(\n contract_address,\n dummy_compute_note_hash,\n dummy_compute_note_nullifier,\n no_handler,\n no_inbox_sync,\n scope,\n );\n });\n }\n\n unconstrained fn dummy_compute_note_hash(\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n\n unconstrained fn dummy_compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr","function_locations":[{"start":6465,"name":"do_sync_state"},{"start":9175,"name":"test::do_sync_state_does_not_panic_on_empty_logs"},{"start":10673,"name":"test::dummy_compute_note_hash"},{"start":11034,"name":"test::dummy_compute_note_nullifier"}]},"127":{"source":"use crate::messages::{discovery::{ComputeNoteHash, ComputeNoteNullifier}, logs::note::MAX_NOTE_PACKED_LEN};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{\n address::AztecAddress,\n constants::MAX_NOTE_HASHES_PER_TX,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::ToField,\n};\n\n/// A struct with the discovered information of a complete note, required for delivery to PXE. Note that this is *not*\n/// the complete note information, since it does not include content, storage slot, etc.\npub(crate) struct DiscoveredNoteInfo {\n pub(crate) note_nonce: Field,\n pub(crate) note_hash: Field,\n pub(crate) inner_nullifier: Field,\n}\n\n/// Searches for note nonces that will result in a note that was emitted in a transaction. While rare, it is possible\n/// for multiple notes to have the exact same packed content and storage slot but different nonces, resulting in\n/// different unique note hashes. Because of this this function returns a *vector* of discovered notes, though in most\n/// cases it will contain a single element.\n///\n/// Due to how nonces are computed, this function requires knowledge of the transaction in which the note was created,\n/// more specifically the list of all unique note hashes in it plus the value of its first nullifier.\npub(crate) unconstrained fn attempt_note_nonce_discovery(\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) -> BoundedVec {\n let discovered_notes = &mut BoundedVec::new();\n\n aztecnr_debug_log_format!(\n \"Attempting nonce discovery on {0} potential notes on contract {1} for storage slot {2}\",\n )(\n [unique_note_hashes_in_tx.len() as Field, contract_address.to_field(), storage_slot],\n );\n\n let maybe_note_hash = compute_note_hash(\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_note_hash.is_none() {\n aztecnr_warn_log_format!(\n \"Unable to compute note hash for note of id {0} with packed length {1}, skipping nonce discovery\",\n )(\n [note_type_id, packed_note.len() as Field],\n );\n } else {\n let note_hash = maybe_note_hash.unwrap();\n let siloed_note_hash = compute_siloed_note_hash(contract_address, note_hash);\n\n // We need to find nonces (typically just one) that result in the siloed note hash that being uniqued into one\n // of the transaction's effects.\n // The nonce is meant to be derived from the index of the note hash in the transaction effects array. However,\n // due to an issue in the kernels the nonce might actually use any of the possible note hash indices - not\n // necessarily the one that corresponds to the note hash. Hence, we need to try them all.\n for i in 0..MAX_NOTE_HASHES_PER_TX {\n let nonce_for_i = compute_note_hash_nonce(first_nullifier_in_tx, i);\n let unique_note_hash_for_i = compute_unique_note_hash(nonce_for_i, siloed_note_hash);\n\n let matching_notes = bvec_filter(\n unique_note_hashes_in_tx,\n |unique_note_hash_in_tx| unique_note_hash_in_tx == unique_note_hash_for_i,\n );\n if matching_notes.len() > 1 {\n let identical_note_hashes = matching_notes.len();\n // Note that we don't actually check that the note hashes array contains unique values, only that the\n // note we found is unique. We don't expect for this to ever happen (it'd indicate a malicious node or\n // PXE, which are both assumed to be cooperative) so testing for it just in case is unnecessary, but we\n // _do_ need to handle it if we find a duplicate.\n panic(\n f\"Received {identical_note_hashes} identical note hashes for a transaction - these should all be unique\",\n )\n } else if matching_notes.len() == 1 {\n let maybe_inner_nullifier_for_i = compute_note_nullifier(\n unique_note_hash_for_i,\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_inner_nullifier_for_i.is_none() {\n // TODO: down the line we want to be able to store notes for which we don't know their nullifier,\n // e.g. notes that belong to someone that is not us (and for which we therefore don't know their\n // associated app-siloed nullifer hiding secret key).\n // https://linear.app/aztec-labs/issue/F-265/store-external-notes\n aztecnr_warn_log_format!(\n \"Unable to compute nullifier of unique note {0} with note type id {1} and owner {2}, skipping PXE insertion\",\n )(\n [unique_note_hash_for_i, note_type_id, owner.to_field()],\n );\n } else {\n // Note that while we did check that the note hash is the preimage of a unique note hash, we\n // perform no validations on the nullifier - we fundamentally cannot, since only the application\n // knows how to compute nullifiers. We simply trust it to have provided the correct one: if it\n // hasn't, then PXE may fail to realize that a given note has been nullified already, and calls to\n // the application could result in invalid transactions (with duplicate nullifiers). This is not a\n // concern because an application already has more direct means of making a call to it fail the\n // transaction.\n discovered_notes.push(\n DiscoveredNoteInfo {\n note_nonce: nonce_for_i,\n note_hash,\n inner_nullifier: maybe_inner_nullifier_for_i.unwrap(),\n },\n );\n }\n // We don't exit the loop - it is possible (though rare) for the exact same note content to be present\n // multiple times in the same transaction with different nonces. This typically doesn't happen due to\n // notes containing random values in order to hide their contents.\n }\n }\n }\n\n *discovered_notes\n}\n\n// There is no BoundedVec::filter in the stdlib, so we use this until that is implemented.\nunconstrained fn bvec_filter(\n bvec: BoundedVec,\n filter: fn[Env](T) -> bool,\n) -> BoundedVec {\n let filtered = &mut BoundedVec::new();\n\n bvec.for_each(|value| {\n if filter(value) {\n filtered.push(value);\n }\n });\n\n *filtered\n}\n\nmod test {\n use crate::{\n messages::logs::note::MAX_NOTE_PACKED_LEN,\n note::{\n note_interface::{NoteHash, NoteType},\n note_metadata::SettledNoteMetadata,\n utils::compute_note_hash_for_nullification,\n },\n oracle::random::random,\n test::mocks::mock_note::MockNote,\n utils::array,\n };\n\n use crate::protocol::{\n address::AztecAddress,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::{FromField, Packable},\n };\n\n use super::attempt_note_nonce_discovery;\n\n // This implementation could be simpler, but this serves as a nice example of the expected flow in a real\n // implementation, and as a sanity check that the interface is sufficient.\n\n unconstrained fn compute_note_hash(\n packed_note: BoundedVec,\n owner: AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n } else {\n Option::none()\n }\n }\n\n unconstrained fn compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n note.compute_nullifier_unconstrained(owner, unique_note_hash)\n } else {\n Option::none()\n }\n }\n\n global VALUE: Field = 7;\n global FIRST_NULLIFIER_IN_TX: Field = 47;\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress::from_field(13);\n global OWNER: AztecAddress = AztecAddress::from_field(14);\n global STORAGE_SLOT: Field = 99;\n global RANDOMNESS: Field = 99;\n\n #[test]\n unconstrained fn no_note_hashes() {\n let unique_note_hashes_in_tx = BoundedVec::new();\n let packed_note = BoundedVec::new();\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n packed_note,\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_hash_computation_is_ignored() {\n let unique_note_hashes_in_tx = BoundedVec::from_array([random()]);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n |_, _, _, _, _, _| Option::none(),\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::new(),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_nullifier_computation_is_ignored() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n |_, _, _, _, _, _, _| Option::none(),\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n struct NoteAndData {\n note: MockNote,\n note_nonce: Field,\n note_hash: Field,\n unique_note_hash: Field,\n inner_nullifier: Field,\n }\n\n unconstrained fn construct_note(value: Field, note_index_in_tx: u32) -> NoteAndData {\n let note_nonce = compute_note_hash_nonce(FIRST_NULLIFIER_IN_TX, note_index_in_tx);\n\n let hinted_note = MockNote::new(value)\n .contract_address(CONTRACT_ADDRESS)\n .owner(OWNER)\n .randomness(RANDOMNESS)\n .storage_slot(STORAGE_SLOT)\n .note_metadata(SettledNoteMetadata::new(note_nonce).into())\n .build_hinted_note();\n let note = hinted_note.note;\n\n let note_hash = note.compute_note_hash(OWNER, STORAGE_SLOT, RANDOMNESS);\n let unique_note_hash = compute_unique_note_hash(\n note_nonce,\n compute_siloed_note_hash(CONTRACT_ADDRESS, note_hash),\n );\n let inner_nullifier = note\n .compute_nullifier_unconstrained(OWNER, compute_note_hash_for_nullification(hinted_note))\n .expect(f\"Could not compute nullifier for note owned by {OWNER}\");\n\n NoteAndData { note, note_nonce, note_hash, unique_note_hash, inner_nullifier }\n }\n\n #[test]\n unconstrained fn single_note() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn multiple_notes_same_preimage() {\n let first_note_index_in_tx = 3;\n let first_note_and_data = construct_note(VALUE, first_note_index_in_tx);\n\n let second_note_index_in_tx = 5;\n let second_note_and_data = construct_note(VALUE, second_note_index_in_tx);\n\n // Both notes have the same preimage (and therefore packed representation), so both should be found in the same\n // call.\n assert_eq(first_note_and_data.note, second_note_and_data.note);\n let packed_note = first_note_and_data.note.pack();\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(first_note_index_in_tx, first_note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(second_note_index_in_tx, second_note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(packed_note),\n );\n\n assert_eq(discovered_notes.len(), 2);\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == first_note_and_data.note_nonce)\n & (discovered_note.note_hash == first_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == first_note_and_data.inner_nullifier)\n }));\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == second_note_and_data.note_nonce)\n & (discovered_note.note_hash == second_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == second_note_and_data.inner_nullifier)\n }));\n }\n\n #[test]\n unconstrained fn single_note_misaligned_nonce() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The note is not at the correct index\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn single_note_nonce_with_index_past_note_hashes_in_tx() {\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The nonce is computed with an index that does not exist in the tx\n let note_index_in_tx = unique_note_hashes_in_tx.len() + 5;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n // The note is inserted at an arbitrary index - its true index is out of the array's bounds\n unique_note_hashes_in_tx.set(2, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test(should_fail_with = \"identical note hashes for a transaction\")]\n unconstrained fn duplicate_unique_note_hashes() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The same unique note hash is present in two indices in the array, which is not allowed. Note that we don't\n // test all note hashes for uniqueness, only those that we actually find.\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let _ = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/nonce_discovery.nr","function_locations":[{"start":1866,"name":"attempt_note_nonce_discovery"},{"start":7210,"name":"bvec_filter"},{"start":8458,"name":"test::compute_note_hash"},{"start":9107,"name":"test::compute_note_nullifier"},{"start":9764,"name":"test::no_note_hashes"},{"start":10362,"name":"test::failed_hash_computation_is_ignored"},{"start":10959,"name":"test::failed_nullifier_computation_is_ignored"},{"start":12052,"name":"test::construct_note"},{"start":13085,"name":"test::single_note"},{"start":14249,"name":"test::multiple_notes_same_preimage"},{"start":16275,"name":"test::single_note_misaligned_nonce"},{"start":17515,"name":"test::single_note_nonce_with_index_past_note_hashes_in_tx"},{"start":18937,"name":"test::duplicate_unique_note_hashes"}]},"128":{"source":"use crate::{\n capsules::CapsuleArray,\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::partial_note::{decode_partial_note_private_message, MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN},\n processing::{\n enqueue_note_for_validation,\n get_pending_partial_notes_completion_logs,\n log_retrieval_response::{LogRetrievalResponse, MAX_LOG_CONTENT_LEN},\n },\n },\n utils::array,\n};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{address::AztecAddress, hash::sha256_to_field, traits::{Deserialize, Serialize}};\n\n/// The slot in the PXE capsules where we store a `CapsuleArray` of `DeliveredPendingPartialNote`.\npub(crate) global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT\".as_bytes(),\n);\n\n/// A partial note that was delivered but is still pending completion. Contains the information necessary to find the\n/// log that will complete it and lead to a note being discovered and delivered.\n#[derive(Serialize, Deserialize)]\npub(crate) struct DeliveredPendingPartialNote {\n pub(crate) owner: AztecAddress,\n pub(crate) randomness: Field,\n pub(crate) note_completion_log_tag: Field,\n pub(crate) note_type_id: Field,\n pub(crate) packed_private_note_content: BoundedVec,\n}\n\npub(crate) unconstrained fn process_partial_note_private_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n scope: AztecAddress,\n) {\n let decoded = decode_partial_note_private_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n // We store the information of the partial note we found in a persistent capsule in PXE, so that we can later\n // search for the public log that will complete it.\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content) = decoded.unwrap();\n\n let pending = DeliveredPendingPartialNote {\n owner,\n randomness,\n note_completion_log_tag,\n note_type_id,\n packed_private_note_content,\n };\n\n CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n )\n .push(pending);\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode partial note private message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Searches for logs that would result in the completion of pending partial notes, ultimately resulting in the notes\n/// being delivered to PXE if completed.\npub(crate) unconstrained fn fetch_and_process_partial_note_completion_logs(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n scope: AztecAddress,\n) {\n let pending_partial_notes = CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n );\n\n aztecnr_debug_log_format!(\"{} pending partial notes\")([pending_partial_notes.len() as Field]);\n\n // Each of the pending partial notes might get completed by a log containing its public values. For performance\n // reasons, we fetch all of these logs concurrently and then process them one by one, minimizing the amount of time\n // waiting for the node roundtrip.\n let maybe_completion_logs = get_pending_partial_notes_completion_logs(contract_address, pending_partial_notes);\n\n // Each entry in the maybe completion logs array corresponds to the entry in the pending partial notes array at the\n // same index. This means we can use the same index as we iterate through the responses to get both the partial\n // note and the log that might complete it.\n assert_eq(maybe_completion_logs.len(), pending_partial_notes.len());\n\n maybe_completion_logs.for_each(|i, maybe_log: Option| {\n let pending_partial_note = pending_partial_notes.get(i);\n\n if maybe_log.is_none() {\n aztecnr_debug_log_format!(\"Found no completion logs for partial note with tag {}\")(\n [pending_partial_note.note_completion_log_tag],\n );\n\n // Note that we're not removing the pending partial note from the capsule array, so we will continue\n // searching for this tagged log when performing message discovery in the future until we either find it or\n // the entry is somehow removed from the array.\n } else {\n aztecnr_debug_log_format!(\"Completion log found for partial note with tag {}\")([\n pending_partial_note.note_completion_log_tag,\n ]);\n let log = maybe_log.unwrap();\n\n // The first field in the completion log payload is the storage slot, followed by the public note\n // content fields.\n let storage_slot = log.log_payload.get(0);\n let public_note_content: BoundedVec = array::subbvec(log.log_payload, 1);\n\n // Public fields are assumed to all be placed at the end of the packed representation, so we combine\n // the private and public packed fields (i.e. the contents of the private message and public log\n // plaintext) to get the complete packed content.\n let complete_packed_note = array::append(\n pending_partial_note.packed_private_note_content,\n public_note_content,\n );\n\n let discovered_notes = attempt_note_nonce_discovery(\n log.unique_note_hashes_in_tx,\n log.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n pending_partial_note.note_type_id,\n complete_packed_note,\n );\n\n // TODO(#11627): is there anything reasonable we can do if we get a log but it doesn't result in a note\n // being found?\n if discovered_notes.len() == 0 {\n panic(\n f\"A partial note's completion log did not result in any notes being found - this should never happen\",\n );\n }\n\n aztecnr_debug_log_format!(\"Discovered {0} notes for partial note with tag {1}\")([\n discovered_notes.len() as Field,\n pending_partial_note.note_completion_log_tag,\n ]);\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n discovered_note.note_nonce,\n complete_packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n log.tx_hash,\n );\n });\n\n // Because there is only a single log for a given tag, once we've processed the tagged log then we simply\n // delete the pending work entry, regardless of whether it was actually completed or not.\n pending_partial_notes.remove(i);\n }\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr","function_locations":[{"start":1784,"name":"process_partial_note_private_msg"},{"start":3162,"name":"fetch_and_process_partial_note_completion_logs"}]},"129":{"source":"use crate::{\n event::event_interface::compute_private_serialized_event_commitment,\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::MAX_MESSAGE_CONTENT_LEN, logs::event::decode_private_event_message,\n processing::enqueue_event_for_validation,\n },\n};\nuse crate::protocol::{address::AztecAddress, traits::ToField};\n\npub(crate) unconstrained fn process_private_event_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n) {\n let decoded = decode_private_event_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (event_type_id, randomness, serialized_event) = decoded.unwrap();\n\n let event_commitment =\n compute_private_serialized_event_commitment(serialized_event, randomness, event_type_id.to_field());\n\n enqueue_event_for_validation(\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private event message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_events.nr","function_locations":[{"start":547,"name":"process_private_event_msg"}]},"130":{"source":"use crate::{\n logging::{aztecnr_debug_log_format, aztecnr_warn_log_format},\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::{decode_private_note_message, MAX_NOTE_PACKED_LEN},\n processing::enqueue_note_for_validation,\n },\n protocol::{address::AztecAddress, constants::MAX_NOTE_HASHES_PER_TX, traits::ToField},\n};\n\npub(crate) unconstrained fn process_private_note_msg(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n msg_metadata: u64,\n msg_content: BoundedVec,\n) {\n let decoded = decode_private_note_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (note_type_id, owner, storage_slot, randomness, packed_note) = decoded.unwrap();\n\n attempt_note_discovery(\n contract_address,\n tx_hash,\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private note message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Attempts discovery of a note given information about its contents and the transaction in which it is suspected the\n/// note was created.\npub unconstrained fn attempt_note_discovery(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) {\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n\n if discovered_notes.len() == 0 {\n // A private note message that results in no discovered notes means none of the computed note hashes matched\n // any unique note hash in the transaction. This could indicate a malformed or malicious message (e.g. a sender\n // providing bogus note content).\n aztecnr_warn_log_format!(\n \"Discarding private note message from tx {0} for contract {1}: no matching note hash found in the tx\",\n )(\n [tx_hash, contract_address.to_field()],\n );\n } else {\n aztecnr_debug_log_format!(\n \"Discovered {0} notes from a private message for contract {1}\",\n )(\n [discovered_notes.len() as Field, contract_address.to_field()],\n );\n }\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n owner,\n storage_slot,\n randomness,\n discovered_note.note_nonce,\n packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n tx_hash,\n );\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_notes.nr","function_locations":[{"start":861,"name":"process_private_note_msg"},{"start":2185,"name":"attempt_note_discovery"}]},"131":{"source":"use crate::messages::{\n discovery::{\n ComputeNoteHash, ComputeNoteNullifier, CustomMessageHandler, partial_notes::process_partial_note_private_msg,\n private_events::process_private_event_msg, private_notes::process_private_note_msg,\n },\n encoding::{decode_message, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN},\n encryption::{aes128::AES128, message_encryption::MessageEncryption},\n msg_type::{\n MIN_CUSTOM_MSG_TYPE_ID, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID, PRIVATE_EVENT_MSG_TYPE_ID, PRIVATE_NOTE_MSG_TYPE_ID,\n },\n processing::MessageContext,\n};\n\nuse crate::logging::{aztecnr_debug_log, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\n/// Processes a message that can contain notes, partial notes, or events.\n///\n/// Notes result in nonce discovery being performed prior to delivery, which requires knowledge of the transaction hash\n/// in which the notes would've been created (typically the same transaction in which the log was emitted), along with\n/// the list of unique note hashes in said transaction and the `compute_note_hash` and `compute_note_nullifier`\n/// functions. Once discovered, the notes are enqueued for validation.\n///\n/// Partial notes result in a pending partial note entry being stored in a PXE capsule, which will later be retrieved\n/// to search for the note's completion public log.\n///\n/// Events are processed by computing an event commitment from the serialized event data and its randomness field, then\n/// enqueueing the event data and commitment for validation.\npub unconstrained fn process_message_ciphertext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_ciphertext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n let message_plaintext_option = AES128::decrypt(message_ciphertext, recipient, contract_address);\n\n if message_plaintext_option.is_some() {\n process_message_plaintext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_plaintext_option.unwrap(),\n message_context,\n recipient,\n );\n } else {\n aztecnr_warn_log_format!(\"Could not decrypt message ciphertext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n\npub(crate) unconstrained fn process_message_plaintext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_plaintext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n // The first thing to do after decrypting the message is to determine what type of message we're processing. We\n // have 3 message types: private notes, partial notes and events.\n\n // We decode the message to obtain the message type id, metadata and content.\n let decoded = decode_message(message_plaintext);\n\n if decoded.is_some() {\n let (msg_type_id, msg_metadata, msg_content) = decoded.unwrap();\n\n if msg_type_id == PRIVATE_NOTE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private note msg\");\n\n process_private_note_msg(\n contract_address,\n message_context.tx_hash,\n message_context.unique_note_hashes_in_tx,\n message_context.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n msg_metadata,\n msg_content,\n );\n } else if msg_type_id == PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing partial note private msg\");\n\n process_partial_note_private_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n recipient,\n );\n } else if msg_type_id == PRIVATE_EVENT_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private event msg\");\n\n process_private_event_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n );\n } else if msg_type_id < MIN_CUSTOM_MSG_TYPE_ID {\n // The message type ID falls in the range reserved for aztec.nr built-in types but wasn't matched above.\n // This most likely means the message is malformed or a custom message was incorrectly assigned a reserved\n // ID. Custom message types must use IDs allocated via `custom_msg_type_id`.\n aztecnr_warn_log_format!(\n \"Message type ID {0} is in the reserved range but is not recognized, ignoring. See https://docs.aztec.network/errors/3\",\n )(\n [msg_type_id as Field],\n );\n } else if process_custom_message.is_some() {\n process_custom_message.unwrap()(\n contract_address,\n msg_type_id,\n msg_metadata,\n msg_content,\n message_context,\n recipient,\n );\n } else {\n // A custom message was received but no handler is configured. This likely means the contract emits custom\n // messages but forgot to register a handler via `AztecConfig::custom_message_handler`.\n aztecnr_warn_log_format!(\n \"Received custom message with type id {0} but no handler is configured, ignoring. See https://docs.aztec.network/errors/2\",\n )(\n [msg_type_id as Field],\n );\n }\n } else {\n aztecnr_warn_log_format!(\"Could not decode message plaintext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/process_message.nr","function_locations":[{"start":1975,"name":"process_message_ciphertext"},{"start":2968,"name":"process_message_plaintext"}]},"132":{"source":"// TODO(#12750): don't make these values assume we're using AES.\nuse crate::protocol::constants::PRIVATE_LOG_CIPHERTEXT_LEN;\nuse crate::utils::array;\n\n// We reassign to the constant here to communicate the distinction between a log and a message. In Aztec.nr, unlike in\n// protocol circuits, we have a concept of a message that can be emitted either as a private log or as an offchain\n// message. Message is a piece of data that is to be eventually delivered to a contract via the `process_message(...)`\n// utility function function that is injected by the #[aztec] macro. Note: PRIVATE_LOG_CIPHERTEXT_LEN is an amount of\n// fields, so MESSAGE_CIPHERTEXT_LEN is the size of the message in fields.\npub global MESSAGE_CIPHERTEXT_LEN: u32 = PRIVATE_LOG_CIPHERTEXT_LEN;\n\n// TODO(#12750): The global variables below should not be here as they are AES128 specific.\n// The header plaintext is 2 bytes (ciphertext length), padded to the 16-byte AES block size by PKCS#7.\npub(crate) global HEADER_CIPHERTEXT_SIZE_IN_BYTES: u32 = 16;\n// AES PKCS#7 always adds at least one byte of padding. Since each plaintext field is 32 bytes (a multiple of the\n// 16-byte AES block size), a full 16-byte padding block is always appended.\npub(crate) global AES128_PKCS7_EXPANSION_IN_BYTES: u32 = 16;\n\npub global EPH_PK_X_SIZE_IN_FIELDS: u32 = 1;\n\n// (15 - 1) * 31 - 16 - 16 = 402. Note: We multiply by 31 because ciphertext bytes are stored in fields using\n// encode_bytes_as_fields, which packs 31 bytes per field (since a Field is ~254 bits and can safely store 31 whole\n// bytes).\npub(crate) global MESSAGE_PLAINTEXT_SIZE_IN_BYTES: u32 = (MESSAGE_CIPHERTEXT_LEN - EPH_PK_X_SIZE_IN_FIELDS) * 31\n - HEADER_CIPHERTEXT_SIZE_IN_BYTES\n - AES128_PKCS7_EXPANSION_IN_BYTES;\n// The plaintext bytes represent Field values that were originally serialized using encode_fields_as_bytes, which\n// converts each Field to 32 bytes. To convert the plaintext bytes back to fields, we divide by 32. 402 / 32 = 12\npub global MESSAGE_PLAINTEXT_LEN: u32 = MESSAGE_PLAINTEXT_SIZE_IN_BYTES / 32;\n\npub global MESSAGE_EXPANDED_METADATA_LEN: u32 = 1;\n\n// The standard message layout is composed of:\n// - an initial field called the 'expanded metadata'\n// - an arbitrary number of fields following that called the 'message content'\n//\n// ```\n// message: [ msg_expanded_metadata, ...msg_content ]\n// ```\n//\n// The expanded metadata itself is interpreted as a u128, of which:\n// - the upper 64 bits are the message type id\n// - the lower 64 bits are called the 'message metadata'\n//\n// ```\n// msg_expanded_metadata: [ msg_type_id | msg_metadata ]\n// <--- 64 bits --->|<--- 64 bits --->\n// ```\n//\n// The meaning of the message metadata and message content depend on the value of the message type id. Note that there\n// is nothing special about the message metadata, it _can_ be considered part of the content. It just has a different\n// name to make it distinct from the message content given that it is not a full field.\n\n/// The maximum length of a message's content, i.e. not including the expanded message metadata.\npub global MAX_MESSAGE_CONTENT_LEN: u32 = MESSAGE_PLAINTEXT_LEN - MESSAGE_EXPANDED_METADATA_LEN;\n\n/// Encodes a message following aztec-nr's standard message encoding. This message can later be decoded with\n/// `decode_message` to retrieve the original values.\n///\n/// - The `msg_type` is an identifier that groups types of messages that are all processed the same way, e.g. private\n/// notes or events. Possible values are defined in `aztec::messages::msg_type`.\n/// - The `msg_metadata` and `msg_content` are the values stored in the message, whose meaning depends on the\n/// `msg_type`. The only special thing about `msg_metadata` that separates it from `msg_content` is that it is a u64\n/// instead of a full Field (due to details of how messages are encoded), allowing applications that can fit values\n/// into this smaller variable to achieve higher data efficiency.\npub fn encode_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; N],\n) -> [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] {\n std::static_assert(\n msg_content.len() <= MAX_MESSAGE_CONTENT_LEN,\n \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\",\n );\n\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n let mut message: [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] = std::mem::zeroed();\n\n message[0] = to_expanded_metadata(msg_type, msg_metadata);\n for i in 0..msg_content.len() {\n message[MESSAGE_EXPANDED_METADATA_LEN + i] = msg_content[i];\n }\n\n message\n}\n\n/// Decodes a standard aztec-nr message, i.e. one created via `encode_message`, returning the original encoded values.\n///\n/// Returns `None` if the message is empty or has invalid (>128 bit) expanded metadata.\n///\n/// Note that `encode_message` returns a fixed size array while this function takes a `BoundedVec`: this is because\n/// prior to decoding the message type is unknown, and consequentially not known at compile time. If working with\n/// fixed-size messages, consider using `BoundedVec::from_array` to convert them.\npub unconstrained fn decode_message(\n message: BoundedVec,\n) -> Option<(u64, u64, BoundedVec)> {\n Option::some(message)\n .and_then(|message| {\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring\n // of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n if message.len() < MESSAGE_EXPANDED_METADATA_LEN {\n Option::none()\n } else {\n Option::some(message.get(0))\n }\n })\n .and_then(|msg_expanded_metadata| from_expanded_metadata(msg_expanded_metadata))\n .map(|(msg_type_id, msg_metadata)| {\n let msg_content = array::subbvec(message, MESSAGE_EXPANDED_METADATA_LEN);\n (msg_type_id, msg_metadata, msg_content)\n })\n}\n\nglobal U64_SHIFT_MULTIPLIER: Field = 2.pow_32(64);\n\nfn to_expanded_metadata(msg_type: u64, msg_metadata: u64) -> Field {\n // We use multiplication instead of bit shifting operations to shift the type bits as bit shift operations are\n // expensive in circuits.\n let type_field: Field = (msg_type as Field) * U64_SHIFT_MULTIPLIER;\n let msg_metadata_field = msg_metadata as Field;\n\n type_field + msg_metadata_field\n}\n\nglobal TWO_POW_128: Field = 2.pow_32(128);\n\n/// Unpacks expanded metadata into (msg_type, msg_metadata). Returns `None` if `input >= 2^128`.\nfn from_expanded_metadata(input: Field) -> Option<(u64, u64)> {\n if input.lt(TWO_POW_128) {\n let msg_metadata = (input as u64);\n let msg_type = ((input - (msg_metadata as Field)) / U64_SHIFT_MULTIPLIER) as u64;\n // Use division instead of bit shift since bit shifts are expensive in circuits\n Option::some((msg_type, msg_metadata))\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray::subarray;\n use super::{\n decode_message, encode_message, from_expanded_metadata, MAX_MESSAGE_CONTENT_LEN, to_expanded_metadata,\n TWO_POW_128,\n };\n\n global U64_MAX: u64 = (2.pow_32(64) - 1) as u64;\n global U128_MAX: Field = (2.pow_32(128) - 1);\n\n #[test]\n unconstrained fn encode_decode_empty_message(msg_type: u64, msg_metadata: u64) {\n let encoded = encode_message(msg_type, msg_metadata, []);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), 0);\n }\n\n #[test]\n unconstrained fn encode_decode_short_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN / 2],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn encode_decode_full_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn to_expanded_metadata_packing() {\n // Test case 1: All bits set\n let packed = to_expanded_metadata(U64_MAX, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let packed = to_expanded_metadata(U64_MAX, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let packed = to_expanded_metadata(0, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let packed = to_expanded_metadata(0, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn from_expanded_metadata_packing() {\n // Test case 1: All bits set\n let input = U128_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let input = (U128_MAX - U64_MAX as Field);\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let input = U64_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let input = 0;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn to_from_expanded_metadata(original_msg_type: u64, original_msg_metadata: u64) {\n let packed = to_expanded_metadata(original_msg_type, original_msg_metadata);\n let (unpacked_msg_type, unpacked_msg_metadata) = from_expanded_metadata(packed).unwrap();\n\n assert_eq(original_msg_type, unpacked_msg_type);\n assert_eq(original_msg_metadata, unpacked_msg_metadata);\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_message() {\n let msg_type_id: u64 = 42;\n let msg_metadata: u64 = 99;\n let mut msg_content = [0; MAX_MESSAGE_CONTENT_LEN];\n for i in 0..MAX_MESSAGE_CONTENT_LEN {\n msg_content[i] = i as Field;\n }\n\n let encoded = encode_message(msg_type_id, msg_metadata, msg_content);\n let (decoded_type_id, decoded_metadata, decoded_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_type_id, msg_type_id);\n assert_eq(decoded_metadata, msg_metadata);\n assert_eq(decoded_content, BoundedVec::from_array(msg_content));\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_message_fails() {\n let msg_content = [0; MAX_MESSAGE_CONTENT_LEN + 1];\n let _ = encode_message(0, 0, msg_content);\n }\n\n #[test]\n unconstrained fn decode_empty_message_returns_none() {\n assert(decode_message(BoundedVec::new()).is_none());\n }\n\n #[test]\n unconstrained fn decode_message_with_oversized_metadata_returns_none() {\n let message = BoundedVec::from_array([TWO_POW_128]);\n assert(decode_message(message).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encoding.nr","function_locations":[{"start":4136,"name":"encode_message"},{"start":5594,"name":"decode_message"},{"start":6617,"name":"to_expanded_metadata"},{"start":7131,"name":"from_expanded_metadata"},{"start":7894,"name":"tests::encode_decode_empty_message"},{"start":8444,"name":"tests::encode_decode_short_message"},{"start":9090,"name":"tests::encode_decode_full_message"},{"start":9628,"name":"tests::to_expanded_metadata_packing"},{"start":10713,"name":"tests::from_expanded_metadata_packing"},{"start":11770,"name":"tests::to_from_expanded_metadata"},{"start":12151,"name":"tests::encode_decode_max_size_message"},{"start":12934,"name":"tests::encode_oversized_message_fails"},{"start":13123,"name":"tests::decode_empty_message_returns_none"},{"start":13280,"name":"tests::decode_message_with_oversized_metadata_returns_none"}]},"133":{"source":"use crate::protocol::{address::AztecAddress, public_keys::AddressPoint, traits::ToField};\n\nuse crate::{\n keys::{\n ecdh_shared_secret::{\n compute_app_siloed_shared_secret, derive_ecdh_shared_secret, derive_shared_secret_field_mask,\n derive_shared_secret_subkey,\n },\n ephemeral::generate_positive_ephemeral_key_pair,\n },\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::{\n EPH_PK_X_SIZE_IN_FIELDS, HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN,\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES,\n },\n encryption::message_encryption::MessageEncryption,\n logs::arithmetic_generics_utils::{\n get_arr_of_size__message_bytes__from_PT, get_arr_of_size__message_bytes_padding__from_PT,\n },\n },\n oracle::{aes128_decrypt::try_aes128_decrypt, random::random, shared_secret::get_shared_secret},\n utils::{\n array,\n conversion::{\n bytes_as_fields::{decode_bytes_from_fields, encode_bytes_as_fields},\n fields_as_bytes::{encode_fields_as_bytes, try_decode_fields_from_bytes},\n },\n point::point_from_x_coord_and_sign,\n },\n};\n\nuse std::aes128::aes128_encrypt;\n\n/// Computes N close-to-uniformly-random 256 bits from a given app-siloed shared secret.\n///\n/// NEVER re-use the same iv and sym_key. DO NOT call this function more than once with the same s_app.\n///\n/// This function is only known to be safe if s_app is derived from combining a random ephemeral key with an\n/// address point and a contract address. See big comment within the body of the function.\nfn extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app: Field) -> [[u8; 32]; N] {\n /*\n * Unsafe because of https://eprint.iacr.org/2010/264.pdf Page 13, Lemma 2 (and the two paragraphs below it).\n *\n * If you call this function, you need to be careful and aware of how the arg `s_app` has been derived.\n *\n * The paper says that the way you derive aes keys and IVs should be fine with poseidon2 (modelled as a RO),\n * as long as you _don't_ use Poseidon2 as a PRG to generate the two exponents x & y which multiply to the\n * shared secret S:\n *\n * S = [x*y]*G.\n *\n * (Otherwise, you would have to \"key\" poseidon2, i.e. generate a uniformly string K which can be public and\n * compute Hash(x) as poseidon(K,x)).\n * In that lemma, k would be 2*254=508, and m would be the number of points on the grumpkin curve (which is\n * close to r according to the Hasse bound).\n *\n * Our shared secret S is [esk * address_sk] * G, and the question is: Can we compute hash(S) using poseidon2\n * instead of sha256?\n *\n * Well, esk is random and not generated with poseidon2, so that's good.\n * What about address_sk?\n * Well, address_sk = poseidon2(stuff) + ivsk, so there was some discussion about whether address_sk is\n * independent of poseidon2. Given that ivsk is random and independent of poseidon2, the address_sk is also\n * independent of poseidon2.\n *\n * Tl;dr: we believe it's safe to hash S = [esk * address_sk] * G using poseidon2, in order to derive a\n * symmetric key.\n *\n * If you're calling this function for a differently-derived `s_app`, be careful.\n */\n \n\n /* The output of this function needs to be 32 random bytes.\n * A single field won't give us 32 bytes of entropy. So we compute two \"random\" fields, by poseidon-hashing\n * with two different indices. We then extract the last 16 (big endian) bytes of each \"random\" field.\n * Note: we use to_be_bytes because it's slightly more efficient. But we have to be careful not to take bytes\n * from the \"big end\", because the \"big\" byte is not uniformly random over the byte: it only has < 6 bits of\n * randomness, because it's the big end of a 254-bit field element.\n */\n\n let mut all_bytes: [[u8; 32]; N] = std::mem::zeroed();\n std::static_assert(N < 256, \"N too large\");\n for k in 0..N {\n let rand1: Field = derive_shared_secret_subkey(s_app, 2 * k);\n let rand2: Field = derive_shared_secret_subkey(s_app, 2 * k + 1);\n\n let rand1_bytes: [u8; 32] = rand1.to_be_bytes();\n let rand2_bytes: [u8; 32] = rand2.to_be_bytes();\n\n let mut bytes: [u8; 32] = [0; 32];\n for i in 0..16 {\n // We take bytes from the \"little end\" of the be-bytes arrays:\n let j = 32 - i - 1;\n bytes[i] = rand1_bytes[j];\n bytes[16 + i] = rand2_bytes[j];\n }\n\n all_bytes[k] = bytes;\n }\n\n all_bytes\n}\n\nfn derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(\n many_random_256_bits: [[u8; 32]; N],\n) -> [([u8; 16], [u8; 16]); N] {\n // Many (sym_key, iv) pairs:\n let mut many_pairs: [([u8; 16], [u8; 16]); N] = std::mem::zeroed();\n for k in 0..N {\n let random_256_bits = many_random_256_bits[k];\n let mut sym_key = [0; 16];\n let mut iv = [0; 16];\n for i in 0..16 {\n sym_key[i] = random_256_bits[i];\n iv[i] = random_256_bits[i + 16];\n }\n many_pairs[k] = (sym_key, iv);\n }\n\n many_pairs\n}\n\npub fn derive_aes_symmetric_key_and_iv_from_shared_secret(s_app: Field) -> [([u8; 16], [u8; 16]); N] {\n let many_random_256_bits: [[u8; 32]; N] = extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app);\n\n derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(many_random_256_bits)\n}\n\npub struct AES128 {}\n\nimpl MessageEncryption for AES128 {\n\n /// AES128-CBC encryption for Aztec protocol messages.\n ///\n /// ## Overview\n ///\n /// The plaintext is an array of up to `MESSAGE_PLAINTEXT_LEN` (12) fields. The output is always exactly\n /// `MESSAGE_CIPHERTEXT_LEN` (15) fields, regardless of plaintext size. All output fields except the\n /// ephemeral public key are uniformly random `Field` values to any observer without knowledge of the\n /// shared secret, making all encrypted messages indistinguishable by size or content.\n ///\n /// ## PKCS#7 Padding\n ///\n /// AES operates on 16-byte blocks, so the plaintext must be padded to a multiple of 16. PKCS#7 padding always\n /// adds at least 1 byte (so the receiver can always detect and strip it), which means:\n /// - 1 B plaintext -> 15 B padding -> 16 B total\n /// - 15 B plaintext -> 1 B padding -> 16 B total\n /// - 16 B plaintext -> 16 B padding -> 32 B total (full extra block)\n ///\n /// In general: if the plaintext is already a multiple of 16, a full 16-byte padding block is appended.\n ///\n /// ## Encryption Steps\n ///\n /// **1. Body encryption.** The plaintext fields are serialized to bytes (32 bytes per field) and AES-128-CBC\n /// encrypted. Since 32 is a multiple of 16, PKCS#7 always adds a full 16-byte padding block (see above):\n ///\n /// ```text\n /// +---------------------------------------------+\n /// | body ct |\n /// | PlaintextLen*32 + 16 B |\n /// +-------------------------------+--------------+\n /// | encrypted plaintext fields | PKCS#7 (16B) |\n /// | (serialized at 32 B each) | |\n /// +-------------------------------+--------------+\n /// ```\n ///\n /// **2. Header encryption.** The byte length of `body_ct` is stored as a 2-byte big-endian integer. This 2-byte\n /// header plaintext is then AES-encrypted; PKCS#7 pads the remaining 14 bytes to fill one 16-byte AES block,\n /// producing a 16-byte header ciphertext:\n ///\n /// ```text\n /// +---------------------------+\n /// | header ct |\n /// | 16 B |\n /// +--------+------------------+\n /// | body ct| PKCS#7 (14B) |\n /// | length | |\n /// | (2 B) | |\n /// +--------+------------------+\n /// ```\n ///\n /// ## Wire Format\n ///\n /// Messages are transmitted as fields, not bytes. A field is ~254 bits and can safely store 31 whole bytes, so\n /// we need to pack our byte data into 31-byte chunks. This packing drives the wire format.\n ///\n /// **Step 1 -- Assemble bytes.** The ciphertexts are laid out in a byte array, padded with zero bytes to a\n /// multiple of 31 so it divides evenly into fields:\n ///\n /// ```text\n /// +------------+-------------------------+---------+\n /// | header ct | body ct | byte pad|\n /// | 16 B | PlaintextLen*32 + 16 B | (zeros) |\n /// +------------+-------------------------+---------+\n /// |<-------- padded to a multiple of 31 B -------->|\n /// ```\n ///\n /// **Step 2 -- Pack and mask.** The byte array is split into 31-byte chunks, each stored in one field. A\n /// Poseidon2-derived mask (see `derive_shared_secret_field_mask`) is added to each so that the resulting\n /// fields appear as uniformly random `Field` values to any observer without knowledge of the shared secret,\n /// hiding the fact that the underlying ciphertext consists of 128-bit AES blocks.\n ///\n /// **Step 3 -- Assemble ciphertext.** The ephemeral public key x-coordinate is prepended and random field padding\n /// is appended to fill to 15 fields:\n ///\n /// ```text\n /// +----------+-------------------------+-------------------+\n /// | eph_pk.x | masked message fields | random field pad |\n /// | | (packed 31 B per field) | (fills to 15) |\n /// +----------+-------------------------+-------------------+\n /// |<---------- MESSAGE_CIPHERTEXT_LEN = 15 fields -------->|\n /// ```\n ///\n /// ## Key Derivation\n ///\n /// The raw ECDH shared secret point is first app-siloed into a scalar `s_app` by hashing with the contract\n /// address (see\n /// [`compute_app_siloed_shared_secret`](crate::keys::ecdh_shared_secret::compute_app_siloed_shared_secret)).\n /// Two (key, IV) pairs are then derived from `s_app` via indexed Poseidon2 hashing: one pair for the body\n /// ciphertext and one for the header ciphertext.\n fn encrypt(\n plaintext: [Field; PlaintextLen],\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> [Field; MESSAGE_CIPHERTEXT_LEN] {\n std::static_assert(\n PlaintextLen <= MESSAGE_PLAINTEXT_LEN,\n \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\",\n );\n\n // AES 128 operates on bytes, not fields, so we need to convert the fields to bytes. (This process is then\n // reversed when processing the message in `process_message_ciphertext`)\n let plaintext_bytes = encode_fields_as_bytes(plaintext);\n\n // Derive ECDH shared secret with recipient using a fresh ephemeral keypair.\n let (eph_sk, eph_pk) = generate_positive_ephemeral_key_pair();\n\n let raw_shared_secret = derive_ecdh_shared_secret(\n eph_sk,\n recipient\n .to_address_point()\n .unwrap_or_else(|| {\n aztecnr_warn_log_format!(\n \"Attempted to encrypt message for an invalid recipient ({0})\",\n )(\n [recipient.to_field()],\n );\n\n // Safety: if the recipient is an invalid address, then it is not possible to encrypt a message for\n // them because we cannot establish a shared secret. This is never expected to occur during normal\n // operation. However, it is technically possible for us to receive an invalid address, and we must\n // therefore handle it. We could simply fail, but that'd introduce a potential security issue in\n // which an attacker forces a contract to encrypt a message for an invalid address, resulting in an\n // impossible transaction - this is sometimes called a 'king of the hill' attack. We choose instead\n // to not fail and encrypt the plaintext regardless using the shared secret that results from a\n // random valid address. The sender is free to choose this address and hence shared secret, but\n // this has no security implications as they already know not only the full plaintext but also the\n // ephemeral private key anyway.\n unsafe {\n random_address_point()\n }\n })\n .inner,\n );\n\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n // It is safe to derive AES keys from `s_app` using Poseidon2 because `s_app` was derived from an ECDH shared\n // secret using an AztecAddress (the recipient). See the block comment in\n // `extract_many_close_to_uniformly_random_256_bits_using_poseidon2` for more info.\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n let ciphertext_bytes = aes128_encrypt(plaintext_bytes, body_iv, body_sym_key);\n\n // Each plaintext field is 32 bytes (a multiple of the 16-byte AES block\n // size), so PKCS#7 always appends a full 16-byte padding block:\n // |ciphertext| = PlaintextLen*32 + 16 = 16 * (1 + PlaintextLen*32 / 16)\n std::static_assert(\n ciphertext_bytes.len() == 16 * (1 + (PlaintextLen * 32) / 16),\n \"unexpected ciphertext length\",\n );\n\n // Encrypt a 2-byte header containing the body ciphertext length.\n let header_plaintext = encode_header(ciphertext_bytes.len());\n\n // Note: the aes128_encrypt builtin fn automatically appends bytes to the input, according to pkcs#7; hence why\n // the output `header_ciphertext_bytes` is 16 bytes larger than the input in this case.\n let header_ciphertext_bytes = aes128_encrypt(header_plaintext, header_iv, header_sym_key);\n // Verify expected header ciphertext size at compile time.\n std::static_assert(\n header_ciphertext_bytes.len() == HEADER_CIPHERTEXT_SIZE_IN_BYTES,\n \"unexpected ciphertext header length\",\n );\n\n // Assemble the message byte array:\n // [header_ct (16B)] [body_ct] [padding to mult of 31]\n let message_bytes_padding_to_mult_31 = get_arr_of_size__message_bytes_padding__from_PT::();\n\n let mut message_bytes = get_arr_of_size__message_bytes__from_PT::();\n\n std::static_assert(\n message_bytes.len() % 31 == 0,\n \"Unexpected error: message_bytes.len() should be divisible by 31, by construction.\",\n );\n\n let mut offset = 0;\n for i in 0..header_ciphertext_bytes.len() {\n message_bytes[offset + i] = header_ciphertext_bytes[i];\n }\n offset += header_ciphertext_bytes.len();\n\n for i in 0..ciphertext_bytes.len() {\n message_bytes[offset + i] = ciphertext_bytes[i];\n }\n offset += ciphertext_bytes.len();\n\n for i in 0..message_bytes_padding_to_mult_31.len() {\n message_bytes[offset + i] = message_bytes_padding_to_mult_31[i];\n }\n offset += message_bytes_padding_to_mult_31.len();\n\n // Ideally we would be able to have a static assert where we check that the offset would be such that we've\n // written to the entire log_bytes array, but we cannot since Noir does not treat the offset as a comptime\n // value (despite the values that it goes through being known at each stage). We instead check that the\n // computation used to obtain the offset computes the expected value (which we _can_ do in a static check), and\n // then add a cheap runtime check to also validate that the offset matches this.\n std::static_assert(\n header_ciphertext_bytes.len() + ciphertext_bytes.len() + message_bytes_padding_to_mult_31.len()\n == message_bytes.len(),\n \"unexpected message length\",\n );\n assert(offset == message_bytes.len(), \"unexpected encrypted message length\");\n\n // Pack message bytes into fields (31 bytes per field) and prepend eph_pk.x.\n let message_bytes_as_fields = encode_bytes_as_fields(message_bytes);\n\n let mut ciphertext: [Field; MESSAGE_CIPHERTEXT_LEN] = [0; MESSAGE_CIPHERTEXT_LEN];\n\n ciphertext[0] = eph_pk.x;\n\n // Mask each content field with a Poseidon2-derived value, so that they appear as uniformly random `Field`\n // values\n let mut offset = 1;\n for i in 0..message_bytes_as_fields.len() {\n let mask = derive_shared_secret_field_mask(s_app, i as u32);\n ciphertext[offset + i] = message_bytes_as_fields[i] + mask;\n }\n offset += message_bytes_as_fields.len();\n\n // Pad with random fields so that padding is indistinguishable from masked data fields.\n for i in offset..MESSAGE_CIPHERTEXT_LEN {\n // Safety: we assume that the sender wants for the message to be private - a malicious one could simply\n // reveal its contents publicly. It is therefore fine to trust the sender to provide random padding.\n ciphertext[i] = unsafe { random() };\n }\n\n ciphertext\n }\n\n unconstrained fn decrypt(\n ciphertext: BoundedVec,\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> Option> {\n // Extract the ephemeral public key x-coordinate and masked fields, returning None for empty ciphertext.\n if ciphertext.len() > 0 {\n let masked_fields: BoundedVec =\n array::subbvec(ciphertext, EPH_PK_X_SIZE_IN_FIELDS);\n Option::some((ciphertext.get(0), masked_fields))\n } else {\n Option::none()\n }\n .and_then(|(eph_pk_x, masked_fields)| {\n // With the x-coordinate of the ephemeral public key we can reconstruct the point as we know that the\n // y-coordinate must be positive. This may fail however, as not all x-coordinates are on the curve. In\n // that case, we simply return `Option::none`.\n point_from_x_coord_and_sign(eph_pk_x, true).and_then(|eph_pk| {\n let s_app = get_shared_secret(recipient, eph_pk, contract_address);\n\n let unmasked_fields = masked_fields.mapi(|i, field| {\n let unmasked = unmask_field(s_app, i, field);\n // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it\n // later, so we can simply set it to 0\n unmasked.unwrap_or(0)\n });\n let ciphertext_without_eph_pk_x = decode_bytes_from_fields(unmasked_fields);\n\n // Derive symmetric keys:\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n // Extract the header ciphertext\n let header_start = 0;\n let header_ciphertext: [u8; HEADER_CIPHERTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), header_start);\n // We need to convert the array to a BoundedVec because the oracle expects a BoundedVec as it's\n // designed to work with messages with unknown length at compile time. This would not be necessary\n // here as the header ciphertext length is fixed. But we do it anyway to not have to have duplicate\n // oracles.\n let header_ciphertext_bvec =\n BoundedVec::::from_array(header_ciphertext);\n\n try_aes128_decrypt(header_ciphertext_bvec, header_iv, header_sym_key)\n // Extract ciphertext length from header (2 bytes, big-endian)\n .and_then(|header_plaintext| extract_ciphertext_length(header_plaintext))\n .filter(|ciphertext_length| ciphertext_length <= MESSAGE_PLAINTEXT_SIZE_IN_BYTES)\n .map(|ciphertext_length| {\n // Extract and decrypt main ciphertext\n let ciphertext_start = header_start + HEADER_CIPHERTEXT_SIZE_IN_BYTES;\n let ciphertext_with_padding: [u8; MESSAGE_PLAINTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), ciphertext_start);\n BoundedVec::from_parts(ciphertext_with_padding, ciphertext_length)\n })\n // Decrypt main ciphertext and return it\n .and_then(|ciphertext| try_aes128_decrypt(ciphertext, body_iv, body_sym_key))\n // Convert bytes back to fields (32 bytes per field). Returns None if the actual bytes are\n // not valid.\n .and_then(|plaintext_bytes| try_decode_fields_from_bytes(plaintext_bytes))\n })\n })\n }\n}\n\n/// Encodes the body ciphertext length into a 2-byte big-endian header.\nfn encode_header(ciphertext_length: u32) -> [u8; 2] {\n [(ciphertext_length >> 8) as u8, ciphertext_length as u8]\n}\n\n/// Extracts the body ciphertext length from a decrypted header as a 2-byte big-endian integer.\n///\n/// Returns `Option::none()` if the header has fewer than 2 bytes.\nunconstrained fn extract_ciphertext_length(header: BoundedVec) -> Option {\n if header.len() >= 2 {\n Option::some(((header.get(0) as u32) << 8) | (header.get(1) as u32))\n } else {\n Option::none()\n }\n}\n\n/// 2^248: upper bound for values that fit in 31 bytes\nglobal TWO_POW_248: Field = 2.pow_32(248);\n\n/// Removes the Poseidon2-derived mask from a ciphertext field. Returns the unmasked value if it fits in 31 bytes\n/// (a content field), or `None` if it doesn't (random padding). Unconstrained to prevent accidental use in\n/// constrained context.\nunconstrained fn unmask_field(s_app: Field, index: u32, masked: Field) -> Option {\n let unmasked = masked - derive_shared_secret_field_mask(s_app, index);\n if unmasked.lt(TWO_POW_248) {\n Option::some(unmasked)\n } else {\n Option::none()\n }\n}\n\n/// Produces a random valid address point, i.e. one that is on the curve. This is equivalent to calling\n/// [`AztecAddress::to_address_point`] on a random valid address.\nunconstrained fn random_address_point() -> AddressPoint {\n let mut result = std::mem::zeroed();\n\n loop {\n // We simply produce random x coordinates until we find one that is on the curve. About half of the x\n // coordinates fulfill this condition, so this should only take a few iterations at most.\n let x_coord = random();\n let point = point_from_x_coord_and_sign(x_coord, true);\n if point.is_some() {\n result = AddressPoint { inner: point.unwrap() };\n break;\n }\n }\n\n result\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::{compute_app_siloed_shared_secret, derive_ecdh_shared_secret},\n messages::{\n encoding::{HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_PLAINTEXT_LEN, MESSAGE_PLAINTEXT_SIZE_IN_BYTES},\n encryption::message_encryption::MessageEncryption,\n },\n test::helpers::test_environment::TestEnvironment,\n };\n use crate::protocol::{address::AztecAddress, traits::FromField};\n use super::{AES128, encode_header, random_address_point};\n use std::{embedded_curve_ops::EmbeddedCurveScalar, test::OracleMock};\n\n #[test]\n unconstrained fn encrypt_decrypt_deterministic() {\n let env = TestEnvironment::new();\n\n // Message decryption requires oracles that are only available during private execution\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n\n let recipient = AztecAddress::from_field(\n 0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70c,\n );\n\n // Mock random values for deterministic test\n let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(eph_sk).times(1);\n\n let randomness = 0x0101010101010101010101010101010101010101010101010101010101010101;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(randomness).times(1000000);\n\n let _ = OracleMock::mock(\"aztec_prv_getNextAppTagAsSender\").returns(42);\n\n // Encrypt the message\n let encrypted_message = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n // Compute the same app-siloed shared secret that the oracle would return\n let raw_shared_secret = derive_ecdh_shared_secret(\n EmbeddedCurveScalar::from_field(eph_sk),\n recipient.to_address_point().unwrap().inner,\n );\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n let _ = OracleMock::mock(\"aztec_utl_getSharedSecret\").returns(s_app);\n\n // Decrypt the message\n let decrypted = AES128::decrypt(encrypted_message, recipient, contract_address).unwrap();\n\n // The decryption function spits out a BoundedVec because it's designed to work with messages with unknown\n // length at compile time. For this reason we need to convert the original input to a BoundedVec.\n let plaintext_bvec = BoundedVec::::from_array(plaintext);\n\n // Verify decryption matches original plaintext\n assert_eq(decrypted, plaintext_bvec, \"Decrypted bytes should match original plaintext\");\n\n // The following is a workaround of \"struct is never constructed\" Noir compilation error (we only ever use\n // static methods of the struct).\n let _ = AES128 {};\n });\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_random() {\n // Same as `encrypt_decrypt_deterministic`, except we don't mock any of the oracles and rely on\n // `TestEnvironment` instead.\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test]\n unconstrained fn encrypt_to_invalid_address() {\n // x = 3 is a non-residue for this curve, resulting in an invalid address\n let invalid_address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n\n let _ = AES128::encrypt([1, 2, 3, 4], invalid_address, contract_address);\n }\n\n // Documents the PKCS#7 padding behavior that `encrypt` relies on (see its static_assert).\n #[test]\n fn pkcs7_padding_always_adds_at_least_one_byte() {\n let key = [0 as u8; 16];\n let iv = [0 as u8; 16];\n\n // 1 byte input + 15 bytes padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 1], iv, key).len(), 16);\n\n // 15 bytes input + 1 byte padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 15], iv, key).len(), 16);\n\n // 16 bytes input (block-aligned) + full 16-byte padding block = 32 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 16], iv, key).len(), 32);\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_max_size_plaintext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let mut plaintext = [0; MESSAGE_PLAINTEXT_LEN];\n for i in 0..MESSAGE_PLAINTEXT_LEN {\n plaintext[i] = i as Field;\n }\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test(should_fail_with = \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\")]\n unconstrained fn encrypt_oversized_plaintext() {\n let address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n let plaintext: [Field; MESSAGE_PLAINTEXT_LEN + 1] = [0; MESSAGE_PLAINTEXT_LEN + 1];\n let _ = AES128::encrypt(plaintext, address, contract_address);\n }\n\n #[test]\n unconstrained fn random_address_point_produces_valid_points() {\n // About half of random addresses are invalid, so testing just a couple gives us high confidence that\n // `random_address_point` is indeed producing valid addresses.\n for _ in 0..10 {\n let random_address = AztecAddress { inner: random_address_point().inner.x };\n assert(random_address.to_address_point().is_some());\n }\n }\n\n #[test]\n unconstrained fn decrypt_invalid_ephemeral_public_key() {\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3, 4];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n // The first field of the ciphertext is the x-coordinate of the ephemeral public key. We set it to a known\n // non-residue (3), causing `decrypt` to fail to produce a decryption shared secret.\n let mut bad_ciphertext = BoundedVec::from_array(ciphertext);\n bad_ciphertext.set(0, 3);\n\n assert(AES128::decrypt(bad_ciphertext, recipient, contract_address).is_none());\n });\n }\n\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_ciphertext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n assert(AES128::decrypt(BoundedVec::new(), recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header AES decrypt oracle to return an empty result. The TS oracle never throws on invalid\n // input: it decrypts to garbage bytes or returns empty\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_header() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let empty_header = BoundedVec::::new();\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(empty_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header oracle to return a 2-byte header that decodes to a ciphertext_length one past the maximum\n // allowed value, verifying the edge case is handled correctly.\n #[test]\n unconstrained fn decrypt_returns_none_on_oversized_ciphertext_length() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let bad_header = BoundedVec::::from_array(encode_header(\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES + 1,\n ));\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(bad_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr","function_locations":[{"start":1764,"name":"extract_many_close_to_uniformly_random_256_bits_using_poseidon2"},{"start":4783,"name":"derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits"},{"start":5332,"name":"derive_aes_symmetric_key_and_iv_from_shared_secret"},{"start":10365,"name":"::encrypt"},{"start":17702,"name":"::decrypt"},{"start":21732,"name":"encode_header"},{"start":22063,"name":"extract_ciphertext_length"},{"start":22648,"name":"unmask_field"},{"start":23061,"name":"random_address_point"},{"start":24228,"name":"test::encrypt_decrypt_deterministic"},{"start":26706,"name":"test::encrypt_decrypt_random"},{"start":27552,"name":"test::encrypt_to_invalid_address"},{"start":28002,"name":"test::pkcs7_padding_always_adds_at_least_one_byte"},{"start":28566,"name":"test::encrypt_decrypt_max_size_plaintext"},{"start":29465,"name":"test::encrypt_oversized_plaintext"},{"start":29823,"name":"test::random_address_point_produces_valid_points"},{"start":30274,"name":"test::decrypt_invalid_ephemeral_public_key"},{"start":31119,"name":"test::decrypt_returns_none_on_empty_ciphertext"},{"start":31673,"name":"test::decrypt_returns_none_on_empty_header"},{"start":32599,"name":"test::decrypt_returns_none_on_oversized_ciphertext_length"}]},"138":{"source":"use crate::{\n event::{event_interface::EventInterface, EventSelector},\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n utils::array,\n};\nuse crate::protocol::traits::{FromField, Serialize, ToField};\n\n/// The number of fields in a private event message content that are not the event's serialized representation (1 field\n/// for randomness).\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 1;\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 0;\n\n/// The maximum length of the packed representation of an event's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, randomness, etc.).\npub global MAX_EVENT_SERIALIZED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_event_message`].\npub fn encode_private_event_message(\n event: Event,\n randomness: Field,\n) -> [Field; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Event: EventInterface + Serialize,\n{\n std::static_assert(\n ::N <= MAX_EVENT_SERIALIZED_LEN,\n \"event's serialized length exceeds the maximum allowed for private events\",\n );\n\n // We use `Serialize` because we want for events to be processable by off-chain actors, e.g. block explorers,\n // wallets and apps, without having to rely on contract invocation. If we used `Packable` we'd need to call utility\n // functions in order to unpack events, which would introduce a level of complexity we don't currently think is\n // worth the savings in DA (for public events) and proving time (when encrypting private event messages).\n let serialized_event = event.serialize();\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_plaintext = [0; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n\n for i in 0..serialized_event.len() {\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = serialized_event[i];\n }\n\n // The event type id is stored in the message metadata\n encode_message(\n PRIVATE_EVENT_MSG_TYPE_ID,\n Event::get_event_type_id().to_field() as u64,\n msg_plaintext,\n )\n}\n\n/// Decodes the plaintext from a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_event_message`].\n///\n/// Note that while [`encode_private_event_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_event_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(EventSelector, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let event_type_id = EventSelector::from_field(msg_metadata as Field);\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // destructuring of the private event message encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let randomness = msg_content.get(PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let serialized_event = array::subbvec(msg_content, PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((event_type_id, randomness, serialized_event))\n }\n}\n\nmod test {\n use crate::{\n event::event_interface::EventInterface,\n messages::{\n encoding::decode_message,\n logs::event::{decode_private_event_message, encode_private_event_message},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n };\n use crate::protocol::traits::Serialize;\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let event = MockEvent::new(VALUE).build_event();\n\n let message_plaintext = encode_private_event_message(event, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_EVENT_MSG_TYPE_ID);\n\n let (event_type_id, randomness, serialized_event) =\n decode_private_event_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(event_type_id, MockEvent::get_event_type_id());\n assert_eq(randomness, RANDOMNESS);\n assert_eq(serialized_event, BoundedVec::from_array(event.serialize()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_event_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0]);\n assert(decode_private_event_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/event.nr","function_locations":[{"start":1377,"name":"encode_private_event_message"},{"start":3755,"name":"decode_private_event_message"},{"start":5127,"name":"test::encode_decode"},{"start":5869,"name":"test::decode_empty_content_returns_none"},{"start":6064,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"140":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\n\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX: u32 = 1;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 2;\n\n/// The maximum length of the packed representation of a note's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, storage slot, randomness, etc.).\npub global MAX_NOTE_PACKED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_note_message`].\npub fn encode_private_note_message(\n note: Note,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n) -> [Field; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Note: NoteType + Packable,\n{\n let packed_note = note.pack();\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_content = [0; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX] = storage_slot;\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n for i in 0..packed_note.len() {\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_note[i];\n }\n\n // Notes use the note type id for metadata\n encode_message(PRIVATE_NOTE_MSG_TYPE_ID, Note::get_id() as u64, msg_content)\n}\n\n/// Decodes the plaintext from a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_note_message`].\n///\n/// Note that while [`encode_private_note_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_note_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(Field, AztecAddress, Field, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // decoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let owner = AztecAddress::from_field(msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX));\n let storage_slot = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX);\n let randomness = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let packed_note = array::subbvec(msg_content, PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((note_type_id, owner, storage_slot, randomness, packed_note))\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::note::{decode_private_note_message, encode_private_note_message, MAX_NOTE_PACKED_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global STORAGE_SLOT: Field = 9;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[derive(Packable)]\n struct MaxSizeNote {\n data: [Field; MAX_NOTE_PACKED_LEN],\n }\n\n impl NoteType for MaxSizeNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_note() {\n let mut data = [0; MAX_NOTE_PACKED_LEN];\n for i in 0..MAX_NOTE_PACKED_LEN {\n data[i] = i as Field;\n }\n let note = MaxSizeNote { data };\n\n let encoded = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n let (msg_type_id, msg_metadata, msg_content) = decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MaxSizeNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(data));\n }\n\n #[derive(Packable)]\n struct OversizedNote {\n data: [Field; MAX_NOTE_PACKED_LEN + 1],\n }\n\n impl NoteType for OversizedNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_note_fails() {\n let note = OversizedNote { data: [0; MAX_NOTE_PACKED_LEN + 1] };\n let _ = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_note_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0, 0, 0]);\n assert(decode_private_note_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/note.nr","function_locations":[{"start":1518,"name":"encode_private_note_message"},{"start":3312,"name":"decode_private_note_message"},{"start":5000,"name":"test::encode_decode"},{"start":5923,"name":"test::::get_id"},{"start":6019,"name":"test::encode_decode_max_size_note"},{"start":7035,"name":"test::::get_id"},{"start":7221,"name":"test::encode_oversized_note_fails"},{"start":7456,"name":"test::decode_empty_content_returns_none"},{"start":7650,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"141":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 1;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX: u32 = 2;\n\n/// Partial notes have a maximum packed length of their private fields bound by extra content in their private message\n/// (e.g. the storage slot, note completion log tag, etc.).\npub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 =\n MAX_MESSAGE_CONTENT_LEN - PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a partial note private message (i.e. one of type [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_partial_note_private_message`].\npub fn encode_partial_note_private_message(\n partial_note_private_content: PartialNotePrivateContent,\n owner: AztecAddress,\n randomness: Field,\n note_completion_log_tag: Field,\n ) -> [Field; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n PartialNotePrivateContent: NoteType + Packable,\n{\n let packed_private_content = partial_note_private_content.pack();\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail, then\n // the encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n let mut msg_content =\n [0; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX] = note_completion_log_tag;\n\n for i in 0..packed_private_content.len() {\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_private_content[i];\n }\n\n encode_message(\n PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n // Notes use the note type id for metadata\n PartialNotePrivateContent::get_id() as u64,\n msg_content,\n )\n}\n\n/// Decodes the plaintext from a partial note private message (i.e. one of type\n/// [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_partial_note_private_message`].\n///\n/// Note that while [`encode_partial_note_private_message`] returns a fixed-size array, this function takes a\n/// [`BoundedVec`] instead. This is because when decoding we're typically processing runtime-sized plaintexts, more\n/// specifically, those that originate from\n/// [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_partial_note_private_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(AztecAddress, Field, Field, Field, BoundedVec)> {\n if msg_content.len() < PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id: Field = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail,\n // then the destructuring of the partial note private message encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n // We currently have three fields that are not the partial note's packed representation, which are the owner,\n // the randomness, and the note completion log tag.\n let owner = AztecAddress::from_field(\n msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX),\n );\n let randomness = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let note_completion_log_tag = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX);\n\n let packed_private_note_content: BoundedVec = array::subbvec(\n msg_content,\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN,\n );\n\n Option::some(\n (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content),\n )\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::partial_note::{decode_partial_note_private_message, encode_partial_note_private_message},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global RANDOMNESS: Field = 10;\n global NOTE_COMPLETION_LOG_TAG: Field = 11;\n\n #[test]\n unconstrained fn encode_decode() {\n // Note that here we use MockNote as the private fields of a partial note\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_partial_note_private_message(note, OWNER, RANDOMNESS, NOTE_COMPLETION_LOG_TAG);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID);\n\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_note) =\n decode_partial_note_private_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(note_completion_log_tag, NOTE_COMPLETION_LOG_TAG);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_partial_note_private_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_succeeds_with_only_reserved_fields() {\n let content = BoundedVec::from_array([0, 0, 0]);\n let (_, _, _, _, packed_note) = decode_partial_note_private_message(0, content).unwrap();\n assert_eq(packed_note.len(), 0);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/partial_note.nr","function_locations":[{"start":1715,"name":"encode_partial_note_private_message"},{"start":3810,"name":"decode_partial_note_private_message"},{"start":6022,"name":"test::encode_decode"},{"start":6999,"name":"test::decode_empty_content_returns_none"},{"start":7197,"name":"test::decode_succeeds_with_only_reserved_fields"}]},"151":{"source":"pub(crate) mod event_validation_request;\npub mod offchain;\n\nmod message_context;\npub use message_context::MessageContext;\n\npub(crate) mod note_validation_request;\npub(crate) mod log_retrieval_request;\npub(crate) mod log_retrieval_response;\npub(crate) mod pending_tagged_log;\n\nuse crate::{\n capsules::CapsuleArray,\n ephemeral::EphemeralArray,\n event::EventSelector,\n messages::{\n discovery::partial_notes::DeliveredPendingPartialNote,\n encoding::MESSAGE_CIPHERTEXT_LEN,\n logs::{event::MAX_EVENT_SERIALIZED_LEN, note::MAX_NOTE_PACKED_LEN},\n processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse,\n note_validation_request::NoteValidationRequest,\n },\n },\n oracle::message_processing,\n};\nuse crate::protocol::{\n address::AztecAddress,\n constants::DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n hash::{compute_log_tag, sha256_to_field},\n traits::{Deserialize, Serialize},\n};\nuse event_validation_request::EventValidationRequest;\n\nglobal NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\n/// An offchain-delivered message with resolved context, ready for processing during sync.\n#[derive(Serialize, Deserialize)]\npub struct OffchainMessageWithContext {\n pub message_ciphertext: BoundedVec,\n pub message_context: MessageContext,\n}\n\n/// Enqueues a note for validation and storage by PXE.\n///\n/// Once validated, the note becomes retrievable via the `get_notes` oracle. The note will be scoped to\n/// `contract_address`, meaning other contracts will not be able to access it unless authorized.\n///\n/// In order for the note validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many note validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// The `packed_note` is what `getNotes` will later return. PXE indexes notes by `storage_slot`, so this value is\n/// typically used to filter notes that correspond to different state variables. `note_hash` and `nullifier` are the\n/// inner hashes, i.e. the raw hashes returned by `NoteHash::compute_note_hash` and `NoteHash::compute_nullifier`. PXE\n/// will verify that the siloed unique note hash was inserted into the tree at `tx_hash`, and will store the nullifier\n/// to later check for nullification.\n///\n/// `owner` is the address used in note hash and nullifier computation, often requiring knowledge of their nullifier\n/// secret key.\n///\n/// `scope` is the account to which the note message was delivered (i.e. the address the message was encrypted to).\n/// This determines which PXE account can see the note - other accounts will not be able to access it (e.g. other\n/// accounts will not be able to see one another's token balance notes, even in the same PXE) unless authorized. In\n/// most cases `recipient` equals `owner`, but they can differ in scenarios like delegated discovery.\npub unconstrained fn enqueue_note_for_validation(\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_nonce: Field,\n packed_note: BoundedVec,\n note_hash: Field,\n nullifier: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n NoteValidationRequest {\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_nonce,\n packed_note,\n note_hash,\n nullifier,\n tx_hash,\n },\n )\n}\n\n/// Enqueues an event for validation and storage by PXE.\n///\n/// This is the primary way for custom message handlers (registered via\n/// [`crate::macros::AztecConfig::custom_message_handler`]) to deliver reassembled events back to PXE after processing\n/// application-specific message formats.\n///\n/// In order for the event validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many event validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// Note that `validate_and_store_enqueued_notes_and_events` is called by Aztec.nr after processing messages, so custom\n/// message processors do not need to be concerned with this.\npub unconstrained fn enqueue_event_for_validation(\n contract_address: AztecAddress,\n event_type_id: EventSelector,\n randomness: Field,\n serialized_event: BoundedVec,\n event_commitment: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n EventValidationRequest {\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n },\n )\n}\n\n/// Validates and stores all enqueued notes and events.\n///\n/// Processes all requests enqueued via [`enqueue_note_for_validation`] and [`enqueue_event_for_validation`], inserting\n/// them into the note database and event store respectively, making them queryable via `get_notes` oracle and our TS\n/// API (PXE::getPrivateEvents).\npub unconstrained fn validate_and_store_enqueued_notes_and_events(scope: AztecAddress) {\n message_processing::validate_and_store_enqueued_notes_and_events(\n NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n MAX_NOTE_PACKED_LEN as Field,\n MAX_EVENT_SERIALIZED_LEN as Field,\n scope,\n );\n\n // Defensive clearing: purge the queues after processing to prevent double-processing if this function is called\n // more than once in the same call frame. It is currently defensive because we only call this once per sync run.\n let _ = EphemeralArray::::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n let _ = EphemeralArray::::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n}\n\n/// Efficiently queries the node for logs that result in the completion of all `DeliveredPendingPartialNote`s stored in\n/// a `CapsuleArray` by performing all node communication concurrently. Returns an `EphemeralArray` with Options\n/// for the responses that correspond to the pending partial notes at the same index.\n///\n/// For example, given an array with pending partial notes `[ p1, p2, p3 ]`, where `p1` and `p3` have corresponding\n/// completion logs but `p2` does not, the returned `EphemeralArray` will have contents `[some(p1_log), none(),\n/// some(p3_log)]`.\npub(crate) unconstrained fn get_pending_partial_notes_completion_logs(\n contract_address: AztecAddress,\n pending_partial_notes: CapsuleArray,\n) -> EphemeralArray> {\n let log_retrieval_requests = EphemeralArray::at(LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT);\n\n // We create a LogRetrievalRequest for each PendingPartialNote in the EphemeralArray. Because we need the indices in\n // the request array to match the indices in the partial note array, we can't use EphemeralArray::for_each, as that\n // function has arbitrary iteration order. Instead, we manually iterate the array from the beginning and push into\n // the requests array, which we expect to be empty.\n let mut i = 0;\n let pending_partial_notes_count = pending_partial_notes.len();\n while i < pending_partial_notes_count {\n let pending_partial_note = pending_partial_notes.get(i);\n // Partial note completion logs are emitted with a domain-separated tag. To find matching logs, we apply the\n // same domain separation to the stored raw tag.\n let log_tag = compute_log_tag(\n pending_partial_note.note_completion_log_tag,\n DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n );\n log_retrieval_requests.push(LogRetrievalRequest { contract_address, unsiloed_tag: log_tag });\n i += 1;\n }\n\n let responses = message_processing::get_logs_by_tag(log_retrieval_requests);\n\n // Defensive clearing: prevent stale requests if this function is called more than once in the same call frame.\n let _ = log_retrieval_requests.clear();\n\n responses\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/mod.nr","function_locations":[{"start":3763,"name":"enqueue_note_for_validation"},{"start":5177,"name":"enqueue_event_for_validation"},{"start":5884,"name":"validate_and_store_enqueued_notes_and_events"},{"start":7412,"name":"get_pending_partial_notes_completion_logs"}]},"153":{"source":"use crate::{\n capsules::CapsuleArray,\n context::UtilityContext,\n ephemeral::EphemeralArray,\n messages::{encoding::MESSAGE_CIPHERTEXT_LEN, processing::OffchainMessageWithContext},\n oracle::contract_sync::set_contract_sync_cache_invalid,\n protocol::{\n address::AztecAddress,\n constants::MAX_TX_LIFETIME,\n hash::sha256_to_field,\n traits::{Deserialize, Serialize},\n },\n};\n\n/// Base capsule slot for the persistent inbox of [`PendingOffchainMsg`] entries.\n///\n/// This is the slot where we accumulate messages received through [`receive`].\nglobal OFFCHAIN_INBOX_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_INBOX_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to pass tx hash resolution requests to PXE.\nglobal OFFCHAIN_CONTEXT_REQUESTS_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_CONTEXT_REQUESTS_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to collect messages ready for processing.\nglobal OFFCHAIN_READY_MESSAGES_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_READY_MESSAGES_SLOT\".as_bytes());\n\n/// Maximum number of offchain messages accepted by `offchain_receive` in a single call.\npub global MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL: u32 = 16;\n\n/// Tolerance added to the `MAX_TX_LIFETIME` cap for message expiration.\nglobal TX_EXPIRATION_TOLERANCE: u64 = 7200; // 2 hours\n\n/// Maximum time-to-live for a tx-bound offchain message.\n///\n/// After `anchor_block_timestamp + MAX_MSG_TTL`, the message is evicted from the inbox.\nglobal MAX_MSG_TTL: u64 = MAX_TX_LIFETIME + TX_EXPIRATION_TOLERANCE;\n\n/// A function that manages offchain-delivered messages for processing during sync.\n///\n/// Offchain messages are messages that are not broadcasted via onchain logs. They are instead delivered to the\n/// recipient by calling the `offchain_receive` utility function (injected by the `#[aztec]` macro). Message transport\n/// is the app's responsibility. Typical examples of transport methods are: messaging apps, email, QR codes, etc.\n///\n/// Once offchain messages are delivered to the recipient's private environment via `offchain_receive`, messages are\n/// locally stored in a persistent inbox.\n///\n/// This function determines when each message in said inbox is ready for processing, when it can be safely disposed\n/// of, etc.\n///\n/// The only current implementation of an `OffchainInboxSync` is [`sync_inbox`], which manages an inbox with expiration\n/// based eviction and automatic transaction context resolution.\npub(crate) type OffchainInboxSync = unconstrained fn[Env](\n/* contract_address */AztecAddress, /* scope */ AztecAddress) -> EphemeralArray;\n\n/// A message delivered via the `offchain_receive` utility function.\npub struct OffchainMessage {\n /// The encrypted message payload.\n pub ciphertext: BoundedVec,\n /// The intended recipient of the message.\n pub recipient: AztecAddress,\n /// The hash of the transaction that produced this message. `Option::none` indicates a tx-less message.\n pub tx_hash: Option,\n /// Anchor block timestamp at message emission.\n pub anchor_block_timestamp: u64,\n}\n\n/// An offchain message awaiting processing (or re-processing) in the inbox.\n///\n/// Messages remain in the inbox until they expire, even if they have already been processed. This is necessary to\n/// handle reorgs: a processed message may need to be re-processed if the transaction that provided its context is\n/// reverted. On each sync, resolved messages are promoted to [`OffchainMessageWithContext`] for processing.\n#[derive(Serialize, Deserialize)]\nstruct PendingOffchainMsg {\n /// The encrypted message payload.\n ciphertext: BoundedVec,\n /// The intended recipient of the message.\n recipient: AztecAddress,\n /// The hash of the transaction that produced this message. A value of 0 indicates a tx-less message.\n tx_hash: Field,\n /// Anchor block timestamp at message emission. Used to compute the effective expiration: messages are evicted\n /// after `anchor_block_timestamp + MAX_MSG_TTL`.\n anchor_block_timestamp: u64,\n}\n\n/// Delivers offchain messages to the given contract's offchain inbox for subsequent processing.\n///\n/// Offchain messages are transaction effects that are not broadcasted via onchain logs. Instead, the sender shares the\n/// message to the recipient through an external channel (e.g. a URL accessible by the recipient). The recipient then\n/// calls this function to hand the messages to the contract so they can be processed through the same mechanisms as\n/// onchain messages.\n///\n/// Each message is routed to the inbox scoped to its `recipient` field, so messages for different accounts are\n/// automatically isolated.\n///\n/// Messages are processed when their originating transaction is found onchain (providing the context needed to\n/// validate resulting notes and events).\n///\n/// Messages are kept in the inbox until they expire. The effective expiration is\n/// `anchor_block_timestamp + MAX_MSG_TTL`.\n///\n/// Processing order is not guaranteed.\npub unconstrained fn receive(\n contract_address: AztecAddress,\n messages: BoundedVec,\n) {\n // May contain duplicates if multiple messages target the same recipient. This is harmless since\n // cache invalidation on the TS side is idempotent (deleting an already-deleted key is a no-op).\n let mut scopes: BoundedVec = BoundedVec::new();\n let mut i = 0;\n let messages_len = messages.len();\n while i < messages_len {\n let msg = messages.get(i);\n let tx_hash = if msg.tx_hash.is_some() {\n msg.tx_hash.unwrap()\n } else {\n 0\n };\n let inbox: CapsuleArray =\n CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, msg.recipient);\n inbox.push(\n PendingOffchainMsg {\n ciphertext: msg.ciphertext,\n recipient: msg.recipient,\n tx_hash,\n anchor_block_timestamp: msg.anchor_block_timestamp,\n },\n );\n scopes.push(msg.recipient);\n i += 1;\n }\n\n set_contract_sync_cache_invalid(contract_address, scopes);\n}\n\n/// Returns offchain-delivered messages to process during sync.\n///\n/// Messages remain in the inbox and are reprocessed on each sync until their originating transaction is no longer at\n/// risk of being dropped by a reorg.\npub unconstrained fn sync_inbox(\n contract_address: AztecAddress,\n scope: AztecAddress,\n) -> EphemeralArray {\n let inbox: CapsuleArray = CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, scope);\n let context_resolution_requests: EphemeralArray = EphemeralArray::at(OFFCHAIN_CONTEXT_REQUESTS_SLOT).clear();\n let ready_to_process: EphemeralArray =\n EphemeralArray::at(OFFCHAIN_READY_MESSAGES_SLOT).clear();\n\n // Build a request list aligned with the inbox indices.\n let mut i = 0;\n let inbox_len = inbox.len();\n while i < inbox_len {\n let msg = inbox.get(i);\n context_resolution_requests.push(msg.tx_hash);\n i += 1;\n }\n\n // Ask PXE to resolve contexts for all requested tx hashes. The oracle returns responses in a new\n // ephemeral array.\n let resolved_contexts =\n crate::oracle::message_processing::get_message_contexts_by_tx_hash(context_resolution_requests);\n\n assert_eq(resolved_contexts.len(), inbox_len);\n\n let now = UtilityContext::new().timestamp();\n\n let mut j = inbox_len;\n while j > 0 {\n // This loop decides what to do with each message in the offchain message inbox. We need to handle 3\n // different scenarios for each message.\n //\n // 1. The TX that emitted this message is still not known to PXE: in this case we can't yet process this\n // message, as any notes or events discovered will fail to be validated. So we leave the message in the inbox,\n // awaiting for future syncs to detect that the TX became available.\n //\n // 2. The message is not associated to a TX to begin with. The current version of offchain message processing\n // does not support this case, but in the future it will. Right now, a message without an associated TX will\n // sit in the inbox until it expires.\n //\n // 3. The TX that emitted this message has been found by PXE. That gives us all the information needed to\n // process the message. We add the message to the `ready_to_process` EphemeralArray so that the `sync_state`\n // loop\n // processes it.\n //\n // In all cases, if the message has expired (i.e. `now > anchor_block_timestamp + MAX_MSG_TTL`), we remove it\n // from the inbox.\n //\n // Note: the loop runs backwards because it might call `inbox.remove(j)` to purge expired messages and we also\n // need to align it with `resolved_contexts.get(j)`. Going from last to first simplifies the algorithm as\n // not yet visited element indexes remain stable.\n j -= 1;\n let maybe_ctx = resolved_contexts.get(j);\n let msg = inbox.get(j);\n\n // Compute the message's effective expiration timestamp to determine if we can purge it from the inbox.\n let effective_expiration = msg.anchor_block_timestamp + MAX_MSG_TTL;\n\n // Message expired. We remove it from the inbox.\n if now > effective_expiration {\n inbox.remove(j);\n }\n\n // Scenario 1: associated TX not yet available. We keep the message in the inbox, as it might become\n // processable as new blocks get mined.\n // Scenario 2: no TX associated to message. The message will sit in the inbox until it expires.\n if maybe_ctx.is_none() {\n continue;\n }\n\n // Scenario 3: Message is ready to process, add to result array. Note we still keep it in the inbox unless we\n // consider it has expired: this is because we need to account for reorgs. If reorg occurs after we processed\n // a message, the effects of processing the message get rewind. However, the associated TX can be included in\n // a subsequent block. Should that happen, the message must be re-processed to ensure consistency.\n let message_context = maybe_ctx.unwrap();\n ready_to_process.push(OffchainMessageWithContext { message_ciphertext: msg.ciphertext, message_context });\n }\n\n ready_to_process\n}\n\nmod test {\n use crate::{\n capsules::CapsuleArray, oracle::random::random, protocol::address::AztecAddress,\n test::helpers::test_environment::TestEnvironment,\n };\n use super::{\n MAX_MSG_TTL, MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL, OFFCHAIN_INBOX_SLOT, OffchainMessage, PendingOffchainMsg,\n receive, sync_inbox,\n };\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n /// Creates an `OffchainMessage` with dummy ciphertext and the given scope as recipient.\n fn make_msg(recipient: AztecAddress, tx_hash: Option, anchor_block_timestamp: u64) -> OffchainMessage {\n OffchainMessage { ciphertext: BoundedVec::new(), recipient, tx_hash, anchor_block_timestamp }\n }\n\n /// Advances the TXE block timestamp by `offset` seconds and returns the resulting timestamp.\n unconstrained fn advance_by(env: TestEnvironment, offset: u64) -> u64 {\n env.advance_next_block_timestamp_by(offset);\n env.mine_block();\n env.last_block_timestamp()\n }\n\n #[test]\n unconstrained fn empty_inbox_returns_empty_result() {\n let (env, scope) = setup();\n env.utility_context(|context| {\n let result = sync_inbox(context.this_address(), scope);\n let inbox: CapsuleArray =\n CapsuleArray::at(context.this_address(), OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0);\n assert_eq(inbox.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_not_expired_before_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance, but not past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn tx_less_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::none(), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn unresolved_tx_stays_in_inbox() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // not resolved, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn multiple_messages_mixed_expiration() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n let survivor_tx_hash = random();\n\n env.utility_context(|context| {\n let address = context.this_address();\n let mut msgs: BoundedVec = BoundedVec::new();\n // Message 0: tx-bound, anchor_ts in the past so it expires at\n // anchor_ts + MAX_MSG_TTL. We set anchor to 0 so it expires quickly.\n msgs.push(make_msg(scope, Option::some(random()), 0));\n // Message 1: tx-bound, anchor_ts is recent so it survives.\n msgs.push(make_msg(scope, Option::some(survivor_tx_hash), anchor_ts));\n // Message 2: tx-less, anchor_ts=0 so it also expires.\n msgs.push(make_msg(scope, Option::none(), 0));\n receive(address, msgs);\n });\n\n // Advance past MAX_MSG_TTL for anchor_ts=0, but not for anchor_ts=anchor_ts.\n let _now = advance_by(env, MAX_MSG_TTL);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // all contexts are None\n // Message 0 expired (anchor=0), message 1 survived (anchor=anchor_ts),\n // Message 2 expired (anchor=0).\n assert_eq(inbox.len(), 1);\n assert_eq(inbox.get(0).tx_hash, survivor_tx_hash);\n });\n }\n\n // -- Resolved context (ready to process) ------------------------------\n\n #[test]\n unconstrained fn resolved_msg_is_ready_to_process() {\n let (env, scope) = setup();\n // TestEnvironment::new() deploys protocol contracts, creating blocks with tx effects.\n // In TXE, tx hashes equal Fr(blockNumber), so Fr(1) is the tx effect from block 1.\n // We use this as a \"known resolvable\" tx hash.\n let known_tx_hash: Field = 1;\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(known_tx_hash), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n // The message should be ready to process since its tx context was resolved.\n assert_eq(result.len(), 1);\n\n let ctx = result.get(0).message_context;\n assert_eq(ctx.tx_hash, known_tx_hash);\n assert(ctx.first_nullifier_in_tx != 0, \"resolved context must have a first nullifier\");\n\n // Message stays in inbox (not expired) for potential reorg reprocessing.\n assert_eq(inbox.len(), 1);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/offchain.nr","function_locations":[{"start":5298,"name":"receive"},{"start":6741,"name":"sync_inbox"},{"start":11111,"name":"test::setup"},{"start":11441,"name":"test::make_msg"},{"start":11724,"name":"test::advance_by"},{"start":11915,"name":"test::empty_inbox_returns_empty_result"},{"start":12378,"name":"test::tx_bound_msg_expires_after_max_msg_ttl"},{"start":13343,"name":"test::tx_bound_msg_not_expired_before_max_msg_ttl"},{"start":14301,"name":"test::tx_less_msg_expires_after_max_msg_ttl"},{"start":15243,"name":"test::unresolved_tx_stays_in_inbox"},{"start":16137,"name":"test::multiple_messages_mixed_expiration"},{"start":17876,"name":"test::resolved_msg_is_ready_to_process"}]},"171":{"source":"#[oracle(aztec_utl_decryptAes128)]\nunconstrained fn aes128_decrypt_oracle(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {}\n\n/// Attempts to decrypt a ciphertext using AES128.\n///\n/// Returns `Option::some(plaintext)` on success, or `Option::none()` if decryption fails (e.g. due to malformed\n/// ciphertext or invalid PKCS#7 padding). Note that decryption with the wrong key will almost always return `None`\n/// because the decrypted garbage data will have invalid PKCS#7 padding.\n///\n/// Note that we accept ciphertext as a BoundedVec, not as an array. This is because this function is typically used\n/// when processing logs and at that point we don't have comptime information about the length of the ciphertext as\n/// the log is not specific to any individual note.\n// TODO(F-498): review naming consistency\npub unconstrained fn try_aes128_decrypt(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {\n aes128_decrypt_oracle(ciphertext, iv, sym_key)\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::compute_app_siloed_shared_secret,\n messages::encryption::aes128::derive_aes_symmetric_key_and_iv_from_shared_secret,\n utils::{array::subarray::subarray, point::point_from_x_coord},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::try_aes128_decrypt;\n use std::aes128::aes128_encrypt;\n\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress { inner: 42 };\n global TEST_PLAINTEXT_LENGTH: u32 = 10;\n global TEST_CIPHERTEXT_LENGTH: u32 = 16;\n global TEST_PADDING_LENGTH: u32 = TEST_CIPHERTEXT_LENGTH - TEST_PLAINTEXT_LENGTH;\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n\n let received_plaintext = try_aes128_decrypt(ciphertext_bvec, iv, sym_key).unwrap();\n assert_eq(received_plaintext.len(), TEST_PLAINTEXT_LENGTH);\n assert_eq(received_plaintext.max_len(), TEST_CIPHERTEXT_LENGTH);\n assert_eq(subarray::<_, _, TEST_PLAINTEXT_LENGTH>(received_plaintext.storage(), 0), plaintext);\n assert_eq(\n subarray::<_, _, TEST_PADDING_LENGTH>(received_plaintext.storage(), TEST_PLAINTEXT_LENGTH),\n [0 as u8; TEST_PADDING_LENGTH],\n );\n })\n }\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt_with_bad_sym_key_is_caught() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n // Decrypting with the wrong key results in garbage data with invalid PKCS#7 padding,\n // so the oracle returns None.\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let mut bad_sym_key = sym_key;\n bad_sym_key[0] = 0;\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n // Decryption with wrong key returns None because the garbage output has invalid PKCS#7 padding.\n let result = try_aes128_decrypt(ciphertext_bvec, iv, bad_sym_key);\n assert(result.is_none(), \"decryption with bad key should return None\");\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/aes128_decrypt.nr","function_locations":[{"start":194,"name":"aes128_decrypt_oracle"},{"start":1046,"name":"try_aes128_decrypt"},{"start":1860,"name":"test::aes_encrypt_then_decrypt"},{"start":3150,"name":"test::aes_encrypt_then_decrypt_with_bad_sym_key_is_caught"}]},"176":{"source":"use crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Stores arbitrary information in a per-contract non-volatile database, which can later be retrieved with `load`. If\n/// data was already stored at this slot, it is overwritten.\n// TODO(F-498): review naming consistency\npub unconstrained fn store(contract_address: AztecAddress, slot: Field, value: T, scope: AztecAddress)\nwhere\n T: Serialize,\n{\n let serialized = value.serialize();\n set_capsule_oracle(contract_address, slot, serialized, scope);\n}\n\n/// Returns data previously stored via `storeCapsule` in the per-contract non-volatile database. Returns\n/// Option::none() if nothing was stored at the given slot.\n// TODO(F-498): review naming consistency\npub unconstrained fn load(contract_address: AztecAddress, slot: Field, scope: AztecAddress) -> Option\nwhere\n T: Deserialize,\n{\n let serialized_option = get_capsule_oracle(contract_address, slot, ::N, scope);\n serialized_option.map(|arr| Deserialize::deserialize(arr))\n}\n\n/// Deletes data in the per-contract non-volatile database. Does nothing if no data was present.\npub unconstrained fn delete(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {\n delete_oracle(contract_address, slot, scope);\n}\n\n/// Copies a number of contiguous entries in the per-contract non-volatile database. This allows for efficient data\n/// structures by avoiding repeated calls to `loadCapsule` and `storeCapsule`. Supports overlapping source and\n/// destination regions (which will result in the overlapped source values being overwritten). All copied slots must\n/// exist in the database (i.e. have been stored and not deleted)\npub unconstrained fn copy(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {\n copy_oracle(contract_address, src_slot, dst_slot, num_entries, scope);\n}\n\n#[oracle(aztec_utl_setCapsule)]\nunconstrained fn set_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n values: [Field; N],\n scope: AztecAddress,\n) {}\n\n/// We need to pass in `array_len` (the value of N) as a parameter to tell the oracle how many fields the response must\n/// have.\n///\n/// Note that the oracle returns an Option<[Field; N]> because we cannot return an Option directly. That would\n/// require for the oracle resolver to know the shape of T (e.g. if T were a struct of 3 u32 values then the expected\n/// response shape would be 3 single items, whereas it were a struct containing `u32, [Field;10], u32` then the\n/// expected shape would be single, array, single.). Instead, we return the serialization and deserialize in Noir.\n#[oracle(aztec_utl_getCapsule)]\nunconstrained fn get_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n array_len: u32,\n scope: AztecAddress,\n) -> Option<[Field; N]> {}\n\n#[oracle(aztec_utl_deleteCapsule)]\nunconstrained fn delete_oracle(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {}\n\n#[oracle(aztec_utl_copyCapsule)]\nunconstrained fn copy_oracle(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {}\n\nmod test {\n // These tests are sort of redundant since we already test the oracle implementation directly in TypeScript, but\n // they are cheap regardless and help ensure both that the TXE implementation works accordingly and that the Noir\n // oracles are hooked up correctly.\n\n use crate::{\n oracle::capsules::{copy, delete, load, store},\n test::{helpers::test_environment::TestEnvironment, mocks::MockStruct},\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, ToField}};\n\n global SLOT: Field = 1;\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n #[test]\n unconstrained fn stores_and_loads() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), value);\n });\n }\n\n #[test]\n unconstrained fn store_overwrites() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n let new_value = MockStruct::new(7, 8);\n store(contract_address, SLOT, new_value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), new_value);\n });\n }\n\n #[test]\n unconstrained fn loads_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_stored_value() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n delete(contract_address, SLOT, scope);\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n delete(contract_address, SLOT, scope);\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn copies_non_overlapping_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 5;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 10;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_src_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 1;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 2;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[1] and src[2] should have been overwritten since they are also dst[0] and dst[1]\n assert_eq(load(contract_address, src, scope).unwrap(), values[0]); // src[0] (unchanged)\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[0]); // dst[0]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[1]); // dst[1]\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_dst_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 2;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 1;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[0] and src[1] should have been overwritten since they are also dst[1] and dst[2]\n assert_eq(load(contract_address, src, scope).unwrap(), values[1]); // dst[1]\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[2]); // dst[2]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[2]); // src[2] (unchanged)\n });\n }\n\n #[test(should_fail_with = \"copy empty slot\")]\n unconstrained fn cannot_copy_empty_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n copy(contract_address, SLOT, SLOT, 1, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_store_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let value = MockStruct::new(5, 6);\n store(other_contract_address, SLOT, value, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_load_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let _: Option = load(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_delete_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n delete(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_copy_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n copy(other_contract_address, SLOT, SLOT, 0, scope);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/capsules.nr","function_locations":[{"start":433,"name":"store"},{"start":886,"name":"load"},{"start":1247,"name":"delete"},{"start":1866,"name":"copy"},{"start":2131,"name":"set_capsule_oracle"},{"start":2931,"name":"get_capsule_oracle"},{"start":3067,"name":"delete_oracle"},{"start":3261,"name":"copy_oracle"},{"start":3884,"name":"test::setup"},{"start":4060,"name":"test::stores_and_loads"},{"start":4450,"name":"test::store_overwrites"},{"start":4957,"name":"test::loads_empty_slot"},{"start":5311,"name":"test::deletes_stored_value"},{"start":5819,"name":"test::deletes_empty_slot"},{"start":6233,"name":"test::copies_non_overlapping_values"},{"start":7106,"name":"test::copies_overlapping_values_with_src_ahead"},{"start":8366,"name":"test::copies_overlapping_values_with_dst_ahead"},{"start":9648,"name":"test::cannot_copy_empty_values"},{"start":9970,"name":"test::cannot_store_other_contract"},{"start":10443,"name":"test::cannot_load_other_contract"},{"start":10891,"name":"test::cannot_delete_other_contract"},{"start":11311,"name":"test::cannot_copy_other_contract"}]},"177":{"source":"use crate::protocol::address::AztecAddress;\n\n#[oracle(aztec_utl_setContractSyncCacheInvalid)]\nunconstrained fn set_contract_sync_cache_invalid_oracle(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {}\n\n/// Forces the PXE to re-sync the given contract for a set of scopes on the next query.\n///\n/// Call this after writing data (e.g. offchain messages) that the contract's `sync_state` function needs to discover.\n/// Without invalidation, the sync cache would skip re-running `sync_state` until the next block.\npub unconstrained fn set_contract_sync_cache_invalid(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {\n set_contract_sync_cache_invalid_oracle(contract_address, scopes);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/contract_sync.nr","function_locations":[{"start":242,"name":"set_contract_sync_cache_invalid_oracle"},{"start":700,"name":"set_contract_sync_cache_invalid"}]},"179":{"source":"use crate::context::UtilityContext;\n\n#[oracle(aztec_utl_getUtilityContext)]\nunconstrained fn get_utility_context_oracle() -> UtilityContext {}\n\n/// Returns a utility context built from the global variables of anchor block and the contract address of the function\n/// being executed.\npub unconstrained fn get_utility_context() -> UtilityContext {\n get_utility_context_oracle()\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/execution.nr","function_locations":[{"start":140,"name":"get_utility_context_oracle"},{"start":344,"name":"get_utility_context"}]},"189":{"source":"use crate::ephemeral::EphemeralArray;\nuse crate::messages::processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse, MessageContext,\n pending_tagged_log::PendingTaggedLog,\n};\nuse crate::protocol::address::AztecAddress;\n\n/// Finds new private logs that may have been sent to all registered accounts in PXE in the current contract and\n/// returns them in an ephemeral array with an oracle-allocated base slot.\npub(crate) unconstrained fn get_pending_tagged_logs(scope: AztecAddress) -> EphemeralArray {\n let result_slot = get_pending_tagged_logs_oracle(scope);\n EphemeralArray::at(result_slot)\n}\n\n#[oracle(aztec_utl_getPendingTaggedLogs_v2)]\nunconstrained fn get_pending_tagged_logs_oracle(scope: AztecAddress) -> Field {}\n\n/// Validates note/event requests stored in ephemeral arrays.\npub(crate) unconstrained fn validate_and_store_enqueued_notes_and_events(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {\n validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot,\n event_validation_requests_array_slot,\n max_note_packed_len,\n max_event_serialized_len,\n scope,\n );\n}\n\n#[oracle(aztec_utl_validateAndStoreEnqueuedNotesAndEvents_v2)]\nunconstrained fn validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {}\n\n/// Fetches logs by tag from an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_logs_by_tag(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_logs_by_tag_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getLogsByTag_v2)]\nunconstrained fn get_logs_by_tag_v2_oracle(request_array_slot: Field) -> Field {}\n\n/// Resolves message contexts for tx hashes in an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_message_contexts_by_tx_hash(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_message_contexts_by_tx_hash_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getMessageContextsByTxHash_v2)]\nunconstrained fn get_message_contexts_by_tx_hash_v2_oracle(request_array_slot: Field) -> Field {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/message_processing.nr","function_locations":[{"start":570,"name":"get_pending_tagged_logs"},{"start":795,"name":"get_pending_tagged_logs_oracle"},{"start":1128,"name":"validate_and_store_enqueued_notes_and_events"},{"start":1692,"name":"validate_and_store_enqueued_notes_and_events_oracle"},{"start":1938,"name":"get_logs_by_tag"},{"start":2163,"name":"get_logs_by_tag_v2_oracle"},{"start":2423,"name":"get_message_contexts_by_tx_hash"},{"start":2694,"name":"get_message_contexts_by_tx_hash_v2_oracle"}]},"196":{"source":"use crate::protocol::address::aztec_address::AztecAddress;\nuse crate::protocol::point::Point;\n\n#[oracle(aztec_utl_getSharedSecret)]\nunconstrained fn get_shared_secret_oracle(\n address: AztecAddress,\n ephPk: Point,\n contract_address: AztecAddress,\n) -> Field {}\n\n/// Returns an app-siloed shared secret between `address` and someone who knows the secret key behind an ephemeral\n/// public key `ephPk`.\n///\n/// The returned value is a Field `s_app`, computed as:\n///\n/// ```text\n/// S = address_secret * ephPk (raw ECDH point)\n/// s_app = h(DOM_SEP, S.x, S.y, contract) (app-siloed scalar)\n/// ```\n///\n/// where `contract` is the address of the calling contract. The oracle host validates this matches its execution\n/// context.\n///\n/// Without app-siloing, a malicious contract could call this oracle with public information (address, ephPk) and\n/// obtain the same raw secret as the legitimate contract, enabling cross-contract decryption. By including the\n/// contract address in the hash, each contract receives a different `s_app`, preventing this attack.\n///\n/// Callers derive indexed subkeys from `s_app` via\n/// [`derive_shared_secret_subkey`](crate::keys::ecdh_shared_secret::derive_shared_secret_subkey).\npub unconstrained fn get_shared_secret(address: AztecAddress, ephPk: Point, contract_address: AztecAddress) -> Field {\n get_shared_secret_oracle(address, ephPk, contract_address)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr","function_locations":[{"start":267,"name":"get_shared_secret_oracle"},{"start":1354,"name":"get_shared_secret"}]},"245":{"source":"/// Appends the elements of the second `BoundedVec` to the end of the first one. The resulting `BoundedVec` can have\n/// any arbitrary maximum length, but it must be large enough to fit all of the elements of both the first and second\n/// vectors.\npub fn append(\n a: BoundedVec,\n b: BoundedVec,\n) -> BoundedVec {\n let mut dst = BoundedVec::new();\n\n dst.extend_from_bounded_vec(a);\n dst.extend_from_bounded_vec(b);\n\n dst\n}\n\nmod test {\n use super::append;\n\n #[test]\n unconstrained fn append_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::new();\n let b: BoundedVec<_, 14> = BoundedVec::new();\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 0);\n assert_eq(result.storage(), std::mem::zeroed());\n }\n\n #[test]\n unconstrained fn append_non_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 6);\n assert_eq(result.storage(), [1, 2, 3, 4, 5, 6, std::mem::zeroed(), std::mem::zeroed()]);\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn append_non_empty_vecs_insufficient_max_len() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let _: BoundedVec = append(a, b);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/append.nr","function_locations":[{"start":396,"name":"append"},{"start":608,"name":"test::append_empty_vecs"},{"start":933,"name":"test::append_non_empty_vecs"},{"start":1387,"name":"test::append_non_empty_vecs_insufficient_max_len"}]},"248":{"source":"/// Returns `DstLen` elements from a source array, starting at `offset`. `DstLen` must not be larger than the number of\n/// elements past `offset`.\n///\n/// Examples:\n/// ```\n/// let foo: [Field; 2] = subarray([1, 2, 3, 4, 5], 2);\n/// assert_eq(foo, [3, 4]);\n///\n/// let bar: [Field; 5] = subarray([1, 2, 3, 4, 5], 2); // fails - we can't return 5 elements since only 3 remain\n/// ```\npub fn subarray(src: [T; SrcLen], offset: u32) -> [T; DstLen] {\n assert(offset + DstLen <= SrcLen, \"DstLen too large for offset\");\n\n let mut dst: [T; DstLen] = std::mem::zeroed();\n for i in 0..DstLen {\n dst[i] = src[i + offset];\n }\n\n dst\n}\n\nmod test {\n use super::subarray;\n\n #[test]\n unconstrained fn subarray_into_empty() {\n // In all of these cases we're setting DstLen to be 0, so we always get back an empty array.\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 2), []);\n }\n\n #[test]\n unconstrained fn subarray_complete() {\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), [1, 2, 3, 4, 5]);\n }\n\n #[test]\n unconstrained fn subarray_different_end_sizes() {\n // We implicitly select how many values to read in the size of the return array\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4, 5]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2]);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subarray_offset_too_large() {\n // With an offset of 1 we can only request up to 4 elements\n let _: [_; 5] = subarray([1, 2, 3, 4, 5], 1);\n }\n\n #[test(should_fail)]\n unconstrained fn subarray_bad_return_value() {\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [3, 3, 4, 5]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr","function_locations":[{"start":483,"name":"subarray"},{"start":776,"name":"test::subarray_into_empty"},{"start":1100,"name":"test::subarray_complete"},{"start":1294,"name":"test::subarray_different_end_sizes"},{"start":1736,"name":"test::subarray_offset_too_large"},{"start":1941,"name":"test::subarray_bad_return_value"}]},"249":{"source":"use crate::utils::array;\n\n/// Returns `DstMaxLen` elements from a source BoundedVec, starting at `offset`. `offset` must not be larger than the\n/// original length, and `DstLen` must not be larger than the total number of elements past `offset` (including the\n/// zeroed elements past `len()`).\n///\n/// Only elements at the beginning of the vector can be removed: it is not possible to also remove elements at the end\n/// of the vector by passing a value for `DstLen` that is smaller than `len() - offset`.\n///\n/// Examples:\n/// ```\n/// let foo = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n/// assert_eq(subbvec(foo, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n///\n/// let bar: BoundedVec<_, 1> = subbvec(foo, 2); // fails - we can't return just 1 element since 3 remain\n/// let baz: BoundedVec<_, 10> = subbvec(foo, 3); // fails - we can't return 10 elements since only 7 remain\n/// ```\npub fn subbvec(\n bvec: BoundedVec,\n offset: u32,\n) -> BoundedVec {\n // from_parts_unchecked does not verify that the elements past len are zeroed, but that is not an issue in our case\n // because we're constructing the new storage array as a subarray of the original one (which should have zeroed\n // storage past len), guaranteeing correctness. This is because `subarray` does not allow extending arrays past\n // their original length.\n BoundedVec::from_parts_unchecked(array::subarray(bvec.storage(), offset), bvec.len() - offset)\n}\n\nmod test {\n use super::subbvec;\n\n #[test]\n unconstrained fn subbvec_empty() {\n let bvec = BoundedVec::::from_array([]);\n assert_eq(subbvec(bvec, 0), bvec);\n }\n\n #[test]\n unconstrained fn subbvec_complete() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), bvec);\n\n let smaller_capacity = BoundedVec::<_, 5>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), smaller_capacity);\n }\n\n #[test]\n unconstrained fn subbvec_partial() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 3>::from_array([3, 4, 5]));\n }\n\n #[test]\n unconstrained fn subbvec_into_empty() {\n let bvec: BoundedVec<_, 10> = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 5), BoundedVec::<_, 5>::from_array([]));\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_offset_past_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n let _: BoundedVec<_, 1> = subbvec(bvec, 6);\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_insufficient_dst_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // We're not providing enough space to hold all of the items inside the original BoundedVec. subbvec can cause\n // for the capacity to reduce, but not the length (other than by len - offset).\n let _: BoundedVec<_, 1> = subbvec(bvec, 2);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_causes_enlarge() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // subbvec does not support capacity increases\n let _: BoundedVec<_, 11> = subbvec(bvec, 0);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_too_large_for_offset() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // This effectively requests a capacity increase, since there'd be just one element plus the 5 empty slots,\n // which is less than 7.\n let _: BoundedVec<_, 7> = subbvec(bvec, 4);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr","function_locations":[{"start":1041,"name":"subbvec"},{"start":1612,"name":"test::subbvec_empty"},{"start":1775,"name":"test::subbvec_complete"},{"start":2083,"name":"test::subbvec_partial"},{"start":2376,"name":"test::subbvec_into_empty"},{"start":2609,"name":"test::subbvec_offset_past_len"},{"start":2816,"name":"test::subbvec_insufficient_dst_len"},{"start":3270,"name":"test::subbvec_dst_len_causes_enlarge"},{"start":3579,"name":"test::subbvec_dst_len_too_large_for_offset"}]},"252":{"source":"use std::static_assert;\n\n/// Encodes an array of bytes as fields.\n///\n/// Use\n/// [`decode_bytes_from_fields`](crate::utils::conversion::bytes_as_fields::decode_bytes_from_fields) to recover\n/// the original bytes.\n///\n/// The `bytes` array length must be a multiple of 31. If padding is added, it will need to be manually removed\n/// after decoding.\n///\n/// ## Encoding\n///\n/// Each 31-byte chunk is interpreted as a big-endian integer and stored in a `Field`. For input `[1, 10, 3, ..., 0]`\n/// (31 bytes), the resulting `Field` is `1 * 256^30 + 10 * 256^29 + 3 * 256^28 + ... + 0`.\npub fn encode_bytes_as_fields(bytes: [u8; N]) -> [Field; N / 31] {\n static_assert(N % 31 == 0, \"N must be a multiple of 31\");\n\n let mut fields = [0; N / 31];\n for i in 0..N / 31 {\n let mut field = 0;\n for j in 0..31 {\n field = field * 256 + bytes[i * 31 + j] as Field;\n }\n fields[i] = field;\n }\n\n fields\n}\n\n/// Decodes fields back into bytes.\n///\n/// Inverse of\n/// [`encode_bytes_as_fields`](crate::utils::conversion::bytes_as_fields::encode_bytes_as_fields).\n/// Each input `Field` must fit in 248 bits; `Field::to_be_bytes::<31>()` fails the proof otherwise.\npub fn decode_bytes_from_fields(fields: BoundedVec) -> BoundedVec {\n let mut bytes = BoundedVec::new();\n for i in 0..fields.len() {\n let chunk: [u8; 31] = fields.get(i).to_be_bytes();\n for j in 0..31 {\n bytes.push(chunk[j]);\n }\n }\n bytes\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_bytes_from_fields, encode_bytes_as_fields};\n\n #[test]\n unconstrained fn round_trips_bytes(input: [u8; 93]) {\n let fields = encode_bytes_as_fields(input);\n\n // In production the fields fly through the system and arrive as a BoundedVec on the other end.\n let fields_bvec = BoundedVec::<_, 6>::from_array(fields);\n let bytes_back = decode_bytes_from_fields(fields_bvec);\n\n assert_eq(bytes_back.len(), input.len());\n assert_eq(subarray(bytes_back.storage(), 0), input);\n }\n\n #[test(should_fail_with = \"N must be a multiple of 31\")]\n unconstrained fn encode_rejects_length_not_multiple_of_31() {\n let _fields = encode_bytes_as_fields([0; 32]);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 31 limbs\")]\n unconstrained fn decode_rejects_oversized_field() {\n // `Field::to_be_bytes::<31>()` fails the proof when a field has any bit above position 247 set.\n let oversized: Field = (1 as Field) * 2.pow_32(249);\n let input = BoundedVec::<_, 1>::from_array([oversized]);\n let _bytes = decode_bytes_from_fields(input);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/bytes_as_fields.nr","function_locations":[{"start":662,"name":"encode_bytes_as_fields"},{"start":1313,"name":"decode_bytes_from_fields"},{"start":1719,"name":"tests::round_trips_bytes"},{"start":2252,"name":"tests::encode_rejects_length_not_multiple_of_31"},{"start":2454,"name":"tests::decode_rejects_oversized_field"}]},"253":{"source":"/// Encodes an array of fields as bytes.\n///\n/// Losslessly preserves any field value; use\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes) to\n/// recover the original fields.\n///\n/// ## Encoding\n///\n/// Each field is written as 32 big-endian bytes and the chunks are concatenated. The field array `[5, 42]` becomes:\n///\n/// ```text\n/// [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, // First field (32 bytes)\n/// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42] // Second field (32 bytes)\n/// ```\n///\n/// ## Privacy\n///\n/// The BN254 modulus is `< 2^254`, so every 32-byte chunk has its top bit at zero and the next bit biased. The output\n/// is therefore distinguishable from uniform random bytes; take this into account when feeding it into anything that\n/// assumes uniform randomness (e.g. ciphertexts meant to look random).\npub fn encode_fields_as_bytes(fields: [Field; N]) -> [u8; 32 * N] {\n let mut bytes = [0; 32 * N];\n for i in 0..N {\n let chunk: [u8; 32] = fields[i].to_be_bytes();\n for j in 0..32 {\n bytes[i * 32 + j] = chunk[j];\n }\n }\n bytes\n}\n\n/// Decodes bytes back into fields.\n///\n/// Panics if the input length is not a multiple of 32 or if any chunk exceeds the BN254 field modulus. See\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes)\n/// for a non-panicking variant.\npub fn decode_fields_from_bytes(bytes: BoundedVec) -> BoundedVec {\n assert(bytes.len() % 32 == 0, \"Input length must be a multiple of 32\");\n try_decode_fields_from_bytes(bytes).expect(f\"Value does not fit in field\")\n}\n\n/// Decodes bytes back into fields, returning None on failure.\n///\n/// Inverse of\n/// [`encode_fields_as_bytes`](crate::utils::conversion::fields_as_bytes::encode_fields_as_bytes).\n/// Returns `Option::none()` if the input length is not a multiple of 32, or if any 32-byte chunk is `>=` the BN254\n/// field modulus.\npub fn try_decode_fields_from_bytes(bytes: BoundedVec) -> Option> {\n if bytes.len() % 32 == 0 {\n let num_chunks = bytes.len() / 32;\n let mut fields: BoundedVec = BoundedVec::new();\n for i in 0..num_chunks {\n let maybe_field = try_decode_field_from_bytes(bytes, i * 32);\n if maybe_field.is_some() {\n fields.push(maybe_field.unwrap());\n }\n }\n if fields.len() == num_chunks {\n Option::some(fields)\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n}\n\nfn try_decode_field_from_bytes(bytes: BoundedVec, offset: u32) -> Option {\n // Field arithmetic silently wraps values >= the modulus, so we compare each chunk against the modulus\n // byte-by-byte (big-endian) while building `field`. cmp: 0 = equal so far, 1 = less than modulus, 2 = exceeds.\n let p = std::field::modulus_be_bytes();\n let mut field = 0;\n let mut cmp: u8 = 0;\n for j in 0..32 {\n let byte = bytes.get(offset + j);\n field = field * 256 + byte as Field;\n if cmp == 0 {\n if byte < p[j] {\n cmp = 1;\n } else if byte > p[j] {\n cmp = 2;\n }\n }\n }\n\n if cmp == 1 {\n Option::some(field)\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_fields_from_bytes, encode_fields_as_bytes, try_decode_fields_from_bytes};\n\n #[test]\n unconstrained fn round_trips_fields(input: [Field; 3]) {\n let bytes = encode_fields_as_bytes(input);\n\n // In production the bytes fly through the system and arrive as a BoundedVec on the other end. 113 is an\n // arbitrary max length larger than the input length of 96.\n let bytes_bvec = BoundedVec::<_, 113>::from_array(bytes);\n let fields_back = try_decode_fields_from_bytes(bytes_bvec).unwrap();\n\n assert_eq(fields_back.len(), input.len());\n assert_eq(subarray(fields_back.storage(), 0), input);\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_length_not_multiple_of_32() {\n let input = BoundedVec::<_, 64>::from_parts([0 as u8; 64], 33);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test]\n unconstrained fn try_decode_accepts_max_field() {\n // -1 in field arithmetic wraps to `modulus - 1`, the largest valid field value.\n let max_field_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let input = BoundedVec::<_, 32>::from_array(max_field_as_bytes);\n\n let fields = try_decode_fields_from_bytes(input).unwrap();\n\n assert_eq(fields.get(0), -1);\n }\n\n // Verifies the overflow check: take the max allowed value, bump a random byte, feed it in.\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n // Skip if the selected byte is already 255. Acceptable under fuzz testing.\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_equal_to_modulus() {\n // The field modulus itself is not a valid field value (it wraps to 0).\n let p: [u8; 32] = std::field::modulus_be_bytes().as_array();\n let input = BoundedVec::::from_array(p);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test(should_fail_with = \"Input length must be a multiple of 32\")]\n unconstrained fn decode_asserts_length_multiple_of_32() {\n let input = BoundedVec::<_, 143>::from_array([\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n 30, 31, 32, 33,\n ]);\n let _fields = decode_fields_from_bytes(input);\n }\n\n #[test(should_fail_with = \"Value does not fit in field\")]\n unconstrained fn decode_panics_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n let _fields = decode_fields_from_bytes(input);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/fields_as_bytes.nr","function_locations":[{"start":1007,"name":"encode_fields_as_bytes"},{"start":1603,"name":"decode_fields_from_bytes"},{"start":2190,"name":"try_decode_fields_from_bytes"},{"start":2829,"name":"try_decode_field_from_bytes"},{"start":3733,"name":"tests::round_trips_fields"},{"start":4320,"name":"tests::try_decode_returns_none_on_length_not_multiple_of_32"},{"start":4528,"name":"tests::try_decode_accepts_max_field"},{"start":5063,"name":"tests::try_decode_returns_none_on_chunk_above_modulus"},{"start":5718,"name":"tests::try_decode_returns_none_on_chunk_equal_to_modulus"},{"start":6128,"name":"tests::decode_asserts_length_multiple_of_32"},{"start":6544,"name":"tests::decode_panics_on_chunk_above_modulus"}]},"256":{"source":"use crate::protocol::{point::Point, utils::field::sqrt};\n\n// I am storing the modulus minus 1 divided by 2 here because full modulus would throw \"String literal too large\" error\n// Full modulus is 21888242871839275222246405745257275088548364400416034343698204186575808495617\nglobal BN254_FR_MODULUS_DIV_2: Field = 10944121435919637611123202872628637544274182200208017171849102093287904247808;\n\n/// Returns: true if p.y <= MOD_DIV_2, else false.\npub fn get_sign_of_point(p: Point) -> bool {\n // We store only a \"sign\" of the y coordinate because the rest can be derived from the x coordinate. To get the\n // sign we check if the y coordinate is less or equal than the field's modulus minus 1 divided by 2. Ideally we'd\n // do `y <= MOD_DIV_2`, but there's no `lte` function, so instead we do `!(y > MOD_DIV_2)`, which is equivalent,\n // and then rewrite that as `!(MOD_DIV_2 < y)`, since we also have no `gt` function.\n !BN254_FR_MODULUS_DIV_2.lt(p.y)\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\npub fn point_from_x_coord(x: Field) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n sqrt(rhs).map(|y| Point { x, y, is_infinite: false })\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate and sign for the y coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\n///\n/// @param x - The x coordinate of the point @param sign - The \"sign\" of the y coordinate - determines whether y <=\n/// (Fr.MODULUS - 1) / 2\npub fn point_from_x_coord_and_sign(x: Field, sign: bool) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n\n sqrt(rhs).map(|y| {\n // If there is a square root, we need to ensure it has the correct \"sign\"\n let y_is_positive = !BN254_FR_MODULUS_DIV_2.lt(y);\n let final_y = if y_is_positive == sign { y } else { -y };\n Point { x, y: final_y, is_infinite: false }\n })\n}\n\nmod test {\n use crate::protocol::point::Point;\n use crate::utils::point::{\n BN254_FR_MODULUS_DIV_2, get_sign_of_point, point_from_x_coord, point_from_x_coord_and_sign,\n };\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign() {\n // Test positive y coordinate\n let x = 0x1af41f5de96446dc3776a1eb2d98bb956b7acd9979a67854bec6fa7c2973bd73;\n let sign = true;\n let p = point_from_x_coord_and_sign(x, sign).unwrap();\n\n assert_eq(p.x, x);\n assert_eq(p.y, 0x07fc22c7f2c7057571f137fe46ea9c95114282bc95d37d71ec4bfb88de457d4a);\n assert_eq(p.is_infinite, false);\n\n // Test negative y coordinate\n let x2 = 0x247371652e55dd74c9af8dbe9fb44931ba29a9229994384bd7077796c14ee2b5;\n let sign2 = false;\n let p2 = point_from_x_coord_and_sign(x2, sign2).unwrap();\n\n assert_eq(p2.x, x2);\n assert_eq(p2.y, 0x26441aec112e1ae4cee374f42556932001507ad46e255ffb27369c7e3766e5c0);\n assert_eq(p2.is_infinite, false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_valid() {\n // x = 8 is a known quadratic residue - should give a valid point\n let result = point_from_x_coord(Field::from(8));\n assert(result.is_some());\n\n let point = result.unwrap();\n assert_eq(point.x, Field::from(8));\n // Check curve equation y^2 = x^3 - 17\n assert_eq(point.y * point.y, point.x * point.x * point.x - 17);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_invalid() {\n // x = 3 is a non-residue for this curve - should give None\n let x = Field::from(3);\n let maybe_point = point_from_x_coord(x);\n assert(maybe_point.is_none());\n }\n\n #[test]\n unconstrained fn test_both_roots_satisfy_curve() {\n // Derive a point from x = 8 (known to be valid from test_point_from_x_coord_valid)\n let x: Field = 8;\n let point = point_from_x_coord(x).unwrap();\n\n // Check y satisfies curve equation\n assert_eq(point.y * point.y, x * x * x - 17);\n\n // Check -y also satisfies curve equation\n let neg_y = 0 - point.y;\n assert_eq(neg_y * neg_y, x * x * x - 17);\n\n // Verify they are different (unless y = 0)\n assert(point.y != neg_y);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign_invalid() {\n // x = 3 has no valid point on the curve (from test_point_from_x_coord_invalid)\n let x = Field::from(3);\n let result_positive = point_from_x_coord_and_sign(x, true);\n let result_negative = point_from_x_coord_and_sign(x, false);\n\n assert(result_positive.is_none());\n assert(result_negative.is_none());\n }\n\n #[test]\n unconstrained fn test_get_sign_of_point() {\n // Derive a point from x = 8, then test both possible y values\n let point = point_from_x_coord(8).unwrap();\n let neg_point = Point { x: point.x, y: 0 - point.y, is_infinite: false };\n\n // One should be \"positive\" (y <= MOD_DIV_2) and one \"negative\"\n let sign1 = get_sign_of_point(point);\n let sign2 = get_sign_of_point(neg_point);\n assert(sign1 != sign2);\n\n // y = 0 should return true (0 <= MOD_DIV_2)\n let zero_y_point = Point { x: 0, y: 0, is_infinite: false };\n assert(get_sign_of_point(zero_y_point) == true);\n\n // y = MOD_DIV_2 should return true (exactly at boundary)\n let boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2, is_infinite: false };\n assert(get_sign_of_point(boundary_point) == true);\n\n // y = MOD_DIV_2 + 1 should return false (just over boundary)\n let over_boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2 + 1, is_infinite: false };\n assert(get_sign_of_point(over_boundary_point) == false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_zero() {\n // x = 0: y^2 = 0^3 - 17 = -17, which is not a quadratic residue in BN254 scalar field\n let result = point_from_x_coord(0);\n assert(result.is_none());\n }\n\n #[test]\n unconstrained fn test_bn254_fr_modulus_div_2() {\n // Verify that BN254_FR_MODULUS_DIV_2 == (p - 1) / 2 This means: 2 * BN254_FR_MODULUS_DIV_2 + 1 == p == 0 (in\n // the field)\n assert_eq(2 * BN254_FR_MODULUS_DIV_2 + 1, 0);\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/point.nr","function_locations":[{"start":488,"name":"get_sign_of_point"},{"start":1371,"name":"point_from_x_coord"},{"start":2088,"name":"point_from_x_coord_and_sign"},{"start":2697,"name":"test::test_point_from_x_coord_and_sign"},{"start":3524,"name":"test::test_point_from_x_coord_valid"},{"start":3966,"name":"test::test_point_from_x_coord_invalid"},{"start":4228,"name":"test::test_both_roots_satisfy_curve"},{"start":4803,"name":"test::test_point_from_x_coord_and_sign_invalid"},{"start":5214,"name":"test::test_get_sign_of_point"},{"start":6328,"name":"test::test_point_from_x_coord_zero"},{"start":6573,"name":"test::test_bn254_fr_modulus_div_2"}]},"266":{"source":"use std::default::Default;\nuse std::hash::Hasher;\n\nglobal RATE: u32 = 3;\n\npub struct Poseidon2 {\n cache: [Field; 3],\n state: [Field; 4],\n cache_size: u32,\n squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2 {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2::hash_internal(input, message_size)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2 {\n let mut result =\n Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n self.state[0] += self.cache[0];\n self.state[1] += self.cache[1];\n self.state[2] += self.cache[2];\n self.state = crate::poseidon2_permutation(self.state);\n }\n\n fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(input: [Field; N], in_len: u32) -> Field {\n let two_pow_64 = 18446744073709551616;\n let iv: Field = (in_len as Field) * two_pow_64;\n let mut state = [0; 4];\n state[RATE] = iv;\n\n if std::runtime::is_unconstrained() {\n for i in 0..(in_len / RATE) {\n state[0] += input[i * RATE];\n state[1] += input[i * RATE + 1];\n state[2] += input[i * RATE + 2];\n state = crate::poseidon2_permutation(state);\n }\n\n // handle remaining elements after last full RATE-sized chunk\n let num_extra_fields = in_len % RATE;\n if num_extra_fields != 0 {\n let remainder_start = in_len - num_extra_fields;\n state[0] += input[remainder_start];\n if num_extra_fields > 1 {\n state[1] += input[remainder_start + 1];\n }\n }\n } else {\n let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];\n states[0] = state;\n\n // process all full RATE-sized chunks, storing state after each permutation\n for chunk_idx in 0..(N / RATE) {\n for i in 0..RATE {\n state[i] += input[chunk_idx * RATE + i];\n }\n state = crate::poseidon2_permutation(state);\n states[chunk_idx + 1] = state;\n }\n\n // get state at the last full block before in_len\n let first_partially_filled_chunk = in_len / RATE;\n state = states[first_partially_filled_chunk];\n\n // handle remaining elements after last full RATE-sized chunk\n let remainder_start = (in_len / RATE) * RATE;\n for j in 0..RATE {\n let idx = remainder_start + j;\n if idx < in_len {\n state[j] += input[idx];\n }\n }\n }\n\n // always run final permutation unless we just completed a full chunk\n // still need to permute once if in_len is 0\n if (in_len == 0) | (in_len % RATE != 0) {\n state = crate::poseidon2_permutation(state);\n };\n\n state[0]\n }\n}\n\npub struct Poseidon2Hasher {\n _state: [Field],\n}\n\nimpl Hasher for Poseidon2Hasher {\n fn finish(self) -> Field {\n let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)\n let mut sponge = Poseidon2::new(iv);\n for i in 0..self._state.len() {\n sponge.absorb(self._state[i]);\n }\n sponge.squeeze()\n }\n\n fn write(&mut self, input: Field) {\n self._state = self._state.push_back(input);\n }\n}\n\nimpl Default for Poseidon2Hasher {\n fn default() -> Self {\n Poseidon2Hasher { _state: @[] }\n }\n}\n","path":"/Users/maximvezenov/nargo/github.com/noir-lang/poseidon/v0.3.0/src/poseidon2.nr","function_locations":[{"start":333,"name":"Poseidon2::hash"},{"start":442,"name":"Poseidon2::new"},{"start":649,"name":"Poseidon2::perform_duplex"},{"start":923,"name":"Poseidon2::absorb"},{"start":1453,"name":"Poseidon2::squeeze"},{"start":1814,"name":"Poseidon2::hash_internal"},{"start":4105,"name":"::finish"},{"start":4426,"name":"::write"},{"start":4549,"name":"::default"}]},"355":{"source":"mod poseidon2_chunks;\n\nuse crate::{\n abis::{\n contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage,\n function_selector::FunctionSelector, nullifier::Nullifier, private_log::PrivateLog,\n transaction::tx_request::TxRequest,\n },\n address::{AztecAddress, EthAddress},\n constants::{\n CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, DOM_SEP__NOTE_HASH_NONCE,\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__SILOED_NOTE_HASH, DOM_SEP__SILOED_NULLIFIER,\n DOM_SEP__UNIQUE_NOTE_HASH, FUNCTION_TREE_HEIGHT, NULL_MSG_SENDER_CONTRACT_ADDRESS,\n TWO_POW_64,\n },\n merkle_tree::root_from_sibling_path,\n messaging::l2_to_l1_message::L2ToL1Message,\n poseidon2::Poseidon2Sponge,\n side_effect::{Counted, Scoped},\n traits::{FromField, Hash, ToField},\n utils::field::{field_from_bytes, field_from_bytes_32_trunc},\n};\n\npub use poseidon2_chunks::poseidon2_absorb_in_chunks_existing_sponge;\nuse poseidon2_chunks::poseidon2_absorb_in_chunks;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\n// TODO: refactor these into their own files: sha256, poseidon2, some protocol-specific hash computations, some merkle computations.\n\npub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field {\n let sha256_hashed = sha256::digest(bytes_to_hash);\n let hash_in_a_field = field_from_bytes_32_trunc(sha256_hashed);\n\n hash_in_a_field\n}\n\npub fn private_functions_root_from_siblings(\n selector: FunctionSelector,\n vk_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT],\n) -> Field {\n let function_leaf_preimage = ContractClassFunctionLeafPreimage { selector, vk_hash };\n let function_leaf = function_leaf_preimage.hash();\n root_from_sibling_path(\n function_leaf,\n function_leaf_index,\n function_leaf_sibling_path,\n )\n}\n\n/// Siloing in the context of Aztec refers to the process of hashing a note hash with a contract address (this way\n/// the note hash is scoped to a specific contract). This is used to prevent intermingling of notes between contracts.\npub fn compute_siloed_note_hash(contract_address: AztecAddress, note_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), note_hash],\n DOM_SEP__SILOED_NOTE_HASH,\n )\n}\n\n/// Computes unique, siloed note hashes from siloed note hashes.\n///\n/// The protocol injects uniqueness into every note_hash, so that every single note_hash in the\n/// tree is unique. This prevents faerie gold attacks, where a malicious sender could create\n/// two identical note_hashes for a recipient (meaning only one would be nullifiable in future).\n///\n/// Most privacy protocols will inject the note's leaf_index (its position in the Note Hashes Tree)\n/// into the note, but this requires the creator of a note to wait until their tx is included in\n/// a block to know the note's final note hash (the unique, siloed note hash), because inserting\n/// leaves into trees is the job of a block producer.\n///\n/// We took a different approach so that the creator of a note will know each note's unique, siloed\n/// note hash before broadcasting their tx to the network.\n/// (There was also a historical requirement relating to \"chained transactions\" -- a feature that\n/// Aztec Connect had to enable notes to be spent from distinct txs earlier in the same block,\n/// and hence before an archive block root had been established for that block -- but that feature\n/// was abandoned for the Aztec Network for having too many bad tradeoffs).\n///\n/// (\n/// Edit: it is no longer true that all final note_hashes will be known by the creator of a tx\n/// before they send it to the network. If a tx makes public function calls, then _revertible_\n/// note_hashes that are created in private will not be made unique in private by the Reset circuit,\n/// but will instead be made unique by the AVM, because the `note_index_in_tx` will not be known\n/// until the AVM has executed the public functions of the tx. (See an explanation in\n/// reset_output_composer.nr for why).\n/// For some such txs, the `note_index_in_tx` might still be predictable through simulation, but\n/// for txs whose public functions create a varying number of non-revertible notes (determined at\n/// runtime), the `note_index_in_tx` will not be deterministically derivable before submitting the\n/// tx to the network.\n/// )\n///\n/// We use the `first_nullifier` of a tx as a seed of uniqueness. We have a guarantee that there will\n/// always be at least one nullifier per tx, because the init circuit will create one if one isn't\n/// created naturally by any functions of the tx. (Search \"protocol_nullifier\").\n/// We combine the `first_nullifier` with the note's index (its position within this tx's new\n/// note_hashes array) (`note_index_in_tx`) to get a truly unique value to inject into a note, which\n/// we call a `note_nonce`.\npub fn compute_unique_note_hash(note_nonce: Field, siloed_note_hash: Field) -> Field {\n let inputs = [note_nonce, siloed_note_hash];\n poseidon2_hash_with_separator(inputs, DOM_SEP__UNIQUE_NOTE_HASH)\n}\n\npub fn compute_note_hash_nonce(first_nullifier_in_tx: Field, note_index_in_tx: u32) -> Field {\n // Hashing the first nullifier with note index in tx is guaranteed to be unique (because all nullifiers are also\n // unique).\n poseidon2_hash_with_separator(\n [first_nullifier_in_tx, note_index_in_tx as Field],\n DOM_SEP__NOTE_HASH_NONCE,\n )\n}\n\npub fn compute_note_nonce_and_unique_note_hash(\n siloed_note_hash: Field,\n first_nullifier: Field,\n note_index_in_tx: u32,\n) -> Field {\n let note_nonce = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n compute_unique_note_hash(note_nonce, siloed_note_hash)\n}\n\npub fn compute_siloed_nullifier(contract_address: AztecAddress, nullifier: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), nullifier],\n DOM_SEP__SILOED_NULLIFIER,\n )\n}\n\npub fn create_protocol_nullifier(tx_request: TxRequest) -> Scoped> {\n // The protocol nullifier is ascribed a special side-effect counter of 1. No other side-effect\n // can have counter 1 (see `validate_as_first_call` for that assertion).\n Nullifier { value: tx_request.hash(), note_hash: 0 }.count(1).scope(\n NULL_MSG_SENDER_CONTRACT_ADDRESS,\n )\n}\n\npub fn compute_log_tag(raw_tag: Field, dom_sep: u32) -> Field {\n poseidon2_hash_with_separator([raw_tag], dom_sep)\n}\n\npub fn compute_siloed_private_log_first_field(\n contract_address: AztecAddress,\n field: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), field],\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD,\n )\n}\n\npub fn compute_siloed_private_log(contract_address: AztecAddress, log: PrivateLog) -> PrivateLog {\n let mut fields = log.fields;\n fields[0] = compute_siloed_private_log_first_field(contract_address, fields[0]);\n PrivateLog::new(fields, log.length)\n}\n\npub fn compute_contract_class_log_hash(log: [Field; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS]) -> Field {\n poseidon2_hash(log)\n}\n\npub fn compute_app_siloed_secret_key(\n master_secret_key: EmbeddedCurveScalar,\n app_address: AztecAddress,\n key_type_domain_separator: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [master_secret_key.hi, master_secret_key.lo, app_address.to_field()],\n key_type_domain_separator,\n )\n}\n\npub fn compute_l2_to_l1_message_hash(\n message: Scoped,\n rollup_version_id: Field,\n chain_id: Field,\n) -> Field {\n let contract_address_bytes: [u8; 32] = message.contract_address.to_field().to_be_bytes();\n let recipient_bytes: [u8; 20] = message.inner.recipient.to_be_bytes();\n let content_bytes: [u8; 32] = message.inner.content.to_be_bytes();\n let rollup_version_id_bytes: [u8; 32] = rollup_version_id.to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n\n let mut bytes: [u8; 148] = std::mem::zeroed();\n for i in 0..32 {\n bytes[i] = contract_address_bytes[i];\n bytes[i + 32] = rollup_version_id_bytes[i];\n // 64 - 84 are for recipient.\n bytes[i + 84] = chain_id_bytes[i];\n bytes[i + 116] = content_bytes[i];\n }\n\n for i in 0..20 {\n bytes[64 + i] = recipient_bytes[i];\n }\n\n sha256_to_field(bytes)\n}\n\n// TODO: consider a variant that enables domain separation with a u32 (we seem to have standardised u32s for domain separators)\n/// Computes sha256 hash of 2 input fields.\n///\n/// @returns A truncated field (i.e., the first byte is always 0).\npub fn accumulate_sha256(v0: Field, v1: Field) -> Field {\n // Concatenate two fields into 32 x 2 = 64 bytes\n let v0_as_bytes: [u8; 32] = v0.to_be_bytes();\n let v1_as_bytes: [u8; 32] = v1.to_be_bytes();\n let hash_input_flattened = v0_as_bytes.concat(v1_as_bytes);\n\n sha256_to_field(hash_input_flattened)\n}\n\npub fn poseidon2_hash(inputs: [Field; N]) -> Field {\n poseidon::poseidon2::Poseidon2::hash(inputs, N)\n}\n\n#[no_predicates]\npub fn poseidon2_hash_with_separator(inputs: [Field; N], separator: T) -> Field\nwhere\n T: ToField,\n{\n let inputs_with_separator = [separator.to_field()].concat(inputs);\n poseidon2_hash(inputs_with_separator)\n}\n\n/// Computes a Poseidon2 hash over a dynamic-length subarray of the given input.\n/// Only the first `in_len` fields of `input` are absorbed; any remaining fields are ignored.\n/// The caller is responsible for ensuring that the input is padded with zeros if required.\n#[no_predicates]\npub fn poseidon2_hash_subarray(input: [Field; N], in_len: u32) -> Field {\n let mut sponge = poseidon2_absorb_in_chunks(input, in_len);\n sponge.squeeze()\n}\n\n// This function is unconstrained because it is intended to be used in unconstrained context only as\n// in constrained contexts it would be too inefficient.\npub unconstrained fn poseidon2_hash_with_separator_bounded_vec(\n inputs: BoundedVec,\n separator: T,\n) -> Field\nwhere\n T: ToField,\n{\n let in_len = inputs.len() + 1;\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n sponge.absorb(separator.to_field());\n\n for i in 0..inputs.len() {\n sponge.absorb(inputs.get(i));\n }\n\n sponge.squeeze()\n}\n\n#[no_predicates]\npub fn poseidon2_hash_bytes(inputs: [u8; N]) -> Field {\n let mut fields = [0; (N + 30) / 31];\n let mut field_index = 0;\n let mut current_field = [0; 31];\n for i in 0..inputs.len() {\n let index = i % 31;\n current_field[index] = inputs[i];\n if index == 30 {\n fields[field_index] = field_from_bytes(current_field, false);\n current_field = [0; 31];\n field_index += 1;\n }\n }\n if field_index != fields.len() {\n fields[field_index] = field_from_bytes(current_field, false);\n }\n poseidon2_hash(fields)\n}\n\n#[test]\nfn subarray_hash_matches_fixed() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash the entire values_to_hash.\n let fixed_len_hash = poseidon::poseidon2::Poseidon2::hash(values_to_hash, values_to_hash.len());\n\n assert_eq(subarray_hash, fixed_len_hash);\n}\n\n#[test]\nfn subarray_hash_matches_variable() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash up to values_to_hash.len() fields of the padded array.\n let variable_len_hash = poseidon::poseidon2::Poseidon2::hash(padded, values_to_hash.len());\n\n assert_eq(subarray_hash, variable_len_hash);\n}\n\n#[test]\nfn smoke_sha256_to_field() {\n let full_buffer = [\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\n 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,\n 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,\n 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,\n 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,\n 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,\n 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\n ];\n let result = sha256_to_field(full_buffer);\n\n assert(result == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184c7);\n\n // to show correctness of the current ver (truncate one byte) vs old ver (mod full bytes):\n let result_bytes = sha256::digest(full_buffer);\n let truncated_field = crate::utils::field::field_from_bytes_32_trunc(result_bytes);\n assert(truncated_field == result);\n let mod_res = result + (result_bytes[31] as Field);\n assert(mod_res == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184e0);\n}\n\n#[test]\nfn unique_siloed_note_hash_matches_typescript() {\n let inner_note_hash = 1;\n let contract_address = AztecAddress::from_field(2);\n let first_nullifier = 3;\n let note_index_in_tx = 4;\n\n let siloed_note_hash = compute_siloed_note_hash(contract_address, inner_note_hash);\n let siloed_note_hash_from_ts =\n 0x1986a4bea3eddb1fff917d629a13e10f63f514f401bdd61838c6b475db949169;\n assert_eq(siloed_note_hash, siloed_note_hash_from_ts);\n\n let nonce: Field = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n let note_hash_nonce_from_ts =\n 0x28e7799791bf066a57bb51fdd0fbcaf3f0926414314c7db515ea343f44f5d58b;\n assert_eq(nonce, note_hash_nonce_from_ts);\n\n let unique_siloed_note_hash_from_nonce = compute_unique_note_hash(nonce, siloed_note_hash);\n let unique_siloed_note_hash = compute_note_nonce_and_unique_note_hash(\n siloed_note_hash,\n first_nullifier,\n note_index_in_tx,\n );\n assert_eq(unique_siloed_note_hash_from_nonce, unique_siloed_note_hash);\n\n let unique_siloed_note_hash_from_ts =\n 0x29949aef207b715303b24639737c17fbfeb375c1d965ecfa85c7e4f0febb7d16;\n assert_eq(unique_siloed_note_hash, unique_siloed_note_hash_from_ts);\n}\n\n#[test]\nfn siloed_nullifier_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let nullifier = 456;\n\n let res = compute_siloed_nullifier(contract_address, nullifier);\n\n let siloed_nullifier_from_ts =\n 0x169b50336c1f29afdb8a03d955a81e485f5ac7d5f0b8065673d1e407e5877813;\n\n assert_eq(res, siloed_nullifier_from_ts);\n}\n\n#[test]\nfn siloed_private_log_first_field_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let field = 456;\n let res = compute_siloed_private_log_first_field(contract_address, field);\n\n let siloed_private_log_first_field_from_ts =\n 0x29480984f7b9257fded523d50addbcfc8d1d33adcf2db73ef3390a8fd5cdffaa;\n\n assert_eq(res, siloed_private_log_first_field_from_ts);\n}\n\n#[test]\nfn empty_l2_to_l1_message_hash_matches_typescript() {\n // All zeroes\n let res = compute_l2_to_l1_message_hash(\n L2ToL1Message { recipient: EthAddress::zero(), content: 0 }.scope(AztecAddress::from_field(\n 0,\n )),\n 0,\n 0,\n );\n\n let empty_l2_to_l1_msg_hash_from_ts =\n 0x003b18c58c739716e76429634a61375c45b3b5cd470c22ab6d3e14cee23dd992;\n\n assert_eq(res, empty_l2_to_l1_msg_hash_from_ts);\n}\n\n#[test]\nfn l2_to_l1_message_hash_matches_typescript() {\n let message = L2ToL1Message { recipient: EthAddress::from_field(1), content: 2 }.scope(\n AztecAddress::from_field(3),\n );\n let version = 4;\n let chainId = 5;\n\n let hash = compute_l2_to_l1_message_hash(message, version, chainId);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let l2_to_l1_message_hash_from_ts =\n 0x0081edf209e087ad31b3fd24263698723d57190bd1d6e9fe056fc0c0a68ee661;\n\n assert_eq(hash, l2_to_l1_message_hash_from_ts);\n}\n\n#[test]\nunconstrained fn poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version() {\n let inputs = BoundedVec::::from_array([1, 2, 3]);\n let separator = 42;\n\n // Hash using bounded vec version\n let bounded_result = poseidon2_hash_with_separator_bounded_vec(inputs, separator);\n\n // Hash using regular version\n let regular_result = poseidon2_hash_with_separator([1, 2, 3], separator);\n\n // Results should match\n assert_eq(bounded_result, regular_result);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr","function_locations":[{"start":1253,"name":"sha256_to_field"},{"start":1605,"name":"private_functions_root_from_siblings"},{"start":2202,"name":"compute_siloed_note_hash"},{"start":5031,"name":"compute_unique_note_hash"},{"start":5247,"name":"compute_note_hash_nonce"},{"start":5663,"name":"compute_note_nonce_and_unique_note_hash"},{"start":5899,"name":"compute_siloed_nullifier"},{"start":6116,"name":"create_protocol_nullifier"},{"start":6480,"name":"compute_log_tag"},{"start":6651,"name":"compute_siloed_private_log_first_field"},{"start":6882,"name":"compute_siloed_private_log"},{"start":7142,"name":"compute_contract_class_log_hash"},{"start":7333,"name":"compute_app_siloed_secret_key"},{"start":7628,"name":"compute_l2_to_l1_message_hash"},{"start":8709,"name":"accumulate_sha256"},{"start":9037,"name":"poseidon2_hash"},{"start":9228,"name":"poseidon2_hash_with_separator"},{"start":9714,"name":"poseidon2_hash_subarray"},{"start":10126,"name":"poseidon2_hash_with_separator_bounded_vec"},{"start":10487,"name":"poseidon2_hash_bytes"},{"start":11063,"name":"subarray_hash_matches_fixed"},{"start":11462,"name":"subarray_hash_matches_variable"},{"start":11878,"name":"smoke_sha256_to_field"},{"start":13280,"name":"unique_siloed_note_hash_matches_typescript"},{"start":14502,"name":"siloed_nullifier_matches_typescript"},{"start":14882,"name":"siloed_private_log_first_field_matches_typescript"},{"start":15292,"name":"empty_l2_to_l1_message_hash_matches_typescript"},{"start":15743,"name":"l2_to_l1_message_hash_matches_typescript"},{"start":16359,"name":"poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version"}]},"357":{"source":"// Log levels matching the JS logger:\n\n// global SILENT_LOG_LEVEL: u8 = 0;\nglobal FATAL_LOG_LEVEL: u8 = 1;\nglobal ERROR_LOG_LEVEL: u8 = 2;\nglobal WARN_LOG_LEVEL: u8 = 3;\nglobal INFO_LOG_LEVEL: u8 = 4;\nglobal VERBOSE_LOG_LEVEL: u8 = 5;\nglobal DEBUG_LOG_LEVEL: u8 = 6;\nglobal TRACE_LOG_LEVEL: u8 = 7;\n\n// --- Per-level log functions (no format args) ---\n\npub fn fatal_log(msg: str) {\n fatal_log_format(msg, []);\n}\n\npub fn error_log(msg: str) {\n error_log_format(msg, []);\n}\n\npub fn warn_log(msg: str) {\n warn_log_format(msg, []);\n}\n\npub fn info_log(msg: str) {\n info_log_format(msg, []);\n}\n\npub fn verbose_log(msg: str) {\n verbose_log_format(msg, []);\n}\n\npub fn debug_log(msg: str) {\n debug_log_format(msg, []);\n}\n\npub fn trace_log(msg: str) {\n trace_log_format(msg, []);\n}\n\n// --- Per-level log functions (with format args) ---\n\npub fn fatal_log_format(msg: str, args: [Field; N]) {\n log_format(FATAL_LOG_LEVEL, msg, args);\n}\n\npub fn error_log_format(msg: str, args: [Field; N]) {\n log_format(ERROR_LOG_LEVEL, msg, args);\n}\n\npub fn warn_log_format(msg: str, args: [Field; N]) {\n log_format(WARN_LOG_LEVEL, msg, args);\n}\n\npub fn info_log_format(msg: str, args: [Field; N]) {\n log_format(INFO_LOG_LEVEL, msg, args);\n}\n\npub fn verbose_log_format(msg: str, args: [Field; N]) {\n log_format(VERBOSE_LOG_LEVEL, msg, args);\n}\n\npub fn debug_log_format(msg: str, args: [Field; N]) {\n log_format(DEBUG_LOG_LEVEL, msg, args);\n}\n\npub fn trace_log_format(msg: str, args: [Field; N]) {\n log_format(TRACE_LOG_LEVEL, msg, args);\n}\n\nfn log_format(log_level: u8, msg: str, args: [Field; N]) {\n // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe\n // to call.\n unsafe { log_oracle_wrapper(log_level, msg, args) };\n}\n\nunconstrained fn log_oracle_wrapper(\n log_level: u8,\n msg: str,\n args: [Field; N],\n) {\n log_oracle(log_level, msg, N, args);\n}\n\n// While the length parameter might seem unnecessary given that we have N, we keep it around because at the AVM\n// bytecode level we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally\n// take that route. The AVM transpiler maps this oracle to the DEBUGLOG opcode, which reads the fields size from memory.\n#[oracle(aztec_utl_log)]\nunconstrained fn log_oracle(\n log_level: u8,\n msg: str,\n length: u32,\n args: [Field; N],\n) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/logging.nr","function_locations":[{"start":395,"name":"fatal_log"},{"start":473,"name":"error_log"},{"start":550,"name":"warn_log"},{"start":626,"name":"info_log"},{"start":705,"name":"verbose_log"},{"start":785,"name":"debug_log"},{"start":863,"name":"trace_log"},{"start":1033,"name":"fatal_log_format"},{"start":1161,"name":"error_log_format"},{"start":1288,"name":"warn_log_format"},{"start":1414,"name":"info_log_format"},{"start":1543,"name":"verbose_log_format"},{"start":1673,"name":"debug_log_format"},{"start":1801,"name":"trace_log_format"},{"start":1934,"name":"log_format"},{"start":2248,"name":"log_oracle_wrapper"},{"start":2801,"name":"log_oracle"}]},"376":{"source":"use crate::constants::TWO_POW_64;\nuse crate::traits::{Deserialize, Serialize};\nuse std::meta::derive;\n// NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr\n// It exists as we sometimes need to perform custom absorption, but the stdlib version\n// has a private absorb() method (it's also designed to just be a hasher)\n// Can be removed when standalone noir poseidon lib exists: See noir#6679\n// TODO: Poseidon is stand-alone now\n\nglobal RATE: u32 = 3;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct Poseidon2Sponge {\n pub cache: [Field; 3],\n pub state: [Field; 4],\n pub cache_size: u32,\n pub squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2Sponge {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2Sponge::hash_internal(input, message_size, message_size != N)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2Sponge {\n let mut result =\n Poseidon2Sponge { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n for i in 0..RATE {\n // We effectively zero-pad the cache by only adding to the state\n // cache that is less than the specified `cache_size`\n if i < self.cache_size {\n self.state[i] += self.cache[i];\n }\n }\n self.state = std::hash::poseidon2_permutation(self.state);\n }\n\n pub fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n pub fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(\n input: [Field; N],\n in_len: u32,\n is_variable_length: bool,\n ) -> Field {\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n for i in 0..input.len() {\n if i < in_len {\n sponge.absorb(input[i]);\n }\n }\n\n sponge.squeeze()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr","function_locations":[{"start":798,"name":"Poseidon2Sponge::hash"},{"start":938,"name":"Poseidon2Sponge::new"},{"start":1151,"name":"Poseidon2Sponge::perform_duplex"},{"start":1592,"name":"Poseidon2Sponge::absorb"},{"start":2126,"name":"Poseidon2Sponge::squeeze"},{"start":2544,"name":"Poseidon2Sponge::hash_internal"}]},"395":{"source":"use crate::utils::field::field_from_bytes;\n\npub trait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n #[inline_always]\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for bool {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u8 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u16 {\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u32 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u64 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u128 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for str {\n #[inline_always]\n fn to_field(self) -> Field {\n assert(N < 32, \"String doesn't fit in a field, consider using Serialize instead\");\n field_from_bytes(self.as_bytes(), true)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/traits/to_field.nr","function_locations":[{"start":176,"name":"::to_field"},{"start":276,"name":"::to_field"},{"start":382,"name":"::to_field"},{"start":468,"name":"::to_field"},{"start":575,"name":"::to_field"},{"start":682,"name":"::to_field"},{"start":790,"name":"::to_field"},{"start":912,"name":">::to_field"}]},"403":{"source":"pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n\n// Convert a 32 byte array to a field element by truncating the final byte\npub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..15 {\n // covers bytes 16..30 (31 is truncated and ignored)\n low = low + (bytes32[15 + 15 - i] as Field) * v;\n v = v * 256;\n // covers bytes 0..14\n high = high + (bytes32[14 - i] as Field) * v;\n }\n // covers byte 15\n low = low + (bytes32[15] as Field) * v;\n\n low + high * v\n}\n\npub fn min(f1: Field, f2: Field) -> Field {\n if f1.lt(f2) {\n f1\n } else {\n f2\n }\n}\n\n// TODO: write doc-comments and tests for these magic constants.\n\nglobal KNOWN_NON_RESIDUE: Field = 5; // This is a non-residue in Noir's native Field.\nglobal C1: u32 = 28;\nglobal C3: Field = 40770029410420498293352137776570907027550720424234931066070132305055;\nglobal C5: Field = 19103219067921713944291392827692070036145651957329286315305642004821462161904;\n\n// @dev: only use this for _huge_ exponents y, when writing a constrained function.\n// If you're only exponentiating by a small value, first consider writing-out the multiplications by hand.\n// Only after you've measured the gates of that approach, consider using the native Field::pow_32 function.\n// Only if your exponent is larger than 32 bits, resort to using this function.\npub fn pow(x: Field, y: Field) -> Field {\n let mut r = 1 as Field;\n let b: [bool; 254] = y.to_le_bits();\n\n for i in 0..254 {\n r *= r;\n r *= (b[254 - 1 - i] as Field) * x + (1 - b[254 - 1 - i] as Field);\n }\n\n r\n}\n\n/// Returns Option::some(sqrt) if there is a square root, and Option::none() if there isn't.\npub fn sqrt(x: Field) -> Option {\n // Safety: if the hint returns the square root of x, then we simply square it\n // check the result equals x. If x is not square, we return a value that\n // enables us to prove that fact (see the `else` clause below).\n let (is_sq, maybe_sqrt) = unsafe { __sqrt(x) };\n\n if is_sq {\n let sqrt = maybe_sqrt;\n validate_sqrt_hint(x, sqrt);\n Option::some(sqrt)\n } else {\n let not_sqrt_hint = maybe_sqrt;\n validate_not_sqrt_hint(x, not_sqrt_hint);\n Option::none()\n }\n}\n\n// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.\nunconstrained fn is_square(x: Field) -> bool {\n let v = pow(x, -1 / 2);\n v * (v - 1) == 0\n}\n\n// Tonelli-Shanks algorithm for computing the square root of a Field element.\n// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field\n// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),\n// and C5 = ZETA^C2, where ZETA is a non-square element of Field.\n// These are pre-computed above as globals.\nunconstrained fn tonelli_shanks_sqrt(x: Field) -> Field {\n let mut z = pow(x, C3);\n let mut t = z * z * x;\n z *= x;\n let mut b = t;\n let mut c = C5;\n\n for i in 0..(C1 - 1) {\n for _j in 1..(C1 - i - 1) {\n b *= b;\n }\n\n z *= if b == 1 { 1 } else { c };\n\n c *= c;\n\n t *= if b == 1 { 1 } else { c };\n\n b = t;\n }\n\n z\n}\n\n// NB: this doesn't return an option, because in the case of there _not_ being a square root, we still want to return a field element that allows us to then assert in the _constrained_ sqrt function that there is no sqrt.\nunconstrained fn __sqrt(x: Field) -> (bool, Field) {\n let is_sq = is_square(x);\n if is_sq {\n let sqrt = tonelli_shanks_sqrt(x);\n (true, sqrt)\n } else {\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // sq * sq = sq // 1 * 1 = 1\n // non-sq * non-sq = sq // -1 * -1 = 1\n // sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n let not_sqrt = tonelli_shanks_sqrt(demo_x_not_square);\n (false, not_sqrt)\n }\n}\n\nfn validate_sqrt_hint(x: Field, hint: Field) {\n assert(hint * hint == x, f\"The claimed_sqrt {hint} is not the sqrt of x {x}\");\n}\n\nfn validate_not_sqrt_hint(x: Field, hint: Field) {\n // We need this assertion, because x = 0 would pass the other assertions in this\n // function, and we don't want people to be able to prove that 0 is not square!\n assert(x != 0, \"0 has a square root; you cannot claim it is not square\");\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n //\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // 1. sq * sq = sq // 1 * 1 = 1\n // 2. non-sq * non-sq = sq // -1 * -1 = 1\n // 3. sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n //\n // We want to demonstrate that this below multiplication falls under bullet-point (2):\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n // I.e. we want to demonstrate that `demo_x_not_square` has Legendre symbol 1\n // (i.e. that it is a square), so we prove that it is square below.\n // Why do we want to prove that it has LS 1?\n // Well, since it was computed with a known-non-residue, its squareness implies we're\n // in case 2 (something multiplied by a known-non-residue yielding a result which\n // has a LS of 1), which implies that x must be a non-square. The unconstrained\n // function gave us the sqrt of demo_x_not_square, so all we need to do is\n // assert its squareness:\n assert(\n hint * hint == demo_x_not_square,\n f\"The hint {hint} does not demonstrate that {x} is not a square\",\n );\n}\n\n#[test]\nunconstrained fn bytes_field_test() {\n // Tests correctness of field_from_bytes_32_trunc against existing methods\n // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7\n let inputs = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167,\n ];\n let field = field_from_bytes(inputs, true);\n let return_bytes: [u8; 31] = field.to_be_bytes();\n assert_eq(inputs, return_bytes);\n // 32 bytes - we remove the final byte, and check it matches the field\n let inputs2 = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158,\n ];\n let field2 = field_from_bytes_32_trunc(inputs2);\n let return_bytes2: [u8; 31] = field2.to_be_bytes();\n\n assert_eq(return_bytes2, return_bytes);\n assert_eq(field2, field);\n}\n\n#[test]\nunconstrained fn max_field_test() {\n // Tests the hardcoded value in constants.nr vs underlying modulus\n // NB: We can't use 0-1 in constants.nr as it will be transpiled incorrectly to ts and sol constants files\n let max_value = crate::constants::MAX_FIELD_VALUE;\n assert_eq(max_value, 0 - 1);\n // modulus == 0 is tested elsewhere, so below is more of a sanity check\n let max_bytes: [u8; 32] = max_value.to_be_bytes();\n let mod_bytes = std::field::modulus_be_bytes();\n for i in 0..31 {\n assert_eq(max_bytes[i], mod_bytes[i]);\n }\n assert_eq(max_bytes[31], mod_bytes[31] - 1);\n}\n\n#[test]\nunconstrained fn sqrt_valid_test() {\n let x = 16; // examples: 16, 9, 25, 81\n let result = sqrt(x);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), x);\n}\n\n#[test]\nunconstrained fn sqrt_invalid_test() {\n let x = KNOWN_NON_RESIDUE; // has no square root in the field\n let result = sqrt(x);\n assert(result.is_none());\n}\n\n#[test]\nunconstrained fn sqrt_zero_test() {\n let result = sqrt(0);\n assert(result.is_some());\n assert_eq(result.unwrap(), 0);\n}\n\n#[test]\nunconstrained fn sqrt_one_test() {\n let result = sqrt(1);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), 1);\n}\n\n#[test]\nunconstrained fn field_from_bytes_empty_test() {\n let empty: [u8; 0] = [];\n let result = field_from_bytes(empty, true);\n assert_eq(result, 0);\n\n let result_le = field_from_bytes(empty, false);\n assert_eq(result_le, 0);\n}\n\n#[test]\nunconstrained fn field_from_bytes_little_endian_test() {\n // Test little-endian conversion: [0x01, 0x02] should be 0x0201 = 513\n let bytes = [0x01, 0x02];\n let result_le = field_from_bytes(bytes, false);\n assert_eq(result_le, 0x0201);\n\n // Compare with big-endian: [0x01, 0x02] should be 0x0102 = 258\n let result_be = field_from_bytes(bytes, true);\n assert_eq(result_be, 0x0102);\n}\n\n#[test]\nunconstrained fn pow_test() {\n assert_eq(pow(2, 0), 1);\n assert_eq(pow(2, 1), 2);\n assert_eq(pow(2, 10), 1024);\n assert_eq(pow(3, 5), 243);\n assert_eq(pow(0, 5), 0);\n assert_eq(pow(1, 100), 1);\n}\n\n#[test]\nunconstrained fn min_test() {\n assert_eq(min(5, 10), 5);\n assert_eq(min(10, 5), 5);\n assert_eq(min(7, 7), 7);\n assert_eq(min(0, 1), 0);\n}\n\n#[test]\nunconstrained fn sqrt_has_two_roots_test() {\n // Every square has two roots: r and -r (i.e., p - r)\n // sqrt(16) can return 4 or -4\n let x = 16;\n let result = sqrt(x).unwrap();\n assert(result * result == x);\n // The other root is -result\n let other_root = 0 - result;\n assert(other_root * other_root == x);\n // Verify they are different (unless x = 0)\n assert(result != other_root);\n\n // Same for 9: roots are 3 and -3\n let y = 9;\n let result_y = sqrt(y).unwrap();\n assert(result_y * result_y == y);\n let other_root_y = 0 - result_y;\n assert(other_root_y * other_root_y == y);\n assert(result_y != other_root_y);\n}\n\n#[test]\nunconstrained fn sqrt_negative_one_test() {\n let x = 0 - 1;\n let result = sqrt(x);\n assert(result.unwrap() == 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636);\n}\n\n#[test]\nunconstrained fn validate_sqrt_hint_valid_test() {\n // 4 is a valid sqrt of 16\n validate_sqrt_hint(16, 4);\n // -4 is also a valid sqrt of 16\n validate_sqrt_hint(16, 0 - 4);\n // 0 is a valid sqrt of 0\n validate_sqrt_hint(0, 0);\n // 1 is a valid sqrt of 1\n validate_sqrt_hint(1, 1);\n // -1 is also a valid sqrt of 1\n validate_sqrt_hint(1, 0 - 1);\n}\n\n#[test(should_fail_with = \"is not the sqrt of x\")]\nunconstrained fn validate_sqrt_hint_invalid_test() {\n // 5 is not a valid sqrt of 16\n validate_sqrt_hint(16, 5);\n}\n\n#[test]\nunconstrained fn validate_not_sqrt_hint_valid_test() {\n // 5 (KNOWN_NON_RESIDUE) is not a square.\n let x = KNOWN_NON_RESIDUE;\n let hint = tonelli_shanks_sqrt(x * KNOWN_NON_RESIDUE);\n validate_not_sqrt_hint(x, hint);\n}\n\n#[test(should_fail_with = \"0 has a square root\")]\nunconstrained fn validate_not_sqrt_hint_zero_test() {\n // 0 has a square root, so we cannot claim it is not square\n validate_not_sqrt_hint(0, 0);\n}\n\n#[test(should_fail_with = \"does not demonstrate that\")]\nunconstrained fn validate_not_sqrt_hint_wrong_hint_test() {\n // Provide a wrong hint for a non-square\n let x = KNOWN_NON_RESIDUE;\n validate_not_sqrt_hint(x, 123);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr","function_locations":[{"start":79,"name":"field_from_bytes"},{"start":553,"name":"field_from_bytes_32_trunc"},{"start":1054,"name":"min"},{"start":1899,"name":"pow"},{"start":2233,"name":"sqrt"},{"start":2915,"name":"is_square"},{"start":3343,"name":"tonelli_shanks_sqrt"},{"start":3951,"name":"__sqrt"},{"start":4795,"name":"validate_sqrt_hint"},{"start":4932,"name":"validate_not_sqrt_hint"},{"start":6570,"name":"bytes_field_test"},{"start":7553,"name":"max_field_test"},{"start":8177,"name":"sqrt_valid_test"},{"start":8379,"name":"sqrt_invalid_test"},{"start":8548,"name":"sqrt_zero_test"},{"start":8685,"name":"sqrt_one_test"},{"start":8854,"name":"field_from_bytes_empty_test"},{"start":9107,"name":"field_from_bytes_little_endian_test"},{"start":9492,"name":"pow_test"},{"start":9715,"name":"min_test"},{"start":9889,"name":"sqrt_has_two_roots_test"},{"start":10562,"name":"sqrt_negative_one_test"},{"start":10768,"name":"validate_sqrt_hint_valid_test"},{"start":11199,"name":"validate_sqrt_hint_invalid_test"},{"start":11331,"name":"validate_not_sqrt_hint_valid_test"},{"start":11611,"name":"validate_not_sqrt_hint_zero_test"},{"start":11828,"name":"validate_not_sqrt_hint_wrong_hint_test"}]},"409":{"source":"pub struct Reader {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Reader {\n pub fn new(data: [Field; N]) -> Self {\n Self { data, offset: 0 }\n }\n\n pub fn read(&mut self) -> Field {\n let result = self.data[self.offset];\n self.offset += 1;\n result\n }\n\n pub fn read_u32(&mut self) -> u32 {\n self.read() as u32\n }\n\n pub fn read_u64(&mut self) -> u64 {\n self.read() as u64\n }\n\n pub fn read_bool(&mut self) -> bool {\n self.read() != 0\n }\n\n pub fn read_array(&mut self) -> [Field; K] {\n let mut result = [0; K];\n for i in 0..K {\n result[i] = self.data[self.offset + i];\n }\n self.offset += K;\n result\n }\n\n pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T {\n let result = deserialise(self.read_array());\n result\n }\n\n pub fn read_struct_array(\n &mut self,\n deserialise: fn([Field; K]) -> T,\n mut result: [T; C],\n ) -> [T; C] {\n for i in 0..C {\n result[i] = self.read_struct(deserialise);\n }\n result\n }\n\n pub fn peek_offset(&mut self, offset: u32) -> Field {\n self.data[self.offset + offset]\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) {\n assert_eq(self.offset, self.data.len(), \"Reader did not read all data\");\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/reader.nr","function_locations":[{"start":144,"name":"Reader::new"},{"start":222,"name":"Reader::read"},{"start":355,"name":"Reader::read_u32"},{"start":429,"name":"Reader::read_u64"},{"start":505,"name":"Reader::read_bool"},{"start":598,"name":"Reader::read_array"},{"start":855,"name":"Reader::read_struct"},{"start":1094,"name":"Reader::read_struct_array"},{"start":1263,"name":"Reader::peek_offset"},{"start":1362,"name":"Reader::advance_offset"},{"start":1426,"name":"Reader::finish"}]},"410":{"source":"use crate::{reader::Reader, writer::Writer};\n\n/// Trait for serializing Noir types into arrays of Fields.\n///\n/// An implementation of the Serialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait (and Deserialize) are\n/// typically used to communicate between Noir and TypeScript (via oracles and function arguments).\n///\n/// # On Following Noir's Intrinsic Serialization\n/// When calling a Noir function from TypeScript (TS), first the function arguments are serialized into an array\n/// of fields. This array is then included in the initial witness. Noir's intrinsic serialization is then used\n/// to deserialize the arguments from the witness. When the same Noir function is called from Noir this Serialize trait\n/// is used instead of the serialization in TS. For this reason we need to have a match between TS serialization,\n/// Noir's intrinsic serialization and the implementation of this trait. If there is a mismatch, the function calls\n/// fail with an arguments hash mismatch error message.\n///\n/// # Associated Constants\n/// * `N` - The length of the output Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Serialize for str {\n/// let N: u32 = N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// let bytes = self.as_bytes();\n/// for i in 0..bytes.len() {\n/// writer.write(bytes[i] as Field);\n/// }\n/// }\n/// }\n/// ```\n#[derive_via(derive_serialize)]\npub trait Serialize {\n let N: u32;\n\n fn serialize(self) -> [Field; Self::N];\n\n fn stream_serialize(self, writer: &mut Writer);\n}\n\n/// Generates a `Serialize` trait implementation for a struct type.\n///\n/// # Parameters\n/// - `s`: The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A quoted code block containing the trait implementation\n///\n/// # Example\n/// For a struct defined as:\n/// ```\n/// struct Log {\n/// fields: [Field; N],\n/// length: u32\n/// }\n/// ```\n///\n/// This function generates code equivalent to:\n/// ```\n/// impl Serialize for Log {\n/// let N: u32 = <[Field; N] as Serialize>::N + ::N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// #[inline_always]\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// Serialize::stream_serialize(self.fields, writer);\n/// Serialize::stream_serialize(self.length, writer);\n/// }\n/// }\n/// ```\npub comptime fn derive_serialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n\n // We care only about the name and type so we drop the last item of the tuple\n let params = nested_struct.0.fields(nested_struct.1).map(|(name, typ, _)| (name, typ));\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Serialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_serialize_clause = get_where_trait_clause(s, quote {Serialize});\n\n let params_len_quote = get_params_len_quote(params);\n\n let function_body = params\n .map(|(name, _typ): (Quoted, Type)| {\n quote {\n $crate::serialization::Serialize::stream_serialize(self.$name, writer);\n }\n })\n .join(quote {});\n\n quote {\n impl$generics_declarations $crate::serialization::Serialize for $typ\n $where_serialize_clause\n {\n let N: u32 = $params_len_quote;\n\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n $crate::serialization::Serialize::stream_serialize(self, &mut writer);\n writer.finish()\n }\n\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n $function_body\n }\n }\n }\n}\n\n/// Trait for deserializing Noir types from arrays of Fields.\n///\n/// An implementation of the Deserialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait is typically used when\n/// deserializing return values from function calls in Noir. Since the same function could be called from TypeScript\n/// (TS), in which case the TS deserialization would get used, we need to have a match between the 2.\n///\n/// # Associated Constants\n/// * `N` - The length of the input Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Deserialize for str {\n/// let N: u32 = M;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let mut bytes = [0 as u8; M];\n/// for i in 0..M {\n/// bytes[i] = reader.read() as u8;\n/// }\n/// str::::from(bytes)\n/// }\n/// }\n/// ```\n#[derive_via(derive_deserialize)]\npub trait Deserialize {\n let N: u32;\n\n fn deserialize(fields: [Field; Self::N]) -> Self;\n\n fn stream_deserialize(reader: &mut Reader) -> Self;\n}\n\n/// Generates a `Deserialize` trait implementation for a given struct `s`.\n///\n/// # Arguments\n/// * `s` - The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A `Quoted` block containing the generated trait implementation\n///\n/// # Requirements\n/// Each struct member type must implement the `Deserialize` trait (it gets used in the generated code).\n///\n/// # Example\n/// For a struct like:\n/// ```\n/// struct MyStruct {\n/// x: AztecAddress,\n/// y: Field,\n/// }\n/// ```\n///\n/// This generates:\n/// ```\n/// impl Deserialize for MyStruct {\n/// let N: u32 = ::N + ::N;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// #[inline_always]\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let x = ::stream_deserialize(reader);\n/// let y = ::stream_deserialize(reader);\n/// Self { x, y }\n/// }\n/// }\n/// ```\npub comptime fn derive_deserialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n let params = nested_struct.0.fields(nested_struct.1);\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Deserialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_deserialize_clause = get_where_trait_clause(s, quote {Deserialize});\n\n // The following will give us:\n // ::N + ::N + ...\n // (or 0 if the struct has no members)\n let right_hand_side_of_definition_of_n = if params.len() > 0 {\n params\n .map(|(_, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n <$param_type as $crate::serialization::Deserialize>::N\n }\n })\n .join(quote {+})\n } else {\n quote {0}\n };\n\n // For structs containing a single member, we can enhance performance by directly deserializing the input array,\n // bypassing the need for loop-based array construction. While this optimization yields significant benefits in\n // Brillig where the loops are expected to not be optimized, it is not relevant in ACIR where the loops are\n // expected to be optimized away.\n let function_body = if params.len() > 1 {\n // This generates deserialization code for each struct member and concatenates them together.\n let deserialization_of_struct_members = params\n .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n let $param_name = <$param_type as Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote {});\n\n // We join the struct member names with a comma to be used in the `Self { ... }` syntax\n // This will give us e.g. `a, b, c` for a struct with three fields named `a`, `b`, and `c`.\n let struct_members = params\n .map(|(param_name, _, _): (Quoted, Type, Quoted)| quote { $param_name })\n .join(quote {,});\n\n quote {\n $deserialization_of_struct_members\n\n Self { $struct_members }\n }\n } else if params.len() == 1 {\n let param_name = params[0].0;\n quote {\n Self { $param_name: $crate::serialization::Deserialize::stream_deserialize(reader) }\n }\n } else {\n quote {\n Self {}\n }\n };\n\n quote {\n impl$generics_declarations $crate::serialization::Deserialize for $typ\n $where_deserialize_clause\n {\n let N: u32 = $right_hand_side_of_definition_of_n;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $function_body\n }\n }\n }\n}\n\n/// Generates a quoted expression that computes the total serialized length of function parameters.\n///\n/// # Parameters\n/// * `params` - An array of tuples where each tuple contains a quoted parameter name and its Type. The type needs\n/// to implement the Serialize trait.\n///\n/// # Returns\n/// A quoted expression that evaluates to:\n/// * `0` if there are no parameters\n/// * `(::N + ::N + ...)` for one or more parameters\ncomptime fn get_params_len_quote(params: [(Quoted, Type)]) -> Quoted {\n if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::serialization::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n }\n}\n\ncomptime fn get_generics_declarations(s: TypeDefinition) -> Quoted {\n let generics = s.generics();\n\n if generics.len() > 0 {\n let generics_declarations_items = generics\n .map(|(name, maybe_integer_typ)| {\n // The second item in the generics tuple is an Option of an integer type that is Some only if\n // the generic is numeric.\n if maybe_integer_typ.is_some() {\n // The generic is numeric, so we return a quote defined as e.g. \"let N: u32\"\n let integer_type = maybe_integer_typ.unwrap();\n quote {let $name: $integer_type}\n } else {\n // The generic is not numeric, so we return a quote containing the name of the generic (e.g. \"T\")\n quote {$name}\n }\n })\n .join(quote {,});\n quote {<$generics_declarations_items>}\n } else {\n // The struct doesn't have any generics defined, so we just return an empty quote.\n quote {}\n }\n}\n\ncomptime fn get_where_trait_clause(s: TypeDefinition, trait_name: Quoted) -> Quoted {\n let generics = s.generics();\n\n // The second item in the generics tuple is an Option of an integer type that is Some only if the generic is\n // numeric.\n let non_numeric_generics =\n generics.filter(|(_, maybe_integer_typ)| maybe_integer_typ.is_none());\n\n if non_numeric_generics.len() > 0 {\n let non_numeric_generics_declarations =\n non_numeric_generics.map(|(name, _)| quote {$name: $trait_name}).join(quote {,});\n quote {where $non_numeric_generics_declarations}\n } else {\n // There are no non-numeric generics, so we return an empty quote.\n quote {}\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/serialization.nr","function_locations":[{"start":3018,"name":"derive_serialize"},{"start":7206,"name":"derive_deserialize"},{"start":10928,"name":"get_params_len_quote"},{"start":11387,"name":"get_generics_declarations"},{"start":12469,"name":"get_where_trait_clause"}]},"412":{"source":"use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};\nuse std::embedded_curve_ops::EmbeddedCurvePoint;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\nglobal BOOL_SERIALIZED_LEN: u32 = 1;\nglobal U8_SERIALIZED_LEN: u32 = 1;\nglobal U16_SERIALIZED_LEN: u32 = 1;\nglobal U32_SERIALIZED_LEN: u32 = 1;\nglobal U64_SERIALIZED_LEN: u32 = 1;\nglobal U128_SERIALIZED_LEN: u32 = 1;\nglobal FIELD_SERIALIZED_LEN: u32 = 1;\nglobal I8_SERIALIZED_LEN: u32 = 1;\nglobal I16_SERIALIZED_LEN: u32 = 1;\nglobal I32_SERIALIZED_LEN: u32 = 1;\nglobal I64_SERIALIZED_LEN: u32 = 1;\n\nimpl Serialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> bool {\n reader.read() != 0\n }\n}\n\nimpl Serialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8\n }\n}\n\nimpl Serialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16\n }\n}\n\nimpl Serialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32\n }\n}\n\nimpl Serialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64\n }\n}\n\nimpl Serialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u128\n }\n}\n\nimpl Serialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self);\n }\n}\n\nimpl Deserialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read()\n }\n}\n\nimpl Serialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u8 as Field);\n }\n}\n\nimpl Deserialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8 as i8\n }\n}\n\nimpl Serialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u16 as Field);\n }\n}\n\nimpl Deserialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16 as i16\n }\n}\n\nimpl Serialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u32 as Field);\n }\n}\n\nimpl Deserialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32 as i32\n }\n}\n\nimpl Serialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u64 as Field);\n }\n}\n\nimpl Deserialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64 as i64\n }\n}\n\nimpl Serialize for [T; M]\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n for i in 0..M {\n self[i].stream_serialize(writer);\n }\n }\n}\n\nimpl Deserialize for [T; M]\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut result: [T; M] = std::mem::zeroed();\n for i in 0..M {\n result[i] = T::stream_deserialize(reader);\n }\n result\n }\n}\n\nimpl Serialize for Option\nwhere\n T: Serialize,\n{\n let N: u32 = ::N + 1;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write_bool(self.is_some());\n if self.is_some() {\n self.unwrap_unchecked().stream_serialize(writer);\n } else {\n writer.advance_offset(::N);\n }\n }\n}\n\nimpl Deserialize for Option\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n if reader.read_bool() {\n Option::some(::stream_deserialize(reader))\n } else {\n reader.advance_offset(::N);\n Option::none()\n }\n }\n}\n\nglobal SCALAR_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurveScalar {\n\n let N: u32 = SCALAR_SIZE;\n\n fn serialize(self) -> [Field; SCALAR_SIZE] {\n [self.lo, self.hi]\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.lo);\n writer.write(self.hi);\n }\n}\n\nimpl Deserialize for EmbeddedCurveScalar {\n let N: u32 = SCALAR_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { lo: fields[0], hi: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { lo: reader.read(), hi: reader.read() }\n }\n}\n\nglobal POINT_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn serialize(self) -> [Field; Self::N] {\n [self.x, self.y]\n }\n\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.x);\n writer.write(self.y);\n }\n}\n\nimpl Deserialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { x: fields[0], y: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { x: reader.read(), y: reader.read() }\n }\n}\n\nimpl Deserialize for str {\n let N: u32 = M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);\n str::::from(u8_arr)\n }\n}\n\nimpl Serialize for str {\n let N: u32 = M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.as_bytes().stream_serialize(writer);\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Deserialize for BoundedVec\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut new_bounded_vec: BoundedVec = BoundedVec::new();\n let payload_len = Self::N - 1;\n\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n let len = reader.peek_offset(payload_len) as u32;\n\n for i in 0..M {\n if i < len {\n new_bounded_vec.push(::stream_deserialize(reader));\n }\n }\n\n // +1 for the length of the BoundedVec\n reader.advance_offset((M - len) * ::N + 1);\n\n new_bounded_vec\n }\n}\n\n// This may cause issues if used as program input, because noir disallows empty arrays for program input.\n// I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint\n// if someone does run into this in the future.\nimpl Deserialize for () {\n let N: u32 = 0;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(_reader: &mut Reader) -> Self {\n ()\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Serialize for BoundedVec\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M + 1; // +1 for the length of the BoundedVec\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.storage().stream_serialize(writer);\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n writer.write_u32(self.len() as u32);\n }\n}\n\n// Create a slice of the given length with each element made from `f(i)` where `i` is the current index\ncomptime fn make_slice(length: u32, f: fn[Env](u32) -> T) -> [T] {\n let mut slice = @[];\n for i in 0..length {\n slice = slice.push_back(f(i));\n }\n slice\n}\n\n// Implements Serialize and Deserialize for an arbitrary tuple type\ncomptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {\n // `T0`, `T1`, `T2`\n let type_names = make_slice(length, |i| f\"T{i}\".quoted_contents());\n\n // `result0`, `result1`, `result2`\n let result_names = make_slice(length, |i| f\"result{i}\".quoted_contents());\n\n // `T0, T1, T2`\n let field_generics = type_names.join(quote [,]);\n\n // `::N + ::N + ::N`\n let full_size_serialize = type_names\n .map(|type_name| quote {\n <$type_name as Serialize>::N\n })\n .join(quote [+]);\n\n // `::N + ::N + ::N`\n let full_size_deserialize = type_names\n .map(|type_name| quote {\n <$type_name as Deserialize>::N\n })\n .join(quote [+]);\n\n // `T0: Serialize, T1: Serialize, T2: Serialize,`\n let serialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Serialize,\n })\n .join(quote []);\n\n // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`\n let deserialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Deserialize,\n })\n .join(quote []);\n\n // Statements to serialize each field\n let serialized_fields = type_names\n .mapi(|i, _type_name| quote {\n $crate::serialization::Serialize::stream_serialize(self.$i, writer);\n })\n .join(quote []);\n\n // Statements to deserialize each field\n let deserialized_fields = type_names\n .mapi(|i, type_name| {\n let result_name = result_names[i];\n quote {\n let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote []);\n let deserialize_results = result_names.join(quote [,]);\n\n quote {\n impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {\n let N: u32 = $full_size_serialize;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n\n $serialized_fields\n }\n }\n\n impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {\n let N: u32 = $full_size_deserialize;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n \n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $deserialized_fields\n ($deserialize_results)\n }\n }\n }\n}\n\n// Keeping these manual impls. They are more efficient since they do not\n// require copying sub-arrays from any serialized arrays.\nimpl Serialize for (T1,)\nwhere\n T1: Serialize,\n{\n let N: u32 = ::N;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: crate::writer::Writer = crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.0.stream_serialize(writer);\n }\n}\n\nimpl Deserialize for (T1,)\nwhere\n T1: Deserialize,\n{\n let N: u32 = ::N;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n (::stream_deserialize(reader),)\n }\n}\n\n#[impl_serialize_for_tuple(2)]\n#[impl_serialize_for_tuple(3)]\n#[impl_serialize_for_tuple(4)]\n#[impl_serialize_for_tuple(5)]\n#[impl_serialize_for_tuple(6)]\nmod impls {\n use crate::serialization::{Deserialize, Serialize};\n}\n\n#[test]\nunconstrained fn bounded_vec_serialization() {\n // Test empty BoundedVec\n let empty_vec: BoundedVec = BoundedVec::from_array([]);\n let serialized = empty_vec.serialize();\n let deserialized = BoundedVec::::deserialize(serialized);\n assert_eq(empty_vec, deserialized);\n assert_eq(deserialized.len(), 0);\n\n // Test partially filled BoundedVec\n let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);\n let serialized = partial_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(partial_vec, deserialized);\n assert_eq(deserialized.len(), 1);\n assert_eq(deserialized.get(0), [1, 2]);\n\n // Test full BoundedVec\n let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);\n let serialized = full_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(full_vec, deserialized);\n assert_eq(deserialized.len(), 3);\n assert_eq(deserialized.get(0), [1, 2]);\n assert_eq(deserialized.get(1), [3, 4]);\n assert_eq(deserialized.get(2), [5, 6]);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/type_impls.nr","function_locations":[{"start":693,"name":"::serialize"},{"start":914,"name":"::stream_serialize"},{"start":1082,"name":"::deserialize"},{"start":1328,"name":"::stream_deserialize"},{"start":1470,"name":"::serialize"},{"start":1691,"name":"::stream_serialize"},{"start":1855,"name":"::deserialize"},{"start":2101,"name":"::stream_deserialize"},{"start":2246,"name":"::serialize"},{"start":2467,"name":"::stream_serialize"},{"start":2633,"name":"::deserialize"},{"start":2879,"name":"::stream_deserialize"},{"start":3025,"name":"::serialize"},{"start":3246,"name":"::stream_serialize"},{"start":3412,"name":"::deserialize"},{"start":3658,"name":"::stream_deserialize"},{"start":3804,"name":"::serialize"},{"start":4025,"name":"::stream_serialize"},{"start":4191,"name":"::deserialize"},{"start":4437,"name":"::stream_deserialize"},{"start":4585,"name":"::serialize"},{"start":4806,"name":"::stream_serialize"},{"start":4974,"name":"::deserialize"},{"start":5220,"name":"::stream_deserialize"},{"start":5371,"name":"::serialize"},{"start":5592,"name":"::stream_serialize"},{"start":5753,"name":"::deserialize"},{"start":5999,"name":"::stream_deserialize"},{"start":6136,"name":"::serialize"},{"start":6357,"name":"::stream_serialize"},{"start":6527,"name":"::deserialize"},{"start":6773,"name":"::stream_deserialize"},{"start":6924,"name":"::serialize"},{"start":7145,"name":"::stream_serialize"},{"start":7318,"name":"::deserialize"},{"start":7564,"name":"::stream_deserialize"},{"start":7717,"name":"::serialize"},{"start":7938,"name":"::stream_serialize"},{"start":8111,"name":"::deserialize"},{"start":8357,"name":"::stream_deserialize"},{"start":8510,"name":"::serialize"},{"start":8731,"name":"::stream_serialize"},{"start":8904,"name":"::deserialize"},{"start":9150,"name":"::stream_deserialize"},{"start":9350,"name":"::serialize"},{"start":9571,"name":"::stream_serialize"},{"start":9831,"name":"::deserialize"},{"start":10077,"name":"::stream_deserialize"},{"start":10389,"name":">::serialize"},{"start":10610,"name":">::stream_serialize"},{"start":10997,"name":">::deserialize"},{"start":11243,"name":">::stream_deserialize"},{"start":11621,"name":"::serialize"},{"start":11744,"name":"::stream_serialize"},{"start":11944,"name":"::deserialize"},{"start":12090,"name":"::stream_deserialize"},{"start":12297,"name":"::serialize"},{"start":12397,"name":"::stream_serialize"},{"start":12593,"name":"::deserialize"},{"start":12737,"name":"::stream_deserialize"},{"start":12916,"name":">::deserialize"},{"start":13162,"name":">::stream_deserialize"},{"start":13395,"name":">::serialize"},{"start":13616,"name":">::stream_serialize"},{"start":13997,"name":">::deserialize"},{"start":14243,"name":">::stream_deserialize"},{"start":15299,"name":"::deserialize"},{"start":15546,"name":"::stream_deserialize"},{"start":15911,"name":">::serialize"},{"start":16132,"name":">::stream_serialize"},{"start":16617,"name":"make_slice"},{"start":16867,"name":"impl_serialize_for_tuple"},{"start":20158,"name":"::serialize"},{"start":20409,"name":"::stream_serialize"},{"start":20616,"name":"::deserialize"},{"start":20877,"name":"::stream_deserialize"},{"start":21226,"name":"bounded_vec_serialization"}]},"413":{"source":"pub struct Writer {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Writer {\n pub fn new() -> Self {\n Self { data: [0; N], offset: 0 }\n }\n\n pub fn write(&mut self, value: Field) {\n self.data[self.offset] = value;\n self.offset += 1;\n }\n\n pub fn write_u32(&mut self, value: u32) {\n self.write(value as Field);\n }\n\n pub fn write_u64(&mut self, value: u64) {\n self.write(value as Field);\n }\n\n pub fn write_bool(&mut self, value: bool) {\n self.write(value as Field);\n }\n\n pub fn write_array(&mut self, value: [Field; K]) {\n for i in 0..K {\n self.data[i + self.offset] = value[i];\n }\n self.offset += K;\n }\n\n pub fn write_struct(&mut self, value: T, serialize: fn(T) -> [Field; K]) {\n self.write_array(serialize(value));\n }\n\n pub fn write_struct_array(\n &mut self,\n value: [T; C],\n serialize: fn(T) -> [Field; K],\n ) {\n for i in 0..C {\n self.write_struct(value[i], serialize);\n }\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) -> [Field; N] {\n assert_eq(self.offset, self.data.len(), \"Writer did not write all data\");\n self.data\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/writer.nr","function_locations":[{"start":128,"name":"Writer::new"},{"start":220,"name":"Writer::write"},{"start":339,"name":"Writer::write_u32"},{"start":428,"name":"Writer::write_u64"},{"start":519,"name":"Writer::write_bool"},{"start":629,"name":"Writer::write_array"},{"start":841,"name":"Writer::write_struct"},{"start":1040,"name":"Writer::write_struct_array"},{"start":1185,"name":"Writer::advance_offset"},{"start":1263,"name":"Writer::finish"}]}}} \ No newline at end of file diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/Nargo.toml index 14327850fecb..a6ac1090fa28 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/Nargo.toml similarity index 66% rename from noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/Nargo.toml index de8971626ad0..0638ade66b1f 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/Nargo.toml index b6785b52010e..e4977f869e05 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/Nargo.toml similarity index 70% rename from noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/Nargo.toml index 5914769cb4d6..f3dcc8cfe2e6 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/non_serializable/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/Nargo.toml similarity index 70% rename from noir-projects/noir-contracts-comp-failures/contracts/non_serializable/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/Nargo.toml index 61dd673b2bd3..cdab1cef9a69 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/non_serializable/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/non_serializable/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/non_serializable/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/Nargo.toml similarity index 66% rename from noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/Nargo.toml index 286bc46ee0af..72dda38ed4e6 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/Nargo.toml similarity index 65% rename from noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/Nargo.toml index 4560f50a26e3..f8be0fd46638 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/Nargo.toml similarity index 74% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/Nargo.toml index 35ab8ec6157d..6eed4a585ff7 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/Nargo.toml similarity index 74% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/Nargo.toml index f1ad725a4ce8..436b4ee2e970 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/Nargo.toml similarity index 74% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/Nargo.toml index a7ce32c176e5..ec3e23bb13da 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/Nargo.toml similarity index 74% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/Nargo.toml index f740d59f6626..84a37e697ef4 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/Nargo.toml similarity index 74% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/Nargo.toml index 261086647ccd..f56dc5fb2456 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/Nargo.toml similarity index 74% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/Nargo.toml index a40cc7085669..64f73d29257e 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/Nargo.toml similarity index 75% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/Nargo.toml index 7f0978672f74..96d0dc5861ba 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/Nargo.toml @@ -5,5 +5,5 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/Nargo.toml similarity index 74% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/Nargo.toml index 82418ccd25ca..ae1de16b581c 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/Nargo.toml @@ -5,5 +5,5 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/Nargo.toml similarity index 75% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/Nargo.toml index 0bcb6a7437d8..69528a9afa01 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/Nargo.toml @@ -5,5 +5,5 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/Nargo.toml similarity index 73% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/Nargo.toml index 84c1a3f7fff7..ce8727023340 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/Nargo.toml similarity index 73% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/Nargo.toml index 597dc861fd55..cabcfcb6cdd5 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/Nargo.toml similarity index 65% rename from noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/Nargo.toml index cc1650303414..431efaa8d4b3 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/Nargo.toml similarity index 65% rename from noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/Nargo.toml index 7953452634e6..1863966a4d4b 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/Nargo.toml similarity index 65% rename from noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/Nargo.toml index 6e878c49849c..94a7e823a84b 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/Nargo.toml similarity index 66% rename from noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/Nargo.toml index 0d19a888079a..fcc5e3960242 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/Nargo.toml similarity index 73% rename from noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/Nargo.toml index fc464e417620..7bd2e4a7abca 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.25.0" type = "contract" [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/Nargo.toml similarity index 68% rename from noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/Nargo.toml index 7a20f71d024d..3fb10af0c6af 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/Nargo.toml similarity index 65% rename from noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/Nargo.toml index a15aff4abcac..f875ce7c8202 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/Nargo.toml similarity index 68% rename from noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/Nargo.toml index 20537523e403..d4a297a56c34 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/Nargo.toml index e9269ae24e7a..0c1533e2caeb 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/Nargo.toml similarity index 66% rename from noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/Nargo.toml index 323d48fb2edc..8d2ada72c96a 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/Nargo.toml similarity index 65% rename from noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/Nargo.toml index 3461ff6d5fe4..5ab0d2b3adfb 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/Nargo.toml similarity index 64% rename from noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/Nargo.toml index c4845c37358f..7da9cd25bdaf 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_before_external/Nargo.toml b/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/Nargo.toml similarity index 67% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_before_external/Nargo.toml rename to noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/Nargo.toml index f29f5d173b46..a2b023bb7165 100644 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_before_external/Nargo.toml +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/Nargo.toml @@ -4,4 +4,4 @@ type = "contract" authors = [""] [dependencies] -aztec = { path = "../../../aztec-nr/aztec" } +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_before_external/src/main.nr b/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/src/main.nr similarity index 100% rename from noir-projects/noir-contracts-comp-failures/contracts/authorize_once_before_external/src/main.nr rename to noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json b/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json new file mode 100644 index 000000000000..4dd4989aa8e1 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json @@ -0,0 +1 @@ +{"noir_version":"1.0.0-beta.20+f39ac4f5748a1ea5dc7bcb8eb5b2c2a8032a2199","name":"AuthorizeOnceBeforeExternal","functions":[{"name":"__aztec_nr_internals__foo","hash":"17058486681893845468","is_unconstrained":true,"custom_attributes":["abi_public"],"abi":{"parameters":[{"name":"from","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"},{"name":"authwit_nonce","type":{"kind":"field"},"visibility":"private"}],"return_type":null,"error_types":{"26387131971136782":{"error_kind":"string","string":"Invalid response from registry"},"7136484461999155778":{"error_kind":"string","string":"Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"},"8502498164115016271":{"error_kind":"string","string":"semantic length returned from oracle does not match data"},"9894212961085021188":{"error_kind":"string","string":"Message not authorized by account"}}},"bytecode":"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","debug_symbols":"tZndTis7DIXfpddcJLbjJLzKFkIFylalqqBuONIR4t2PzdiZKVJy6M++Ya22zFfHsZPM9GP1tHl4/32/3T+//Fnd/vpYPRy2u9329/3u5XH9tn3Zy7sfq6B/Yl3d4s0K5EUWiavbGEVBVN9GU7L3kymLJtFsWkzrpBhMlSdclOtBrkO5HoSHbJrt/WIq14NcR8E0moKpxANFlEyTKZtm02JaJ03BVHlVFEyFh/K9iUyFh/I9iU2zaTGtk3IwjabCQ+ExmpJpMhUeyXg5mxbTOmkOptEUTNGUTJOp8bLxsvGy8YrxivIkvgKmaEqmyZRNs6nyWLROWoWXQDSagimakmkyZdNsWkzrpDEEN9ENuEE35EappIbdZDfFTTUTg5voRslJDbpRMqtJ/g67yW6Km2pGe2QySi5qwA26ITfJDbvJbpRc1VQz2i6MaqIbcINuyE1yw26ym+KmmiEnk5O1lVhHob00GSVnNUrWeLSdclST3RQ31Yy21GSiG3CDbshNcuPk5OTk5ORkdjI7mZ3MTmYns5PZyexkdjI7WdsqBzXohtwoR/OjrTWZ7Ka4qWa0rbKWlvbVZNCNAjWr2lqTUaAWmzbXZIoZbausmde+mgy4UWD+/LxZ+Zp9/3bYbHTJXizisrS/rg+b/dvqdv++292s/lnv3r/+6c/rev+lb+uDfCpD3OyfRAX4vN1t1H3ezFeH/qWAIdnVgJAaQHrmCBEHiEDayBMjEHODcDliwICRixMqzUFk+vE4uLATcindcVAfgUSeCiSeU5HhiJCukAn+i5lIiB5DQsqLTOARovQRJOuaIUi6u5eJOhiFXNbGIctB7GUihtGEVJ8P7qdiHMVcFbK8lG4Ug9IkCHMuaiOks5K5GMe3ZMZBZdbohVlhHgPFn5YEhjiXBMZuSUS+MA2jsgx6BJtioDiIYZDKWGrxkpDlVa5sYXxL5jVKEy4uzXiN2oRLa/OEjAL0MgqXlucwihra0iueYzeK0cIJ1CZFfMZuQvMAQrUt4NIq3ZkdB5K0mS2QBLUbyHg0Jc0QDD0Ijqo05ValcxRQyikzU6jNjJzVezODMDxj0HzICP2OQxz1CzSGHNq6GzzS5bM7jmNmwNFa+i2O0eTK6bUxYN6iy3HL4KBQKzC0pqtzGDLlx4zB5HJoCyEHnsPAn0cxnx4rEnSjoEGRSu+jM0INfUYcLceOwMXZD76VF41qNOZ5NS50HgMQ27TyIA4anRZyW9IhLE5vPw8Da/adVmzthvE/+0I7yUrfx27f02gxhVDmFVnuMruQcoUSq5eXWAqXlliKl5fYkPHDEkt4cYkNw0hQ54U0nzeURLExGM9iYG07LVbql3rKfzUdV+m4GiHOHbe49/vWLBxGkNq2awhy6u9CBqORp0DohSq+f5BiGO0tBG1vWdxC4ilhVJ8YeQyVuycgHu34YXHITv0dfxhImvda8aV7fOHRls+5HV+48pmBILbDWMLUf7xQRs8X5kcUOZ8dSAyLQHIvkDx6YlO4ZUROmWcGQm09FD8IZLRfErRjsjy/6QcyGozcOrUVMcDiscsJ3SsX1paSgP3D9gkQ4B5kwCBsSxHhovG+7tXv5OX6cXs4+rnpU2GH7fpht7GXz+/7x8Wnb/+++if+c9Xr4eVx8/R+2Chp/s1K/vyKlW/kwHCnD+jlpbSuvMx3n/rt/wE="},{"name":"offchain_receive","hash":"16664779991078358632","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]},"visibility":"private"}],"return_type":null,"error_types":{"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"}}},"bytecode":"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","debug_symbols":"tZndbhs5DEbfxde+GFI/FPMqQVG4qbswYDiBmyywKPLuS2b0acZZSPDa7U10kniOKQ4paexfm+/7b29/fT2cfjz/3Dw8/tp8Ox+Ox8NfX4/PT7vXw/PJ/vprM/mPzGXzELY26uYh2ximOlIduY6hjrGOqY65jlLHUsfqi9UXqy9WX7LXiY3Z/q4+ch3NT+SQAPYO5CFmARSAVpAJQAAGBEAEJADMArPALDAXmAvMBeYCc4G5wFxgLjAXmAvMCrPCrDArzAqzVrNMflVyIAAD/DXZIQMEYO/Ok4NWoAlAAAYEgL07++WUABkgADeLg1bgCeBmdTBz8OA5ACIgATJAAAWgFbw2ZyAAzAHmALMXaPC0eIXOIAA3e4RepB/gVTqDX+4xR3txJAd7cXRh1AppAlgYMTowIAAiIAEyQABu9niSVsgTgABu9sByAESAm4tDBgigALSCN8gMBHCzz9QbZIYISAAzJ0+CN8gMBWDmxAbeIDMQgAEBEAEJ4GbPoTfIDAWgFbxBkifKGyR5sXmDzBAAbvZseIPMkAECKACdoXgTzeDm4sCAAIgAX+kmhwwQgC925KAVvK0yOxCAAQHgS2h2cLO/hbfVDAIoAK3gbTUDAdysDgFgZvEwvK1myAAzi7+7t9UMWsHbagYCMCAA3BwcEiADBODm6KAVvK1mIIBflRwEUAB+lc/L+2sGAng8PkHvrxkiIAEyQAAFYObi98v7awYCMMDN+f19u8Em+fX1vN/7HrnaNW0vfdmd96fXzcPp7Xjcbv7eHd8+XvTzZXf6GF93Z/uvKfen7zaa8MfhuHd63y5XT/1LabJFrF5uLNQUNF1KqC+Jvjh/KGKUJpDL67l/fUiYQZCyBFDo+llYl7VZlJK6s4h9ScocqiPZSWJRpHihSH0FZ+aqYDt8NEW+OgbbKhGD7VLdGAYKOzRJVdgsYldR+grb06vBlvJFIHr9NFoMyTacbgw0uKeBSVEVHFInl2ODtroKU+kZBoUZiWGIFPSG+2mLIxJRYugnYuBQgkJ5mUSkq2PQhA7PE8ebamoKiyL2FSSDHtWMqiKVxZEuq4oGdUlCaC+yU0JXoaNkIggtq6XGlp2rDbqsl5S6Ch6sl8wRDubUvafMoxWvrTQ0JeqHEYbFya04V10a6fKu8rAyJl2Ka+o7RqtmTG3RlJWBbisM7ReGjO5JoHZPVp36ScGDKHJKLRdJ401RUMbCafF0owiDVS+mthlLvy7CaDunzG3V0/U95UvHqD5TuyEprAzp+ii4VVZkkX4Ug+okLtjSKRD14xg4goS2D5Wp9OPIf9ZBmWLLaSYJ3V4LgxrVpMiIrmv0P45hJGFZA+2zln7Xx9HunJdDX+zemaEhtqRerF6fDKP9fQpYeuyoJP15DBwcMA9OfFMUXNr6V3K/RmV0dJ3aSm5l0p9H/g25yHfnIt+di3x/LtJ0fy5GjutyMTTcnQsLvrR5ZLqp26/ORfqzjivzme7O53BP0jaPMFjHk/6GPWlUn4KVL60fVD+fYkcHjVBwTOD1U+L/OatEaqfYtDqCflLkcO9ZJY9250nR7ZbM/p6Y0+g5MS9PmoVvdLSpmK70HXJvhQ/zeVVdjI7z3NJpX870n1dlUJz2BQdSYd9shM5D89BQuH2EYZ/U3WSQ0gxyw4O7fQUVWiJC/4l3eNbK7QSrmfJt57W1I/TrW37Djihy/woud9f30NBfwb/Yr7unw/nia8d3V50Pu2/Hff31x9vpafXf139e8B98bflyfn7af3877920fHdpPx6LfapclL9sN/b57aOdwbeZxX7zj98fi+pWJ/ry7rH8Cw=="},{"name":"public_dispatch","hash":"10014804801067860817","is_unconstrained":true,"custom_attributes":["abi_public"],"abi":{"parameters":[{"name":"selector","type":{"kind":"field"},"visibility":"private"}],"return_type":null,"error_types":{"26387131971136782":{"error_kind":"string","string":"Invalid response from registry"},"7136484461999155778":{"error_kind":"string","string":"Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"},"8502498164115016271":{"error_kind":"string","string":"semantic length returned from oracle does not match data"},"9894212961085021188":{"error_kind":"string","string":"Message not authorized by account"},"11194752367584870169":{"error_kind":"fmtstring","length":27,"item_types":[{"kind":"field"}]}}},"bytecode":"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","debug_symbols":"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"},{"name":"sync_state","hash":"8131136269561630715","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"return_type":null,"error_types":{"361444214588792908":{"error_kind":"string","string":"attempt to multiply with overflow"},"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"1064022259863234536":{"error_kind":"fmtstring","length":101,"item_types":[{"kind":"integer","sign":"unsigned","width":32}]},"1998584279744703196":{"error_kind":"string","string":"attempt to subtract with overflow"},"5421095327929394772":{"error_kind":"string","string":"attempt to bit-shift with overflow"},"5449178635769758673":{"error_kind":"fmtstring","length":61,"item_types":[{"kind":"field"},{"kind":"field"}]},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"9791669845391776238":{"error_kind":"string","string":"0 has a square root; you cannot claim it is not square"},"9885968605480832328":{"error_kind":"string","string":"Attempted to read past the length of a CapsuleArray"},"10791800398362570014":{"error_kind":"string","string":"extend_from_bounded_vec out of bounds"},"10835969307644359280":{"error_kind":"fmtstring","length":40,"item_types":[]},"11021520179822076911":{"error_kind":"string","string":"Attempted to delete past the length of a CapsuleArray"},"12820178569648940736":{"error_kind":"fmtstring","length":48,"item_types":[{"kind":"field"},{"kind":"field"}]},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"},"17110599087403377004":{"error_kind":"fmtstring","length":98,"item_types":[]},"17655676068928457687":{"error_kind":"string","string":"Reader did not read all data"}}},"bytecode":"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","debug_symbols":"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"}],"outputs":{"structs":{"functions":[{"kind":"struct","path":"AuthorizeOnceBeforeExternal::foo_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::foo_parameters","fields":[{"name":"from","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"authwit_nonce","type":{"kind":"field"}}]}}]},{"kind":"struct","path":"AuthorizeOnceBeforeExternal::offchain_receive_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::offchain_receive_parameters","fields":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]},{"kind":"struct","path":"AuthorizeOnceBeforeExternal::sync_state_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::sync_state_parameters","fields":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}]},"globals":{}},"file_map":{"3":{"source":"use crate::cmp::{Eq, Ord};\nuse crate::convert::From;\nuse crate::runtime::is_unconstrained;\n\nmod check_shuffle;\nmod quicksort;\n\nimpl [T; N] {\n /// Returns the length of this array.\n ///\n /// ```noir\n /// fn len(self) -> Field\n /// ```\n ///\n /// example\n ///\n /// ```noir\n /// fn main() {\n /// let array = [42, 42];\n /// assert(array.len() == 2);\n /// }\n /// ```\n #[builtin(array_len)]\n pub fn len(self) -> u32 {}\n\n /// Returns this array as a vector.\n ///\n /// ```noir\n /// let array = [1, 2];\n /// let vector = array.as_vector();\n /// assert_eq(vector, [1, 2].as_vector());\n /// ```\n #[builtin(as_vector)]\n pub fn as_vector(self) -> [T] {}\n\n /// Returns this array as a vector.\n /// This method is deprecated in favor of `as_vector`.\n ///\n /// ```noir\n /// let array = [1, 2];\n /// let vector = array.as_slice();\n /// assert_eq(vector, [1, 2].as_vector());\n /// ```\n #[builtin(as_vector)]\n #[deprecated(\"This method has been renamed to `as_vector`\")]\n pub fn as_slice(self) -> [T] {}\n\n /// Applies a function to each element of this array, returning a new array containing the mapped elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let b = a.map(|a| a * 2);\n /// assert_eq(b, [2, 4, 6]);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> [U; N] {\n let uninitialized = crate::mem::zeroed();\n let mut ret = [uninitialized; N];\n\n for i in 0..self.len() {\n ret[i] = f(self[i]);\n }\n\n ret\n }\n\n /// Applies a function to each element of this array along with its index,\n /// returning a new array containing the mapped elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let b = a.mapi(|i, a| i + a * 2);\n /// assert_eq(b, [2, 5, 8]);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> [U; N] {\n let uninitialized = crate::mem::zeroed();\n let mut ret = [uninitialized; N];\n\n for i in 0..self.len() {\n ret[i] = f(i, self[i]);\n }\n\n ret\n }\n\n /// Applies a function to each element of this array.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let mut b = [0; 3];\n /// let mut i = 0;\n /// a.for_each(|x| {\n /// b[i] = x;\n /// i += 1;\n /// });\n /// assert_eq(a, b);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n for i in 0..self.len() {\n f(self[i]);\n }\n }\n\n /// Applies a function to each element of this array along with its index.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let mut b = [0; 3];\n /// a.for_eachi(|i, x| {\n /// b[i] = x;\n /// });\n /// assert_eq(a, b);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n for i in 0..self.len() {\n f(i, self[i]);\n }\n }\n\n /// Applies a function to each element of the array, returning the final accumulated value. The first\n /// parameter is the initial value.\n ///\n /// This is a left fold, so the given function will be applied to the accumulator and first element of\n /// the array, then the second, and so on. For a given call the expected result would be equivalent to:\n ///\n /// ```rust\n /// let a1 = [1];\n /// let a2 = [1, 2];\n /// let a3 = [1, 2, 3];\n ///\n /// let f = |a, b| a - b;\n /// a1.fold(10, f); //=> f(10, 1)\n /// a2.fold(10, f); //=> f(f(10, 1), 2)\n /// a3.fold(10, f); //=> f(f(f(10, 1), 2), 3)\n ///\n /// assert_eq(a3.fold(10, f), 10 - 1 - 2 - 3);\n /// ```\n pub fn fold(&self, mut accumulator: U, f: fn[Env](U, T) -> U) -> U {\n for elem in self {\n accumulator = f(accumulator, elem);\n }\n accumulator\n }\n\n /// Same as fold, but uses the first element as the starting element.\n ///\n /// Requires the input array to be non-empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [1, 2, 3, 4];\n /// let reduced = arr.reduce(|a, b| a + b);\n /// assert(reduced == 10);\n /// }\n /// ```\n pub fn reduce(&self, f: fn[Env](T, T) -> T) -> T {\n let mut accumulator = self[0];\n for i in 1..self.len() {\n accumulator = f(accumulator, self[i]);\n }\n accumulator\n }\n\n /// Returns true if all the elements in this array satisfy the given predicate.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [2, 2, 2, 2, 2];\n /// let all = arr.all(|a| a == 2);\n /// assert(all);\n /// }\n /// ```\n pub fn all(&self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = true;\n for elem in self {\n ret &= predicate(elem);\n }\n ret\n }\n\n /// Returns true if any of the elements in this array satisfy the given predicate.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [2, 2, 2, 2, 5];\n /// let any = arr.any(|a| a == 5);\n /// assert(any);\n /// }\n /// ```\n pub fn any(&self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n for elem in self {\n ret |= predicate(elem);\n }\n ret\n }\n\n /// Concatenates this array with another array.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr1 = [1, 2, 3, 4];\n /// let arr2 = [6, 7, 8, 9, 10, 11];\n /// let concatenated_arr = arr1.concat(arr2);\n /// assert(concatenated_arr == [1, 2, 3, 4, 6, 7, 8, 9, 10, 11]);\n /// }\n /// ```\n pub fn concat(&self, array2: [T; M]) -> [T; N + M] {\n let mut result = [crate::mem::zeroed(); N + M];\n for i in 0..N {\n result[i] = self[i];\n }\n for i in 0..M {\n result[i + N] = array2[i];\n }\n result\n }\n}\n\nimpl [T; N]\nwhere\n T: Ord + Eq,\n{\n /// Returns a new sorted array. The original array remains untouched. Notice that this function will\n /// only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting\n /// logic it uses internally is optimized specifically for these values. If you need a sort function to\n /// sort any type, you should use the [`Self::sort_via`] function.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let arr = [42, 32];\n /// let sorted = arr.sort();\n /// assert(sorted == [32, 42]);\n /// }\n /// ```\n pub fn sort(&self) -> Self {\n self.sort_via(|a, b| a <= b)\n }\n}\n\nimpl [T; N]\nwhere\n T: Eq,\n{\n /// Returns a new sorted array by sorting it with a custom comparison function.\n /// The original array remains untouched.\n /// The ordering function must return true if the first argument should be sorted to be before the second argument or is equal to the second argument.\n ///\n /// Using this method with an operator like `<` that does not return `true` for equal values will result in an assertion failure for arrays with equal elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let arr = [42, 32]\n /// let sorted_ascending = arr.sort_via(|a, b| a <= b);\n /// assert(sorted_ascending == [32, 42]); // verifies\n ///\n /// let sorted_descending = arr.sort_via(|a, b| a >= b);\n /// assert(sorted_descending == [32, 42]); // does not verify\n /// }\n /// ```\n pub fn sort_via(&self, ordering: fn[Env](T, T) -> bool) -> Self {\n // Safety: `sorted` array is checked to be:\n // a. a permutation of `input`'s elements\n // b. satisfying the predicate `ordering`\n let sorted = unsafe { quicksort::quicksort(self, ordering) };\n\n if !is_unconstrained() {\n for i in 0..N - 1 {\n assert(\n ordering(sorted[i], sorted[i + 1]),\n \"Array has not been sorted correctly according to `ordering`.\",\n );\n }\n check_shuffle::check_shuffle(self, &sorted);\n }\n sorted\n }\n}\n\nimpl [u8; N] {\n /// Converts a byte array of type `[u8; N]` to a string. Note that this performs no UTF-8 validation -\n /// the given array is interpreted as-is as a string.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let hi = [104, 105].as_str_unchecked();\n /// assert_eq(hi, \"hi\");\n /// }\n /// ```\n #[builtin(array_as_str_unchecked)]\n pub fn as_str_unchecked(self) -> str {}\n}\n\nimpl From> for [u8; N] {\n /// Returns an array of the string bytes.\n fn from(s: str) -> Self {\n s.as_bytes()\n }\n}\n\nmod test {\n #[test]\n fn map_empty() {\n assert_eq([].map(|x| x + 1), []);\n }\n\n global arr_with_100_values: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2, 54,\n 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41, 19, 98,\n 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21, 43, 86, 35,\n 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15, 127, 81, 30, 8,\n 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n global expected_with_100_values: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30, 32,\n 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58, 61, 62,\n 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82, 84, 84, 86,\n 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114, 114, 116, 118,\n 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n fn sort_u32(a: u32, b: u32) -> bool {\n a <= b\n }\n\n #[test]\n fn test_sort() {\n let arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = arr.sort();\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_100_values() {\n let arr: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2,\n 54, 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41,\n 19, 98, 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21,\n 43, 86, 35, 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15,\n 127, 81, 30, 8, 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n\n let sorted = arr.sort();\n\n let expected: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30,\n 32, 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58,\n 61, 62, 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82,\n 84, 84, 86, 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114,\n 114, 116, 118, 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_100_values_comptime() {\n let sorted = arr_with_100_values.sort();\n assert(sorted == expected_with_100_values);\n }\n\n #[test]\n fn test_sort_via() {\n let arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = arr.sort_via(sort_u32);\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_via_100_values() {\n let arr: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2,\n 54, 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41,\n 19, 98, 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21,\n 43, 86, 35, 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15,\n 127, 81, 30, 8, 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n\n let sorted = arr.sort_via(sort_u32);\n\n let expected: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30,\n 32, 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58,\n 61, 62, 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82,\n 84, 84, 86, 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114,\n 114, 116, 118, 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n assert(sorted == expected);\n }\n\n #[test]\n fn mapi_empty() {\n assert_eq([].mapi(|i, x| i * x + 1), []);\n }\n\n #[test]\n fn for_each_empty() {\n let empty_array: [Field; 0] = [];\n empty_array.for_each(|_x| assert(false));\n }\n\n #[test]\n fn for_eachi_empty() {\n let empty_array: [Field; 0] = [];\n empty_array.for_eachi(|_i, _x| assert(false));\n }\n\n #[test]\n fn map_example() {\n let a = [1, 2, 3];\n let b = a.map(|a| a * 2);\n assert_eq(b, [2, 4, 6]);\n }\n\n #[test]\n fn mapi_example() {\n let a = [1, 2, 3];\n let b = a.mapi(|i, a| i + a * 2);\n assert_eq(b, [2, 5, 8]);\n }\n\n #[test]\n fn for_each_example() {\n let a = [1, 2, 3];\n let mut b = [0, 0, 0];\n let b_ref = &mut b;\n let mut i = 0;\n let i_ref = &mut i;\n a.for_each(|x| {\n b_ref[*i_ref] = x * 2;\n *i_ref += 1;\n });\n assert_eq(b, [2, 4, 6]);\n assert_eq(i, 3);\n }\n\n #[test]\n fn for_eachi_example() {\n let a = [1, 2, 3];\n let mut b = [0, 0, 0];\n let b_ref = &mut b;\n a.for_eachi(|i, a| { b_ref[i] = i + a * 2; });\n assert_eq(b, [2, 5, 8]);\n }\n\n #[test]\n fn concat() {\n let arr1 = [1, 2, 3, 4];\n let arr2 = [6, 7, 8, 9, 10, 11];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1, 2, 3, 4, 6, 7, 8, 9, 10, 11]);\n }\n\n #[test]\n fn concat_zero_length_with_something() {\n let arr1 = [];\n let arr2 = [1];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1]);\n }\n\n #[test]\n fn concat_something_with_zero_length() {\n let arr1 = [1];\n let arr2 = [];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1]);\n }\n\n #[test]\n fn concat_zero_lengths() {\n let arr1: [Field; 0] = [];\n let arr2: [Field; 0] = [];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, []);\n }\n}\n","path":"std/array/mod.nr","function_locations":[{"start":480,"name":"[T; N]::len"},{"start":735,"name":"[T; N]::as_vector"},{"start":1112,"name":"[T; N]::as_slice"},{"start":1443,"name":"[T; N]::map"},{"start":2004,"name":"[T; N]::mapi"},{"start":2552,"name":"[T; N]::for_each"},{"start":2970,"name":"[T; N]::for_eachi"},{"start":3837,"name":"[T; N]::fold"},{"start":4355,"name":"[T; N]::reduce"},{"start":4865,"name":"[T; N]::all"},{"start":5338,"name":"[T; N]::any"},{"start":5881,"name":"[T; N]::concat"},{"start":6778,"name":"[T; N]::sort"},{"start":7794,"name":"[T; N]::sort_via"},{"start":8823,"name":"[u8; N]::as_str_unchecked"},{"start":8950,"name":"> for [u8; N]>::from"},{"start":9024,"name":"test::map_empty"},{"start":10134,"name":"test::sort_u32"},{"start":10189,"name":"test::test_sort"},{"start":10420,"name":"test::test_sort_100_values"},{"start":11588,"name":"test::test_sort_100_values_comptime"},{"start":11733,"name":"test::test_sort_via"},{"start":11980,"name":"test::test_sort_via_100_values"},{"start":13141,"name":"test::mapi_empty"},{"start":13236,"name":"test::for_each_empty"},{"start":13374,"name":"test::for_eachi_empty"},{"start":13513,"name":"test::map_example"},{"start":13650,"name":"test::mapi_example"},{"start":13799,"name":"test::for_each_example"},{"start":14139,"name":"test::for_eachi_example"},{"start":14350,"name":"test::concat"},{"start":14609,"name":"test::concat_zero_length_with_something"},{"start":14812,"name":"test::concat_something_with_zero_length"},{"start":15001,"name":"test::concat_zero_lengths"}]},"5":{"source":"use crate::meta::ctstring::AsCtString;\nuse crate::meta::derive_via;\n\n/// Compare two values for equality\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n if result {\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\ncomptime fn make_tuple_eq_body(n: u32) -> Quoted {\n let mut body = f\"self.0.eq(other.0)\".as_ctstring();\n for i in 1u32..n {\n body = body.append_fmtstr(f\" & self.{i}.eq(other.{i})\");\n }\n f\"{body}\".quoted_contents()\n}\n\nimpl Eq for (A, B) {\n fn eq(self, other: (A, B)) -> bool {\n make_tuple_eq_body!(2u32)\n }\n}\n\nimpl Eq for (A, B, C) {\n fn eq(self, other: (A, B, C)) -> bool {\n make_tuple_eq_body!(3u32)\n }\n}\n\nimpl Eq for (A, B, C, D) {\n fn eq(self, other: (A, B, C, D)) -> bool {\n make_tuple_eq_body!(4u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E) {\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n make_tuple_eq_body!(5u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F) {\n fn eq(self, other: (A, B, C, D, E, F)) -> bool {\n make_tuple_eq_body!(6u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G) {\n fn eq(self, other: (A, B, C, D, E, F, G)) -> bool {\n make_tuple_eq_body!(7u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H) {\n fn eq(self, other: (A, B, C, D, E, F, G, H)) -> bool {\n make_tuple_eq_body!(8u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I)) -> bool {\n make_tuple_eq_body!(9u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J)) -> bool {\n make_tuple_eq_body!(10u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J, K) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> bool {\n make_tuple_eq_body!(11u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> bool {\n make_tuple_eq_body!(12u32)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\n/// A value with three states: `Ordering::less()`, `Ordering::equal()` or `Ordering::greater()`.\n/// Most often used to encode the result of a comparison operation.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n/// Compare one object to another, returning whether it is less-than, equal-to,\n/// or greater-than the other object.\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let self_len = self.len();\n let other_len = other.len();\n let min_len = if self_len < other_len {\n self_len\n } else {\n other_len\n };\n\n let mut result = Ordering::equal();\n for i in 0..min_len {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n\n if result != Ordering::equal() {\n result\n } else {\n self_len.cmp(other_len)\n }\n }\n}\n\ncomptime fn make_tuple_ord_body(n: u32) -> Quoted {\n let last = n - 1u32;\n let mut body = if last == 1 {\n f\"let result = self.0.cmp(other.0);\".as_ctstring()\n } else {\n f\"let mut result = self.0.cmp(other.0);\".as_ctstring()\n };\n for i in 1u32..last {\n body = body.append_fmtstr(\n f\" if result == Ordering::equal() {{ result = self.{i}.cmp(other.{i}); }}\",\n );\n }\n body = body.append_fmtstr(\n f\" if result != Ordering::equal() {{ result }} else {{ self.{last}.cmp(other.{last}) }}\",\n );\n f\"{body}\".quoted_contents()\n}\n\nimpl Ord for (A, B) {\n fn cmp(self, other: (A, B)) -> Ordering {\n make_tuple_ord_body!(2u32)\n }\n}\n\nimpl Ord for (A, B, C) {\n fn cmp(self, other: (A, B, C)) -> Ordering {\n make_tuple_ord_body!(3u32)\n }\n}\n\nimpl Ord for (A, B, C, D) {\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n make_tuple_ord_body!(4u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E) {\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n make_tuple_ord_body!(5u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F) {\n fn cmp(self, other: (A, B, C, D, E, F)) -> Ordering {\n make_tuple_ord_body!(6u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G) {\n fn cmp(self, other: (A, B, C, D, E, F, G)) -> Ordering {\n make_tuple_ord_body!(7u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H)) -> Ordering {\n make_tuple_ord_body!(8u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I)) -> Ordering {\n make_tuple_ord_body!(9u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J)) -> Ordering {\n make_tuple_ord_body!(10u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J, K) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> Ordering {\n make_tuple_ord_body!(11u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> Ordering {\n make_tuple_ord_body!(12u32)\n }\n}\n\n/// Compares and returns the maximum of two values.\n///\n/// Returns the second argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::max(1, 2), 2);\n/// assert_eq(cmp::max(2, 2), 2);\n/// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n/// Compares and returns the minimum of two values.\n///\n/// Returns the first argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::min(1, 2), 1);\n/// assert_eq(cmp::min(2, 2), 2);\n/// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use super::{Eq, max, min, Ord};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n\n #[test]\n fn correctly_handles_unequal_length_vectors() {\n let vector_1 = [0, 1, 2, 3].as_vector();\n let vector_2 = [0, 1, 2].as_vector();\n assert(!vector_1.eq(vector_2));\n }\n\n #[test]\n fn lexicographic_ordering_for_vectors() {\n assert(\n [2_u32].as_vector().cmp([1_u32, 1_u32, 1_u32].as_vector())\n == super::Ordering::greater(),\n );\n assert(\n [1_u32, 2_u32].as_vector().cmp([1_u32, 2_u32, 3_u32].as_vector())\n == super::Ordering::less(),\n );\n }\n}\n","path":"std/cmp.nr","function_locations":[{"start":305,"name":"derive_eq"},{"start":851,"name":"::eq"},{"start":940,"name":"::eq"},{"start":1026,"name":"::eq"},{"start":1112,"name":"::eq"},{"start":1198,"name":"::eq"},{"start":1282,"name":"::eq"},{"start":1366,"name":"::eq"},{"start":1452,"name":"::eq"},{"start":1538,"name":"::eq"},{"start":1624,"name":"::eq"},{"start":1717,"name":"::eq"},{"start":1796,"name":"::eq"},{"start":1921,"name":"::eq"},{"start":2139,"name":"::eq"},{"start":2418,"name":">::eq"},{"start":2598,"name":"make_tuple_eq_body"},{"start":2859,"name":"::eq"},{"start":2991,"name":"::eq"},{"start":3136,"name":"::eq"},{"start":3294,"name":"::eq"},{"start":3465,"name":"::eq"},{"start":3649,"name":"::eq"},{"start":3846,"name":"::eq"},{"start":4056,"name":"::eq"},{"start":4279,"name":"::eq"},{"start":4516,"name":"::eq"},{"start":4766,"name":"::eq"},{"start":4876,"name":"::eq"},{"start":5477,"name":"Ordering::less"},{"start":5548,"name":"Ordering::equal"},{"start":5621,"name":"Ordering::greater"},{"start":5992,"name":"derive_ord"},{"start":6642,"name":"::cmp"},{"start":6889,"name":"::cmp"},{"start":7137,"name":"::cmp"},{"start":7385,"name":"::cmp"},{"start":7631,"name":"::cmp"},{"start":7877,"name":"::cmp"},{"start":8125,"name":"::cmp"},{"start":8373,"name":"::cmp"},{"start":8621,"name":"::cmp"},{"start":8875,"name":"::cmp"},{"start":8974,"name":"::cmp"},{"start":9444,"name":"::cmp"},{"start":9847,"name":"::cmp"},{"start":10415,"name":"make_tuple_ord_body"},{"start":11037,"name":"::cmp"},{"start":11179,"name":"::cmp"},{"start":11335,"name":"::cmp"},{"start":11505,"name":"::cmp"},{"start":11689,"name":"::cmp"},{"start":11887,"name":"::cmp"},{"start":12099,"name":"::cmp"},{"start":12325,"name":"::cmp"},{"start":12565,"name":"::cmp"},{"start":12820,"name":"::cmp"},{"start":13089,"name":"::cmp"},{"start":13451,"name":"max"},{"start":13828,"name":"min"},{"start":13982,"name":"cmp_tests::sanity_check_min"},{"start":14178,"name":"cmp_tests::sanity_check_max"},{"start":14400,"name":"cmp_tests::correctly_handles_unequal_length_vectors"},{"start":14600,"name":"cmp_tests::lexicographic_ordering_for_vectors"}]},"6":{"source":"use crate::{cmp::Eq, convert::From, runtime::is_unconstrained, static_assert};\n\n/// A `BoundedVec` is a growable storage similar to a built-in vector except that it\n/// is bounded with a maximum possible length. `BoundedVec` is also not\n/// subject to the same restrictions vectors are (notably, nested vectors are disallowed).\n///\n/// Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by\n/// pushing an additional element is also more efficient - the length only needs to be increased\n/// by one.\n///\n/// For these reasons `BoundedVec` should generally be preferred over vectors when there\n/// is a reasonable maximum bound that can be placed on the vector.\n///\n/// Example:\n///\n/// ```noir\n/// let mut vector: BoundedVec = BoundedVec::new();\n/// for i in 0..5 {\n/// vector.push(i);\n/// }\n/// assert(vector.len() == 5);\n/// assert(vector.max_len() == 10);\n/// ```\npub struct BoundedVec {\n storage: [T; MaxLen],\n len: u32,\n}\n\nimpl BoundedVec {\n /// Creates a new, empty vector of length zero.\n ///\n /// Since this container is backed by an array internally, it still needs an initial value\n /// to give each element. To resolve this, each element is zeroed internally. This value\n /// is guaranteed to be inaccessible unless `get_unchecked` is used.\n ///\n /// Example:\n ///\n /// ```noir\n /// let empty_vector: BoundedVec = BoundedVec::new();\n /// assert(empty_vector.len() == 0);\n /// ```\n ///\n /// Note that whenever calling `new` the maximum length of the vector should always be specified\n /// via a type signature:\n ///\n /// ```noir\n /// fn good() -> BoundedVec {\n /// // Ok! MaxLen is specified with a type annotation\n /// let v1: BoundedVec = BoundedVec::new();\n /// let v2 = BoundedVec::new();\n ///\n /// // Ok! MaxLen is known from the type of `good`'s return value\n /// v2\n /// }\n ///\n /// fn bad() {\n /// // Error: Type annotation needed\n /// // The compiler can't infer `MaxLen` from the following code:\n /// let mut v3 = BoundedVec::new();\n /// v3.push(5);\n /// }\n /// ```\n ///\n /// This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions\n /// but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a\n /// constraint failure at runtime when the vec is pushed to.\n pub fn new() -> Self {\n let zeroed = crate::mem::zeroed();\n BoundedVec { storage: [zeroed; MaxLen], len: 0 }\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this\n /// will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// let last = v.get(v.len() - 1);\n /// assert(first != last);\n /// }\n /// ```\n pub fn get(&self, index: u32) -> T {\n assert(index < self.len, \"Attempted to read past end of BoundedVec\");\n self.get_unchecked(index)\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero, without\n /// performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element,\n /// it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn sum_of_first_three(v: BoundedVec) -> u32 {\n /// // Always ensure the length is larger than the largest\n /// // index passed to get_unchecked\n /// assert(v.len() > 2);\n /// let first = v.get_unchecked(0);\n /// let second = v.get_unchecked(1);\n /// let third = v.get_unchecked(2);\n /// first + second + third\n /// }\n /// ```\n pub fn get_unchecked(&self, index: u32) -> T {\n self.storage[index]\n }\n\n /// Writes an element to the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// assert(first != 42);\n /// v.set(0, 42);\n /// let new_first = v.get(0);\n /// assert(new_first == 42);\n /// }\n /// ```\n pub fn set(&mut self, index: u32, value: T) {\n assert(index < self.len, \"Attempted to write past end of BoundedVec\");\n self.set_unchecked(index, value)\n }\n\n /// Writes an element to the vector at the given index, starting from zero, without performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element, it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn set_unchecked_example() {\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([1, 2]);\n ///\n /// // Here we're safely writing within the valid range of `vec`\n /// // `vec` now has the value [42, 2]\n /// vec.set_unchecked(0, 42);\n ///\n /// // We can then safely read this value back out of `vec`.\n /// // Notice that we use the checked version of `get` which would prevent reading unsafe values.\n /// assert_eq(vec.get(0), 42);\n ///\n /// // We've now written past the end of `vec`.\n /// // As this index is still within the maximum potential length of `v`,\n /// // it won't cause a constraint failure.\n /// vec.set_unchecked(2, 42);\n /// println(vec);\n ///\n /// // This will write past the end of the maximum potential length of `vec`,\n /// // it will then trigger a constraint failure.\n /// vec.set_unchecked(5, 42);\n /// println(vec);\n /// }\n /// ```\n pub fn set_unchecked(&mut self, index: u32, value: T) {\n self.storage[index] = value;\n }\n\n /// Pushes an element to the end of the vector. This increases the length\n /// of the vector by one.\n ///\n /// Panics if the new length of the vector will be greater than the max length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// v.push(1);\n /// v.push(2);\n ///\n /// // Panics with failed assertion \"push out of bounds\"\n /// v.push(3);\n /// ```\n pub fn push(&mut self, elem: T) {\n assert(self.len < MaxLen, \"push out of bounds\");\n\n self.storage[self.len] = elem;\n self.len += 1;\n }\n\n /// Returns the current length of this vector\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// assert(v.len() == 0);\n ///\n /// v.push(100);\n /// assert(v.len() == 1);\n ///\n /// v.push(200);\n /// v.push(300);\n /// v.push(400);\n /// assert(v.len() == 4);\n ///\n /// let _ = v.pop();\n /// let _ = v.pop();\n /// assert(v.len() == 2);\n /// ```\n pub fn len(&self) -> u32 {\n self.len\n }\n\n /// Returns the maximum length of this vector. This is always\n /// equal to the `MaxLen` parameter this vector was initialized with.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.max_len() == 5);\n /// v.push(10);\n /// assert(v.max_len() == 5);\n /// ```\n pub fn max_len(_self: &BoundedVec) -> u32 {\n MaxLen\n }\n\n /// Returns the internal array within this vector.\n ///\n /// Since arrays in Noir are immutable, mutating the returned storage array will not mutate\n /// the storage held internally by this vector.\n ///\n /// Note that uninitialized elements may be zeroed out!\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.storage() == [0, 0, 0, 0, 0]);\n ///\n /// v.push(57);\n /// assert(v.storage() == [57, 0, 0, 0, 0]);\n /// ```\n pub fn storage(self) -> [T; MaxLen] {\n self.storage\n }\n\n /// Pushes each element from the given array to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([2, 4]);\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_array(&mut self, array: [T; Len]) {\n let new_len = self.len + array.len();\n assert(new_len <= MaxLen, \"extend_from_array out of bounds\");\n for i in 0..array.len() {\n self.storage[self.len + i] = array[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the given vector to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_vector([2, 4].as_vector());\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_vector(&mut self, vector: [T]) {\n let new_len = self.len + vector.len();\n assert(new_len <= MaxLen, \"extend_from_vector out of bounds\");\n for i in 0..vector.len() {\n self.storage[self.len + i] = vector[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the other vector to this vector. The length of\n /// the other vector is left unchanged.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// ```noir\n /// let mut v1: BoundedVec = BoundedVec::new();\n /// let mut v2: BoundedVec = BoundedVec::new();\n ///\n /// v2.extend_from_array([1, 2, 3]);\n /// v1.extend_from_bounded_vec(v2);\n ///\n /// assert(v1.storage() == [1, 2, 3, 0, 0]);\n /// assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]);\n /// ```\n pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) {\n let append_len = vec.len();\n let new_len = self.len + append_len;\n assert(new_len <= MaxLen, \"extend_from_bounded_vec out of bounds\");\n\n if is_unconstrained() {\n for i in 0..append_len {\n self.storage[self.len + i] = vec.get_unchecked(i);\n }\n } else {\n // The source vector can be longer than the destination, or vice versa;\n // regardless we will only ever be able to read or write whichever is\n // the shorter max length of the two. We asserted that the actual content fits,\n // but the capacity of the source vector could be higher.\n let max = crate::cmp::min(Len, MaxLen);\n\n // Save the last item in case we have to do a fixup on an already full array.\n let last = if MaxLen > 0 {\n self.storage[MaxLen - 1]\n } else {\n crate::mem::zeroed()\n };\n\n for src in 0..max {\n // Since we are iterating to the static capacity of the arrays,\n // the destination could be out of bounds. If that's the case,\n // overwrite the last item, which we'll fixup in the end.\n // NB using cmp::min resulted in more opcodes here.\n let mut dst = self.len + src;\n if dst >= MaxLen { dst = MaxLen - 1; };\n // Assigning the source or zeroed to avoid having to merge arrays in SSA.\n self.storage[dst] = if src < append_len {\n vec.get_unchecked(src)\n } else {\n last\n }\n }\n\n // Fixup the last item if we have to.\n if MaxLen > 0 {\n self.storage[MaxLen - 1] = if (self.len + append_len == MaxLen) & (append_len > 0) {\n vec.get_unchecked(append_len - 1)\n } else {\n last\n }\n }\n }\n self.len = new_len;\n }\n\n /// Creates a new vector, populating it with values derived from an array input.\n /// The maximum length of the vector is determined based on the type signature.\n ///\n /// Example:\n ///\n /// ```noir\n /// let bounded_vec: BoundedVec = BoundedVec::from_array([1, 2, 3])\n /// ```\n pub fn from_array(array: [T; Len]) -> Self {\n static_assert(Len <= MaxLen, \"from array out of bounds\");\n let mut vec: BoundedVec = BoundedVec::new();\n vec.extend_from_array(array);\n vec\n }\n\n /// Pops the element at the end of the vector. This will decrease the length\n /// of the vector by one.\n ///\n /// Panics if the vector is empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.push(1);\n /// v.push(2);\n ///\n /// let two = v.pop();\n /// let one = v.pop();\n ///\n /// assert(two == 2);\n /// assert(one == 1);\n ///\n /// // error: cannot pop from an empty vector\n /// let _ = v.pop();\n /// ```\n pub fn pop(&mut self) -> T {\n assert(self.len > 0, \"cannot pop from an empty vector\");\n self.len -= 1;\n\n let elem = self.storage[self.len];\n self.storage[self.len] = crate::mem::zeroed();\n elem\n }\n\n /// Returns true if the given predicate returns true for any element\n /// in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.extend_from_array([2, 4, 6]);\n ///\n /// let all_even = !v.any(|elem: u32| elem % 2 != 0);\n /// assert(all_even);\n /// ```\n pub fn any(self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n if is_unconstrained() {\n for i in 0..self.len {\n ret |= predicate(self.storage[i]);\n }\n } else {\n let mut exceeded_len = false;\n for i in 0..MaxLen {\n exceeded_len |= i == self.len;\n if !exceeded_len {\n ret |= predicate(self.storage[i]);\n }\n }\n }\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.map(|value| value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element\n /// in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.mapi(|i, value| i + value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(i, self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Calls a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_each(|value| result.push(value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Calls a closure on each element in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_eachi(|i, value| result.push(i + value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(i, self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function will zero out any elements at or past index `len` of `array`.\n /// This incurs an extra runtime cost of O(MaxLen). If you are sure your array is\n /// zeroed after that index, you can use [`from_parts_unchecked`][Self::from_parts_unchecked] to remove the extra loop.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n /// ```\n pub fn from_parts(mut array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n let zeroed = crate::mem::zeroed();\n\n if is_unconstrained() {\n for i in len..MaxLen {\n array[i] = zeroed;\n }\n } else {\n for i in 0..MaxLen {\n if i >= len {\n array[i] = zeroed;\n }\n }\n }\n\n BoundedVec { storage: array, len }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function is unsafe because it expects all elements past the `len` index\n /// of `array` to be zeroed, but does not check for this internally. Use `from_parts`\n /// for a safe version of this function which does zero out any indices past the\n /// given length. Invalidating this assumption can notably cause `BoundedVec::eq`\n /// to give incorrect results since it will check even elements past `len`.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n ///\n /// // invalid use!\n /// let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n /// let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n ///\n /// // both vecs have length 3 so we'd expect them to be equal, but this\n /// // fails because elements past the length are still checked in eq\n /// assert_eq(vec1, vec2); // fails\n /// ```\n pub fn from_parts_unchecked(array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n BoundedVec { storage: array, len }\n }\n}\n\nimpl Eq for BoundedVec\nwhere\n T: Eq,\n{\n fn eq(self, other: BoundedVec) -> bool {\n // TODO: https://github.com/noir-lang/noir/issues/4837\n //\n // We make the assumption that the user has used the proper interface for working with `BoundedVec`s\n // rather than directly manipulating the internal fields as this can result in an inconsistent internal state.\n if self.len == other.len {\n self.storage == other.storage\n } else {\n false\n }\n }\n}\n\nimpl From<[T; Len]> for BoundedVec {\n fn from(array: [T; Len]) -> BoundedVec {\n BoundedVec::from_array(array)\n }\n}\n\nmod bounded_vec_tests {\n\n mod get {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_elements_past_end_of_vec() {\n let vec: BoundedVec = BoundedVec::new();\n\n let _ = vec.get(0);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_beyond_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let _ = vec.get(3);\n }\n\n #[test]\n fn get_works_within_bounds() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(2), 3);\n assert_eq(vec.get(4), 5);\n }\n\n #[test]\n fn get_unchecked_works() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(0), 1);\n assert_eq(vec.get_unchecked(2), 3);\n }\n\n #[test]\n fn get_unchecked_works_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(4), 0);\n }\n }\n\n mod set {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn set_updates_values_properly() {\n let mut vec = BoundedVec::from_array([0, 0, 0, 0, 0]);\n\n vec.set(0, 42);\n assert_eq(vec.storage, [42, 0, 0, 0, 0]);\n\n vec.set(1, 43);\n assert_eq(vec.storage, [42, 43, 0, 0, 0]);\n\n vec.set(2, 44);\n assert_eq(vec.storage, [42, 43, 44, 0, 0]);\n\n vec.set(1, 10);\n assert_eq(vec.storage, [42, 10, 44, 0, 0]);\n\n vec.set(0, 0);\n assert_eq(vec.storage, [0, 10, 44, 0, 0]);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_writing_elements_past_end_of_vec() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.set(0, 42);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_setting_beyond_length() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.set(3, 4);\n }\n\n #[test]\n fn set_unchecked_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(0, 10);\n assert_eq(vec.get(0), 10);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn set_unchecked_operations_past_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(3, 40);\n assert_eq(vec.get(3), 40);\n }\n\n #[test]\n fn set_preserves_other_elements() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n vec.set(2, 30);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 30);\n assert_eq(vec.get(3), 4);\n assert_eq(vec.get(4), 5);\n }\n }\n\n mod any {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn returns_false_if_predicate_not_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, false, false]);\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn returns_true_if_predicate_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, true, true]);\n let result = vec.any(|value| value);\n\n assert(result);\n }\n\n #[test]\n fn returns_false_on_empty_boundedvec() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn any_with_complex_predicates() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n assert(vec.any(|x| x > 3));\n assert(!vec.any(|x| x > 10));\n assert(vec.any(|x| x % 2 == 0)); // has a even number\n assert(vec.any(|x| x == 3)); // has a specific value\n }\n\n #[test]\n fn any_with_partial_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n assert(vec.any(|x| x == 1));\n assert(vec.any(|x| x == 2));\n assert(!vec.any(|x| x == 3));\n }\n }\n\n mod map {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-map-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| value * 2);\n // docs:end:bounded-vec-map-example\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.map(|value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn map_with_conditional_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.map(|x| if x % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([1, 4, 3, 8]);\n assert_eq(result, expected);\n }\n\n #[test]\n fn map_preserves_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|x| x * 2);\n\n assert_eq(result.len(), vec.len());\n assert_eq(result.max_len(), vec.max_len());\n }\n\n #[test]\n fn map_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.map(|x| x * 2);\n assert_eq(result, vec);\n assert_eq(result.len(), 0);\n assert_eq(result.max_len(), 5);\n }\n }\n\n mod mapi {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-mapi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| i + value * 2);\n // docs:end:bounded-vec-mapi-example\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.mapi(|_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn mapi_with_index_branching_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.mapi(|i, x| if i % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([2, 2, 6, 4]);\n assert_eq(result, expected);\n }\n }\n\n mod for_each {\n use crate::collections::bounded_vec::BoundedVec;\n\n // map in terms of for_each\n fn for_each_map(\n input: BoundedVec,\n f: fn[Env](T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_each(|x| output_ref.push(f(x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-each-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_each(|value| { *acc_ref += value; });\n // docs:end:bounded-vec-for-each-example\n assert_eq(acc, 6);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| value * 2);\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_each_map(vec, |value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_each_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_each(|_| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_each_with_side_effects() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let mut seen = BoundedVec::::new();\n let seen_ref = &mut seen;\n vec.for_each(|x| seen_ref.push(x));\n assert_eq(seen, vec);\n }\n }\n\n mod for_eachi {\n use crate::collections::bounded_vec::BoundedVec;\n\n // mapi in terms of for_eachi\n fn for_eachi_mapi(\n input: BoundedVec,\n f: fn[Env](u32, T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_eachi(|i, x| output_ref.push(f(i, x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-eachi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_eachi(|i, value| { *acc_ref += i * value; });\n // docs:end:bounded-vec-for-eachi-example\n\n // 0 * 1 + 1 * 2 + 2 * 3\n assert_eq(acc, 8);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| i + value * 2);\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_eachi_mapi(vec, |_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_eachi_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_eachi(|_, _| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_eachi_with_index_tracking() {\n let vec: BoundedVec = BoundedVec::from_array([10, 20, 30]);\n let mut indices = BoundedVec::::new();\n let indices_ref = &mut indices;\n vec.for_eachi(|i, _| indices_ref.push(i));\n\n let expected = BoundedVec::from_array([0, 1, 2]);\n assert_eq(indices, expected);\n }\n\n }\n\n mod from_array {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty() {\n let empty_array: [Field; 0] = [];\n let bounded_vec = BoundedVec::from_array([]);\n\n assert_eq(bounded_vec.max_len(), 0);\n assert_eq(bounded_vec.len(), 0);\n assert_eq(bounded_vec.storage(), empty_array);\n }\n\n #[test]\n fn equal_len() {\n let array = [1, 2, 3];\n let bounded_vec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 3);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.storage(), array);\n }\n\n #[test]\n fn max_len_greater_then_array_len() {\n let array = [1, 2, 3];\n let bounded_vec: BoundedVec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n assert_eq(bounded_vec.get(2), 3);\n }\n\n #[test(should_fail_with = \"from array out of bounds\")]\n fn max_len_lower_then_array_len() {\n let _: BoundedVec = BoundedVec::from_array([0; 3]);\n }\n\n #[test]\n fn from_array_preserves_order() {\n let array = [5, 3, 1, 4, 2];\n let vec: BoundedVec = BoundedVec::from_array(array);\n for i in 0..array.len() {\n assert_eq(vec.get(i), array[i]);\n }\n }\n\n #[test]\n fn from_array_with_different_types() {\n let bool_array = [true, false, true];\n let bool_vec: BoundedVec = BoundedVec::from_array(bool_array);\n assert_eq(bool_vec.len(), 3);\n assert_eq(bool_vec.get(0), true);\n assert_eq(bool_vec.get(1), false);\n }\n }\n\n mod trait_from {\n use crate::collections::bounded_vec::BoundedVec;\n use crate::convert::From;\n\n #[test]\n fn simple() {\n let array = [1, 2];\n let bounded_vec: BoundedVec = BoundedVec::from(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 2);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n }\n }\n\n mod trait_eq {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty_equality() {\n let bounded_vec1: BoundedVec = BoundedVec::new();\n let bounded_vec2: BoundedVec = BoundedVec::new();\n\n assert_eq(bounded_vec1, bounded_vec2);\n }\n\n #[test]\n fn inequality() {\n let mut bounded_vec1: BoundedVec = BoundedVec::new();\n let mut bounded_vec2: BoundedVec = BoundedVec::new();\n bounded_vec1.push(1);\n bounded_vec2.push(2);\n\n assert(bounded_vec1 != bounded_vec2);\n }\n }\n\n mod from_parts {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn from_parts() {\n // docs:start:from-parts\n let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // Any elements past the given length are zeroed out, so these\n // two BoundedVecs will be completely equal\n let vec1: BoundedVec = BoundedVec::from_parts([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts([1, 2, 3, 2], 3);\n assert_eq(vec1, vec2);\n // docs:end:from-parts\n }\n\n #[test]\n fn from_parts_unchecked() {\n // docs:start:from-parts-unchecked\n let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // invalid use!\n let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n\n // both vecs have length 3 so we'd expect them to be equal, but this\n // fails because elements past the length are still checked in eq\n assert(vec1 != vec2);\n // docs:end:from-parts-unchecked\n }\n }\n\n mod push_pop {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn push_and_pop_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n assert_eq(vec.len(), 0);\n\n vec.push(1);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 1);\n\n vec.push(2);\n assert_eq(vec.len(), 2);\n assert_eq(vec.get(1), 2);\n\n let popped = vec.pop();\n assert_eq(popped, 2);\n assert_eq(vec.len(), 1);\n\n let popped2 = vec.pop();\n assert_eq(popped2, 1);\n assert_eq(vec.len(), 0);\n }\n\n #[test(should_fail_with = \"push out of bounds\")]\n fn push_to_full_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n vec.push(3); // should panic\n }\n\n #[test(should_fail_with = \"cannot pop from an empty vector\")]\n fn pop_from_empty_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n let _ = vec.pop(); // should panic\n }\n\n #[test]\n fn push_pop_cycle() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // push to full\n vec.push(1);\n vec.push(2);\n vec.push(3);\n assert_eq(vec.len(), 3);\n\n // pop all\n assert_eq(vec.pop(), 3);\n assert_eq(vec.pop(), 2);\n assert_eq(vec.pop(), 1);\n assert_eq(vec.len(), 0);\n\n // push again\n vec.push(4);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 4);\n }\n }\n\n mod extend {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn extend_from_array() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3]);\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3].as_vector());\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec() {\n // The source deliberately has a higher capacity,\n // to make sure we are not trying to assign out-of-bounds.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_limit() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_full_and_empty() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_zero_len() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_last_zeroed() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get_unchecked(3), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_empty_self() {\n // self.len == 0 with Len > MaxLen: the loop doesn't reach\n // the last storage slot, so the fixup must write it.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_equal_capacity() {\n // Len == MaxLen, fills to capacity.\n let mut vec1: BoundedVec = BoundedVec::new();\n vec1.push(1);\n let vec2: BoundedVec = BoundedVec::from_array([2, 3, 4]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 4);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n assert_eq(vec1.get(3), 4);\n }\n\n #[test(should_fail_with = \"extend_from_array out of bounds\")]\n fn extend_array_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3, 4]); // should panic\n }\n\n #[test(should_fail_with = \"extend_from_vector out of bounds\")]\n fn extend_vector_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3, 4].as_vector()); // S]should panic\n }\n\n #[test(should_fail_with = \"extend_from_bounded_vec out of bounds\")]\n fn extend_bounded_vec_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n let other: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n vec.extend_from_bounded_vec(other); // should panic\n }\n\n #[test]\n fn extend_with_empty_collections() {\n let mut vec: BoundedVec = BoundedVec::new();\n let original_len = vec.len();\n\n vec.extend_from_array([]);\n assert_eq(vec.len(), original_len);\n\n vec.extend_from_vector([].as_vector());\n assert_eq(vec.len(), original_len);\n\n let empty: BoundedVec = BoundedVec::new();\n vec.extend_from_bounded_vec(empty);\n assert_eq(vec.len(), original_len);\n }\n }\n\n mod storage {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn storage_consistency() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // test initial storage state\n assert_eq(vec.storage(), [0, 0, 0, 0, 0]);\n\n vec.push(1);\n vec.push(2);\n\n // test storage after modifications\n assert_eq(vec.storage(), [1, 2, 0, 0, 0]);\n\n // storage doesn't change length\n assert_eq(vec.len(), 2);\n assert_eq(vec.max_len(), 5);\n }\n\n #[test]\n fn storage_after_pop() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n let _ = vec.pop();\n // after pop, the last element should be zeroed\n assert_eq(vec.storage(), [1, 2, 0]);\n assert_eq(vec.len(), 2);\n }\n\n #[test]\n fn vector_immutable() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let storage = vec.storage();\n\n assert_eq(storage, [1, 2, 3]);\n\n // Verify that the original vector is unchanged\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n }\n}\n","path":"std/collections/bounded_vec.nr","function_locations":[{"start":2599,"name":"BoundedVec::new"},{"start":3202,"name":"BoundedVec::get"},{"start":4110,"name":"BoundedVec::get_unchecked"},{"start":4693,"name":"BoundedVec::set"},{"start":6221,"name":"BoundedVec::set_unchecked"},{"start":6759,"name":"BoundedVec::push"},{"start":7367,"name":"BoundedVec::len"},{"start":7808,"name":"BoundedVec::max_len"},{"start":8406,"name":"BoundedVec::storage"},{"start":8962,"name":"BoundedVec::extend_from_array"},{"start":9733,"name":"BoundedVec::extend_from_vector"},{"start":10678,"name":"BoundedVec::extend_from_bounded_vec"},{"start":13073,"name":"BoundedVec::from_array"},{"start":13816,"name":"BoundedVec::pop"},{"start":14439,"name":"BoundedVec::any"},{"start":15355,"name":"BoundedVec::map"},{"start":16355,"name":"BoundedVec::mapi"},{"start":17313,"name":"BoundedVec::for_each"},{"start":18118,"name":"BoundedVec::for_eachi"},{"start":19117,"name":"BoundedVec::from_parts"},{"start":20766,"name":"BoundedVec::from_parts_unchecked"},{"start":20978,"name":">::eq"},{"start":21549,"name":" for BoundedVec>::from"},{"start":21832,"name":"bounded_vec_tests::get::panics_when_reading_elements_past_end_of_vec"},{"start":22067,"name":"bounded_vec_tests::get::panics_when_reading_beyond_length"},{"start":22242,"name":"bounded_vec_tests::get::get_works_within_bounds"},{"start":22501,"name":"bounded_vec_tests::get::get_unchecked_works"},{"start":22745,"name":"bounded_vec_tests::get::get_unchecked_works_past_len"},{"start":23018,"name":"bounded_vec_tests::set::set_updates_values_properly"},{"start":23656,"name":"bounded_vec_tests::set::panics_when_writing_elements_past_end_of_vec"},{"start":23891,"name":"bounded_vec_tests::set::panics_when_setting_beyond_length"},{"start":24066,"name":"bounded_vec_tests::set::set_unchecked_operations"},{"start":24398,"name":"bounded_vec_tests::set::set_unchecked_operations_past_len"},{"start":24662,"name":"bounded_vec_tests::set::set_preserves_other_elements"},{"start":25130,"name":"bounded_vec_tests::any::returns_false_if_predicate_not_satisfied"},{"start":25384,"name":"bounded_vec_tests::any::returns_true_if_predicate_satisfied"},{"start":25633,"name":"bounded_vec_tests::any::returns_false_on_empty_boundedvec"},{"start":25844,"name":"bounded_vec_tests::any::any_with_complex_predicates"},{"start":26207,"name":"bounded_vec_tests::any::any_with_partial_vector"},{"start":26594,"name":"bounded_vec_tests::map::applies_function_correctly"},{"start":27016,"name":"bounded_vec_tests::map::applies_function_that_changes_return_type"},{"start":27364,"name":"bounded_vec_tests::map::does_not_apply_function_past_len"},{"start":27737,"name":"bounded_vec_tests::map::map_with_conditional_logic"},{"start":28061,"name":"bounded_vec_tests::map::map_preserves_length"},{"start":28353,"name":"bounded_vec_tests::map::map_on_empty_vector"},{"start":28727,"name":"bounded_vec_tests::mapi::applies_function_correctly"},{"start":29160,"name":"bounded_vec_tests::mapi::applies_function_that_changes_return_type"},{"start":29517,"name":"bounded_vec_tests::mapi::does_not_apply_function_past_len"},{"start":29899,"name":"bounded_vec_tests::mapi::mapi_with_index_branching_logic"},{"start":30458,"name":"bounded_vec_tests::for_each::for_each_map"},{"start":30688,"name":"bounded_vec_tests::for_each::smoke_test"},{"start":31096,"name":"bounded_vec_tests::for_each::applies_function_correctly"},{"start":31430,"name":"bounded_vec_tests::for_each::applies_function_that_changes_return_type"},{"start":31788,"name":"bounded_vec_tests::for_each::does_not_apply_function_past_len"},{"start":32169,"name":"bounded_vec_tests::for_each::for_each_on_empty_vector"},{"start":32455,"name":"bounded_vec_tests::for_each::for_each_with_side_effects"},{"start":33012,"name":"bounded_vec_tests::for_eachi::for_eachi_mapi"},{"start":33249,"name":"bounded_vec_tests::for_eachi::smoke_test"},{"start":33705,"name":"bounded_vec_tests::for_eachi::applies_function_correctly"},{"start":34049,"name":"bounded_vec_tests::for_eachi::applies_function_that_changes_return_type"},{"start":34417,"name":"bounded_vec_tests::for_eachi::does_not_apply_function_past_len"},{"start":34804,"name":"bounded_vec_tests::for_eachi::for_eachi_on_empty_vector"},{"start":35097,"name":"bounded_vec_tests::for_eachi::for_eachi_with_index_tracking"},{"start":35574,"name":"bounded_vec_tests::from_array::empty"},{"start":35884,"name":"bounded_vec_tests::from_array::equal_len"},{"start":36201,"name":"bounded_vec_tests::from_array::max_len_greater_then_array_len"},{"start":36672,"name":"bounded_vec_tests::from_array::max_len_lower_then_array_len"},{"start":36815,"name":"bounded_vec_tests::from_array::from_array_preserves_order"},{"start":37104,"name":"bounded_vec_tests::from_array::from_array_with_different_types"},{"start":37541,"name":"bounded_vec_tests::trait_from::simple"},{"start":37979,"name":"bounded_vec_tests::trait_eq::empty_equality"},{"start":38228,"name":"bounded_vec_tests::trait_eq::inequality"},{"start":38637,"name":"bounded_vec_tests::from_parts::from_parts"},{"start":39227,"name":"bounded_vec_tests::from_parts::from_parts_unchecked"},{"start":40009,"name":"bounded_vec_tests::push_pop::push_and_pop_operations"},{"start":40635,"name":"bounded_vec_tests::push_pop::push_to_full_vector"},{"start":40909,"name":"bounded_vec_tests::push_pop::pop_from_empty_vector"},{"start":41078,"name":"bounded_vec_tests::push_pop::push_pop_cycle"},{"start":41724,"name":"bounded_vec_tests::extend::extend_from_array"},{"start":42070,"name":"bounded_vec_tests::extend::extend_from_vector"},{"start":42434,"name":"bounded_vec_tests::extend::extend_from_bounded_vec"},{"start":43055,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_limit"},{"start":43569,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_full_and_empty"},{"start":44073,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_zero_len"},{"start":44367,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_last_zeroed"},{"start":44792,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_empty_self"},{"start":45359,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_equal_capacity"},{"start":45946,"name":"bounded_vec_tests::extend::extend_array_beyond_max_len"},{"start":46224,"name":"bounded_vec_tests::extend::extend_vector_beyond_max_len"},{"start":46527,"name":"bounded_vec_tests::extend::extend_bounded_vec_beyond_max_len"},{"start":46813,"name":"bounded_vec_tests::extend::extend_with_empty_collections"},{"start":47413,"name":"bounded_vec_tests::storage::storage_consistency"},{"start":47915,"name":"bounded_vec_tests::storage::storage_after_pop"},{"start":48233,"name":"bounded_vec_tests::storage::vector_immutable"}]},"16":{"source":"use crate::field::field_less_than;\nuse crate::runtime::is_unconstrained;\n\n// The low and high decomposition of the field modulus\npub(crate) global PLO: Field = 53438638232309528389504892708671455233;\npub(crate) global PHI: Field = 64323764613183177041862057485226039389;\n\npub(crate) global TWO_POW_128: Field = 0x100000000000000000000000000000000;\n\n// Decomposes a single field into two 16 byte fields.\nfn compute_decomposition(x: Field) -> (Field, Field) {\n // Here's we're taking advantage of truncating 128 bit limbs from the input field\n // and then subtracting them from the input such the field division is equivalent to integer division.\n let low = (x as u128) as Field;\n let high = (x - low) / TWO_POW_128;\n\n (low, high)\n}\n\npub(crate) unconstrained fn decompose_hint(x: Field) -> (Field, Field) {\n compute_decomposition(x)\n}\n\nunconstrained fn lte_hint(x: Field, y: Field) -> bool {\n if x == y {\n true\n } else {\n field_less_than(x, y)\n }\n}\n\n// Assert that (alo > blo && ahi >= bhi) || (alo <= blo && ahi > bhi)\nfn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) {\n let (alo, ahi) = a;\n let (blo, bhi) = b;\n // Safety: borrow is enforced to be boolean due to its type.\n // if borrow is 0, it asserts that (alo > blo && ahi >= bhi)\n // if borrow is 1, it asserts that (alo <= blo && ahi > bhi)\n unsafe {\n let borrow = lte_hint(alo, blo);\n\n let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128;\n let rhi = ahi - bhi - (borrow as Field);\n\n rlo.assert_max_bit_size::<128>();\n rhi.assert_max_bit_size::<128>();\n }\n}\n\n/// Decompose a single field into two 16 byte fields.\npub fn decompose(x: Field) -> (Field, Field) {\n if is_unconstrained() {\n compute_decomposition(x)\n } else {\n // Safety: decomposition is properly checked below\n unsafe {\n // Take hints of the decomposition\n let (xlo, xhi) = decompose_hint(x);\n\n // Range check the limbs\n xlo.assert_max_bit_size::<128>();\n xhi.assert_max_bit_size::<128>();\n\n // Check that the decomposition is correct\n assert_eq(x, xlo + TWO_POW_128 * xhi);\n\n // Assert that the decomposition of P is greater than the decomposition of x\n assert_gt_limbs((PLO, PHI), (xlo, xhi));\n (xlo, xhi)\n }\n }\n}\n\npub fn assert_gt(a: Field, b: Field) {\n if is_unconstrained() {\n assert(\n // Safety: already unconstrained\n unsafe { field_less_than(b, a) },\n );\n } else {\n // Decompose a and b\n let a_limbs = decompose(a);\n let b_limbs = decompose(b);\n\n // Assert that a_limbs is greater than b_limbs\n assert_gt_limbs(a_limbs, b_limbs)\n }\n}\n\npub fn assert_lt(a: Field, b: Field) {\n assert_gt(b, a);\n}\n\npub fn gt(a: Field, b: Field) -> bool {\n if is_unconstrained() {\n // Safety: unsafe in unconstrained\n unsafe {\n field_less_than(b, a)\n }\n } else if a == b {\n false\n } else {\n // Safety: Take a hint of the comparison and verify it\n unsafe {\n if field_less_than(a, b) {\n assert_gt(b, a);\n false\n } else {\n assert_gt(a, b);\n true\n }\n }\n }\n}\n\npub fn lt(a: Field, b: Field) -> bool {\n gt(b, a)\n}\n\nmod tests {\n // TODO: Allow imports from \"super\"\n use crate::field::bn254::{assert_gt, decompose, gt, lt, lte_hint, PHI, PLO, TWO_POW_128};\n\n #[test]\n fn check_decompose() {\n assert_eq(decompose(TWO_POW_128), (0, 1));\n assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1));\n assert_eq(decompose(0x1234567890), (0x1234567890, 0));\n }\n\n #[test]\n unconstrained fn check_lte_hint() {\n assert(lte_hint(0, 1));\n assert(lte_hint(0, 0x100));\n assert(lte_hint(0x100, TWO_POW_128 - 1));\n assert(!lte_hint(0 - 1, 0));\n\n assert(lte_hint(0, 0));\n assert(lte_hint(0x100, 0x100));\n assert(lte_hint(0 - 1, 0 - 1));\n }\n\n #[test]\n fn check_gt() {\n assert(gt(1, 0));\n assert(gt(0x100, 0));\n assert(gt((0 - 1), (0 - 2)));\n assert(gt(TWO_POW_128, 0));\n assert(!gt(0, 0));\n assert(!gt(0, 0x100));\n assert(gt(0 - 1, 0 - 2));\n assert(!gt(0 - 2, 0 - 1));\n assert_gt(0 - 1, 0);\n }\n\n #[test]\n fn check_plo_phi() {\n assert_eq(PLO + PHI * TWO_POW_128, 0);\n let p_bytes = crate::field::modulus_le_bytes();\n let mut p_low: Field = 0;\n let mut p_high: Field = 0;\n\n let mut offset = 1;\n for i in 0..16 {\n p_low += (p_bytes[i] as Field) * offset;\n p_high += (p_bytes[i + 16] as Field) * offset;\n offset *= 256;\n }\n assert_eq(p_low, PLO);\n assert_eq(p_high, PHI);\n }\n\n #[test]\n fn check_decompose_edge_cases() {\n assert_eq(decompose(0), (0, 0));\n assert_eq(decompose(TWO_POW_128 - 1), (TWO_POW_128 - 1, 0));\n assert_eq(decompose(TWO_POW_128 + 1), (1, 1));\n assert_eq(decompose(TWO_POW_128 * 2), (0, 2));\n assert_eq(decompose(TWO_POW_128 * 2 + 0x1234567890), (0x1234567890, 2));\n }\n\n #[test]\n fn check_decompose_large_values() {\n let large_field = 0xffffffffffffffff;\n let (lo, hi) = decompose(large_field);\n assert_eq(large_field, lo + TWO_POW_128 * hi);\n\n let large_value = large_field - TWO_POW_128;\n let (lo2, hi2) = decompose(large_value);\n assert_eq(large_value, lo2 + TWO_POW_128 * hi2);\n }\n\n #[test]\n fn check_lt_comprehensive() {\n assert(lt(0, 1));\n assert(!lt(1, 0));\n assert(!lt(0, 0));\n assert(!lt(42, 42));\n\n assert(lt(TWO_POW_128 - 1, TWO_POW_128));\n assert(!lt(TWO_POW_128, TWO_POW_128 - 1));\n }\n}\n","path":"std/field/bn254.nr","function_locations":[{"start":456,"name":"compute_decomposition"},{"start":818,"name":"decompose_hint"},{"start":906,"name":"lte_hint"},{"start":1116,"name":"assert_gt_limbs"},{"start":1725,"name":"decompose"},{"start":2431,"name":"assert_gt"},{"start":2837,"name":"assert_lt"},{"start":2901,"name":"gt"},{"start":3405,"name":"lt"},{"start":3607,"name":"tests::check_decompose"},{"start":3857,"name":"tests::check_lte_hint"},{"start":4164,"name":"tests::check_gt"},{"start":4494,"name":"tests::check_plo_phi"},{"start":4989,"name":"tests::check_decompose_edge_cases"},{"start":5349,"name":"tests::check_decompose_large_values"},{"start":5710,"name":"tests::check_lt_comprehensive"}]},"17":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [bool; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [bool; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [bool; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = false if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = true.\n pub fn sgn0(self) -> bool {\n (self as u8) % 2 == 1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [bool; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [bool; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [bool] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [bool] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_be_bits();\n assert_eq(bits, [false, false, false, false, false, false, true, false]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_le_bits();\n assert_eq(bits, [false, true, false, false, false, false, false, false]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_field.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_val.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [bool; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [false; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [bool; 8] = 1.to_le_bits();\n let expected: [bool; 8] = [true, false, false, false, false, false, false, false];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [bool; 8] = 4.to_le_bits();\n let expected: [bool; 8] = [false, false, true, false, false, false, false, false];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), false);\n assert_eq(2.sgn0(), false);\n assert_eq(4.sgn0(), false);\n assert_eq(100.sgn0(), false);\n\n assert_eq(1.sgn0(), true);\n assert_eq(3.sgn0(), true);\n assert_eq(5.sgn0(), true);\n assert_eq(101.sgn0(), true);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [bool; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits(bits: [bool; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits(bits: [bool; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1]);\n p_minus_1_bits[254 - 1] = false;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(!p_plus_4_bits[254 - 3]);\n p_plus_4_bits[254 - 3] = true;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_be_bits();\n assert(p_plus_4_converted_bits[254 - 3]);\n p_plus_4_converted_bits[254 - 3] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_be_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0]);\n p_minus_1_bits[0] = false;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(!p_plus_4_bits[2]);\n p_plus_4_bits[2] = true;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_le_bits();\n assert(p_plus_4_converted_bits[2]);\n p_plus_4_converted_bits[2] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_le_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n}\n","path":"std/field/mod.nr","function_locations":[{"start":380,"name":"Field::assert_max_bit_size"},{"start":1196,"name":"Field::to_le_bits"},{"start":2387,"name":"Field::to_be_bits"},{"start":3562,"name":"Field::to_le_bytes"},{"start":5033,"name":"Field::to_be_bytes"},{"start":5904,"name":"Field::to_le_radix"},{"start":6362,"name":"Field::to_be_radix"},{"start":7053,"name":"Field::pow_32"},{"start":7455,"name":"Field::sgn0"},{"start":7538,"name":"Field::lt"},{"start":7918,"name":"Field::from_le_bytes"},{"start":8476,"name":"Field::from_be_bytes"},{"start":8757,"name":"__assert_max_bit_size"},{"start":8885,"name":"__to_le_radix"},{"start":9013,"name":"__to_be_radix"},{"start":9734,"name":"__to_le_bits"},{"start":10452,"name":"__to_be_bits"},{"start":10527,"name":"modulus_num_bits"},{"start":10603,"name":"modulus_be_bits"},{"start":10679,"name":"modulus_le_bits"},{"start":10755,"name":"modulus_be_bytes"},{"start":10831,"name":"modulus_le_bytes"},{"start":10992,"name":"__field_less_than"},{"start":11068,"name":"field_less_than"},{"start":11210,"name":"bytes32_to_field"},{"start":11617,"name":"lt_fallback"},{"start":12579,"name":"tests::test_to_be_bits"},{"start":12852,"name":"tests::test_to_le_bits"},{"start":13127,"name":"tests::test_to_be_bytes"},{"start":13433,"name":"tests::test_to_le_bytes"},{"start":13739,"name":"tests::test_to_be_radix"},{"start":14321,"name":"tests::test_to_le_radix"},{"start":14921,"name":"tests::test_to_le_radix_1"},{"start":15374,"name":"tests::test_to_le_radix_brillig_1"},{"start":15728,"name":"tests::test_to_le_radix_3"},{"start":16039,"name":"tests::test_to_le_radix_brillig_3"},{"start":16467,"name":"tests::test_to_le_radix_512"},{"start":16876,"name":"tests::not_enough_limbs_brillig"},{"start":17072,"name":"tests::not_enough_limbs"},{"start":17214,"name":"tests::test_field_less_than"},{"start":17469,"name":"tests::test_large_field_values_unconstrained"},{"start":17922,"name":"tests::test_large_field_values"},{"start":18369,"name":"tests::test_decomposition_edge_cases"},{"start":18959,"name":"tests::test_pow_32"},{"start":19288,"name":"tests::test_sgn0"},{"start":19710,"name":"tests::test_bit_decomposition_overflow"},{"start":19992,"name":"tests::test_byte_decomposition_overflow"},{"start":20209,"name":"tests::test_to_from_be_bytes_bn254_edge_cases"},{"start":22160,"name":"tests::test_to_from_le_bytes_bn254_edge_cases"},{"start":24245,"name":"tests::from_le_bits"},{"start":24792,"name":"tests::from_be_bits"},{"start":25038,"name":"tests::test_to_from_be_bits_bn254_edge_cases"},{"start":26971,"name":"tests::test_to_from_le_bits_bn254_edge_cases"}]},"18":{"source":"// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\nuse crate::static_assert;\n\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated(\"This function has been moved to std::hash::keccakf1600\")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you're working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n \"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\n }\n let generators = derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n crate::assert_constant(separator);\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators(\"pedersen_hash_length\".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n crate::assert_constant(starting_index);\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\npub fn poseidon2_permutation(input: [Field; N]) -> [Field; N] {\n static_assert(\n N == POSEIDON2_CONFIG_STATE_SIZE,\n f\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\",\n );\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal(input: [Field; N]) -> [Field; N] {}\n\n#[foreign(poseidon2_config_state_size)]\ncomptime fn poseidon2_config_state_size() -> u32 {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n /// Returns the hash value without consuming the hasher.\n /// Override this for more efficient implementations that avoid copying.\n /// TODO: deprecate finish() and replace it\n fn finish_ref(&self) -> Field {\n (*self).finish()\n }\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault;\n\nimpl BuildHasher for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl Default for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for [T]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n },\n );\n}\n","path":"std/hash/mod.nr","function_locations":[{"start":572,"name":"sha256_compression"},{"start":707,"name":"keccakf1600"},{"start":882,"name":"keccak::keccakf1600"},{"start":1044,"name":"blake2s"},{"start":1142,"name":"blake3"},{"start":1629,"name":"__blake3"},{"start":1747,"name":"pedersen_commitment"},{"start":1976,"name":"pedersen_commitment_with_separator"},{"start":2380,"name":"pedersen_hash"},{"start":2537,"name":"pedersen_hash_with_separator"},{"start":3531,"name":"derive_generators"},{"start":3890,"name":"__derive_generators"},{"start":3968,"name":"poseidon2_permutation"},{"start":4324,"name":"poseidon2_permutation_internal"},{"start":4417,"name":"poseidon2_config_state_size"},{"start":4728,"name":"derive_hash"},{"start":5953,"name":">::build_hasher"},{"start":6085,"name":">::default"},{"start":6217,"name":"::hash"},{"start":6347,"name":"::hash"},{"start":6487,"name":"::hash"},{"start":6627,"name":"::hash"},{"start":6767,"name":"::hash"},{"start":6908,"name":"::hash"},{"start":7047,"name":"::hash"},{"start":7193,"name":"::hash"},{"start":7340,"name":"::hash"},{"start":7487,"name":"::hash"},{"start":7635,"name":"::hash"},{"start":7782,"name":"::hash"},{"start":7914,"name":"::hash"},{"start":8103,"name":"::hash"},{"start":8343,"name":"::hash"},{"start":8559,"name":"::hash"},{"start":8822,"name":"::hash"},{"start":9132,"name":"::hash"},{"start":9528,"name":"assert_pedersen"}]},"41":{"source":"use crate::cmp::{Eq, Ord, Ordering};\nuse crate::default::Default;\nuse crate::hash::{Hash, Hasher};\n\n/// Represents a value of type T or its absence.\n/// Use `Option::some(value)` to construct a value or `Option::none()` to record the absence of one.\npub struct Option {\n _is_some: bool,\n _value: T,\n}\n\nimpl Option {\n /// Constructs a None value\n pub fn none() -> Self {\n Self { _is_some: false, _value: crate::mem::zeroed() }\n }\n\n /// Constructs a Some wrapper around the given value\n pub fn some(_value: T) -> Self {\n Self { _is_some: true, _value }\n }\n\n /// True if this Option is None\n pub fn is_none(&self) -> bool {\n !self._is_some\n }\n\n /// True if this Option is Some\n pub fn is_some(&self) -> bool {\n self._is_some\n }\n\n /// Asserts `self.is_some()` and returns the wrapped value.\n pub fn unwrap(self) -> T {\n assert(self._is_some);\n self._value\n }\n\n /// Returns the inner value without asserting `self.is_some()`\n /// Note that if `self` is `None`, there is no guarantee what value will be returned,\n /// only that it will be of type `T`.\n pub fn unwrap_unchecked(self) -> T {\n self._value\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.\n pub fn unwrap_or(self, default: T) -> T {\n if self._is_some {\n self._value\n } else {\n default\n }\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return\n /// a default value.\n pub fn unwrap_or_else(self, default: fn[Env]() -> T) -> T {\n if self._is_some {\n self._value\n } else {\n default()\n }\n }\n\n /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value\n pub fn expect(self, message: fmtstr) -> T {\n assert(self.is_some(), message);\n self._value\n }\n\n /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.\n pub fn map(self, f: fn[Env](T) -> U) -> Option {\n if self._is_some {\n Option::some(f(self._value))\n } else {\n Option::none()\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.\n pub fn map_or(self, default: U, f: fn[Env](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.\n pub fn map_or_else(self, default: fn[Env1]() -> U, f: fn[Env2](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default()\n }\n }\n\n /// Returns None if self is None. Otherwise, this returns `other`.\n pub fn and(self, other: Self) -> Self {\n if self.is_none() {\n Option::none()\n } else {\n other\n }\n }\n\n /// If self is None, this returns None. Otherwise, this calls the given function\n /// with the Some value contained within self, and returns the result of that call.\n ///\n /// In some languages this function is called `flat_map` or `bind`.\n pub fn and_then(self, f: fn[Env](T) -> Option) -> Option {\n if self._is_some {\n f(self._value)\n } else {\n Option::none()\n }\n }\n\n /// If self is Some, return self. Otherwise, return `other`.\n pub fn or(self, other: Self) -> Self {\n if self._is_some {\n self\n } else {\n other\n }\n }\n\n /// If self is Some, return self. Otherwise, return `default()`.\n pub fn or_else(self, default: fn[Env]() -> Self) -> Self {\n if self._is_some {\n self\n } else {\n default()\n }\n }\n\n // If only one of the two Options is Some, return that option.\n // Otherwise, if both options are Some or both are None, None is returned.\n pub fn xor(self, other: Self) -> Self {\n if self._is_some {\n if other._is_some {\n Option::none()\n } else {\n self\n }\n } else if other._is_some {\n other\n } else {\n Option::none()\n }\n }\n\n /// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.\n /// Otherwise, this returns `None`\n pub fn filter(self, predicate: fn[Env](T) -> bool) -> Self {\n if self._is_some {\n if predicate(self._value) {\n self\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n }\n\n /// Flattens an Option> into a Option.\n /// This returns None if the outer Option is None. Otherwise, this returns the inner Option.\n pub fn flatten(option: Option>) -> Option {\n if option._is_some {\n option._value\n } else {\n Option::none()\n }\n }\n}\n\nimpl Default for Option {\n fn default() -> Self {\n Option::none()\n }\n}\n\nimpl Eq for Option\nwhere\n T: Eq,\n{\n fn eq(self, other: Self) -> bool {\n if self._is_some == other._is_some {\n if self._is_some {\n self._value == other._value\n } else {\n true\n }\n } else {\n false\n }\n }\n}\n\nimpl Hash for Option\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self._is_some.hash(state);\n if self._is_some {\n self._value.hash(state);\n }\n }\n}\n\n// For this impl we're declaring Option::none < Option::some\nimpl Ord for Option\nwhere\n T: Ord,\n{\n fn cmp(self, other: Self) -> Ordering {\n if self._is_some {\n if other._is_some {\n self._value.cmp(other._value)\n } else {\n Ordering::greater()\n }\n } else if other._is_some {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n","path":"std/option.nr","function_locations":[{"start":389,"name":"Option::none"},{"start":553,"name":"Option::some"},{"start":672,"name":"Option::is_none"},{"start":774,"name":"Option::is_some"},{"start":898,"name":"Option::unwrap"},{"start":1196,"name":"Option::unwrap_unchecked"},{"start":1368,"name":"Option::unwrap_or"},{"start":1668,"name":"Option::unwrap_or_else"},{"start":1969,"name":"Option::expect"},{"start":2190,"name":"Option::map"},{"start":2490,"name":"Option::map_or"},{"start":2784,"name":"Option::map_or_else"},{"start":3009,"name":"Option::and"},{"start":3446,"name":"Option::and_then"},{"start":3669,"name":"Option::or"},{"start":3902,"name":"Option::or_else"},{"start":4192,"name":"Option::xor"},{"start":4636,"name":"Option::filter"},{"start":5065,"name":"Option::flatten"},{"start":5242,"name":">::default"},{"start":5357,"name":">::eq"},{"start":5706,"name":">::hash"},{"start":5975,"name":">::cmp"}]},"42":{"source":"/// Halt the program at runtime with the given error message.\n///\n/// The provided error message must be either a `str` or a `fmtstr`.\npub fn panic(message: T) -> U\nwhere\n T: StringLike,\n{\n assert(false, message);\n crate::mem::zeroed()\n}\n\ntrait StringLike {}\n\nimpl StringLike for str {}\nimpl StringLike for fmtstr {}\n","path":"std/panic.nr","function_locations":[{"start":196,"name":"panic"}]},"52":{"source":"use crate::{\n authwit::{authorization_interface::AuthorizationInterface, AuthorizationSelector},\n context::{gas::GasOpts, PrivateContext, PublicContext},\n hash::hash_args,\n macros::authorization::authorization,\n oracle::{execution_cache::load, offchain_effect::emit_offchain_effect},\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::AztecAddress,\n constants::{\n CANONICAL_AUTH_REGISTRY_ADDRESS, DOM_SEP__AUTHWIT_INNER, DOM_SEP__AUTHWIT_NULLIFIER, DOM_SEP__AUTHWIT_OUTER,\n },\n hash::poseidon2_hash_with_separator,\n traits::{Serialize, ToField},\n};\n\n/// Authentication witness helper library\n///\n/// Authentication Witness is a scheme for authenticating actions on Aztec, so users can allow third-parties (e.g.\n/// protocols or other users) to execute an action on their behalf.\n///\n/// This library provides helper functions to manage such witnesses. The authentication witness, is some \"witness\"\n/// (data) that authenticates a `message_hash`. The simplest example of an authentication witness, is a signature. The\n/// signature is the \"evidence\", that the signer has seen the message, agrees with it, and has allowed it. It does not\n/// need to be a signature. It could be any kind of \"proof\" that the message is allowed. Another proof could be knowing\n/// some kind of secret, or having some kind of \"token\" that allows the message.\n///\n/// The `message_hash` is a hash of the following structure: hash(consumer, chain_id, version, inner_hash)\n/// - consumer: the address of the contract that is \"consuming\" the message,\n/// - chain_id: the chain id of the chain that the message is being consumed on,\n/// - version: the version of the chain that the message is being consumed on,\n/// - inner_hash: the hash of the \"inner\" message that is being consumed, this is the \"actual\" message or action.\n///\n/// While the `inner_hash` could be anything, such as showing you signed a specific message, it will often be a hash of\n/// the \"action\" to approve, along with who made the call. As part of this library, we provide a few helper functions\n/// to deal with such messages.\n///\n/// For example, we provide helper function that is used for checking that the message is an encoding of the current\n/// call. This can be used to let some contract \"allow\" another contract to act on its behalf, as long as it can show\n/// that it is acting on behalf of the contract.\n///\n/// If we take a case of allowing a contract to transfer tokens on behalf of an account, the `inner_hash` can be\n/// derived as: inner_hash = hash(caller, \"transfer\", hash(to, amount))\n///\n/// Where the `caller` would be the address of the contract that is trying to transfer the tokens, and `to` and\n/// `amount` the arguments for the transfer.\n///\n/// Note that we have both a `caller` and a `consumer`, the `consumer` will be the contract that is consuming the\n/// message, in the case of the transfer, it would be the `Token` contract itself, while the caller, will be the actor\n/// that is allowed to transfer the tokens.\n///\n///\n/// The authentication mechanism works differently in public and private contexts. In private, we recall that\n/// everything is executed on the user's device, so we can use `oracles` to \"ask\" the user (not contract) for\n/// information. In public we cannot do this, since it is executed by the sequencer (someone else). Therefore we can\n/// instead use a \"registry\" to store the messages that we have approved.\n///\n/// A simple example would be a \"token\" that is being \"pulled\" from one account into another. We will first outline how\n/// this would look in private, and then in public later.\n///\n/// Say that a user `Alice` wants to deposit some tokens into a DeFi protocol (say a DEX). `Alice` would make a\n/// `deposit` transaction, that she is executing using her account contract. The account would call the `DeFi` contract\n/// to execute `deposit`, which would try to pull funds from the `Token` contract. Since the `DeFi` contract is trying\n/// to pull funds from an account that is not its own, it needs to convince the `Token` contract that it is allowed to\n/// do so.\n///\n/// This is where the authentication witness comes in The `Token` contract computes a `message_hash` from the\n/// `transfer` call, and then asks `Alice Account` contract to verify that the `DeFi` contract is allowed to execute\n/// that call.\n///\n/// `Alice Account` contract can then ask `Alice` if she wants to allow the `DeFi` contract to pull funds from her\n/// account. If she does, she will sign the `message_hash` and return the signature to the `Alice Account` which will\n/// validate it and return success to the `Token` contract which will then allow the `DeFi` contract to pull funds from\n/// `Alice`.\n///\n/// To ensure that the same \"approval\" cannot be used multiple times, we also compute a `nullifier` for the\n/// authentication witness, and emit it from the `Token` contract (consumer).\n///\n/// Note that we can do this flow as we are in private were we can do oracle calls out from contracts.\n///\n///\n/// Person Contract Contract Contract\n/// Alice Alice Account Token DeFi\n/// | | | |\n/// | Defi.deposit(Token, 1000) | |\n/// |----------------->| | |\n/// | | deposit(Token, 1000) |\n/// | |---------------------------------------->|\n/// | | | |\n/// | | | transfer(Alice, Defi, 1000)\n/// | | |<---------------------|\n/// | | | |\n/// | | Check if Defi may call transfer(Alice, Defi, 1000)\n/// | |<-----------------| |\n/// | | | |\n/// | Please give me AuthWit for DeFi | |\n/// | calling transfer(Alice, Defi, 1000) | |\n/// |<-----------------| | |\n/// | | | |\n/// | | | |\n/// | AuthWit for transfer(Alice, Defi, 1000) |\n/// |----------------->| | |\n/// | | AuthWit validity | |\n/// | |----------------->| |\n/// | | | |\n/// | | throw if invalid AuthWit |\n/// | | | |\n/// | | emit AuthWit nullifier |\n/// | | | |\n/// | | transfer(Alice, Defi, 1000) |\n/// | | | |\n/// | | | |\n/// | | | success |\n/// | | |--------------------->|\n/// | | | |\n/// | | | |\n/// | | | deposit(Token, 1000)\n/// | | | |\n/// | | | |\n///\n///\n/// If we instead were in public, we cannot do the same flow. Instead we would use an authentication registry to store\n/// the messages that we have approved.\n///\n/// To approve a message, `Alice Account` can make a `set_authorized` call to the registry, to set a `message_hash` as\n/// authorized. This is essentially a mapping from `message_hash` to `true` for `Alice Contract`. Every account has its\n/// own map in the registry, so `Alice` cannot approve a message for `Bob`.\n///\n/// The `Token` contract can then try to \"spend\" the approval by calling `consume` on the registry. If the message was\n/// approved, the value is updated to `false`, and we return the success flag. For more information on the registry,\n/// see `main.nr` in `auth_registry_contract`.\n///\n/// Person Contract Contract Contract Contract\n/// Alice Alice Account Registry Token DeFi\n/// | | | | |\n/// | Registry.set_authorized(..., true) | | |\n/// |----------------->| | | |\n/// | | set_authorized(..., true) | |\n/// | |------------------->| | |\n/// | | | | |\n/// | | set authorized to true | |\n/// | | | | |\n/// | | | | |\n/// | Defi.deposit(Token, 1000) | | |\n/// |----------------->| | | |\n/// | | deposit(Token, 1000) | |\n/// | |-------------------------------------------------------------->|\n/// | | | | |\n/// | | | transfer(Alice, Defi, 1000) |\n/// | | | |<---------------------|\n/// | | | | |\n/// | | | Check if Defi may call transfer(Alice, Defi, 1000)\n/// | | |<------------------| |\n/// | | | | |\n/// | | throw if invalid AuthWit | |\n/// | | | | |\n/// | | | | |\n/// | | set authorized to false | |\n/// | | | | |\n/// | | | | |\n/// | | | AuthWit validity | |\n/// | | |------------------>| |\n/// | | | | |\n/// | | | | transfer(Alice, Defi, 1000)\n/// | | | |<-------------------->|\n/// | | | | |\n/// | | | | success |\n/// | | | |--------------------->|\n/// | | | | |\n/// | | | | deposit(Token, 1000)\n/// | | | | |\n///\n///\n/// --- FAQ ---\n/// Q: Why are we using a success flag of `poseidon2_hash_bytes(\"IS_VALID()\")` instead of just returning a boolean?\n/// A: We want to make sure that we don't accidentally return `true` if there is a collision in the function\n/// selector. By returning a hash of `IS_VALID()`, it becomes very unlikely that there is both a collision and we\n/// return a success flag.\n///\n/// Q: Why are we using static calls?\n/// A: We are using static calls to ensure that the account contract cannot re-enter. If it was a normal call, it\n/// could make a new call and do a re-entry attack. Using a static ensures that it cannot update any state.\n///\n/// Q: Would it not be cheaper to use a nullifier instead of updating state in public?\n/// A: At a quick glance, a public state update + nullifier is 96 bytes, but two state updates are 128, so it would\n/// be cheaper to use a nullifier, if this is the way it would always be done. However, if both the approval and the\n/// consumption is done in the same transaction, then we will be able to squash the updates (only final tx state diff\n/// is posted to DA), and now it is cheaper.\n///\n/// Q: Why is the chain id and the version part of the message hash?\n/// A: The chain id and the version is part of the message hash to ensure that the message is only valid on a\n/// specific chain to avoid a case where the same message could be used across multiple chains.\n\npub global IS_VALID_SELECTOR: Field = 0x47dacd73; // 4 last bytes of\n// poseidon2_hash_bytes(\"IS_VALID()\")\n\n/// A struct that represents a contract call the user can authorize. It's associated identifier is generated by\n/// serializing and hashing it. The user is expected to sign this hash to signal the contract call can be performed on\n/// their behalf\n#[authorization]\nstruct CallAuthorization {\n msg_sender: AztecAddress,\n selector: FunctionSelector,\n args_hash: Field,\n}\n\n/// A struct that represents a request to authorize a call, which is used to emit an offchain effect so the user/wallet\n/// can understand what they are being asked to sign. It is generated from a CallAuthorization by adding metadata to\n/// it, such as the selector for the authorization, the inner hash, and the actual arguments that are being passed to\n/// the function call.\n#[derive(Serialize)]\nstruct CallAuthorizationRequest {\n selector: AuthorizationSelector,\n inner_hash: Field,\n on_behalf_of: AztecAddress,\n msg_sender: AztecAddress,\n fn_selector: FunctionSelector,\n args_hash: Field,\n}\n\nunconstrained fn emit_authorization_as_offchain_effect(\n authorization: CallAuthorization,\n inner_hash: Field,\n on_behalf_of: AztecAddress,\n) {\n let args: [Field; N] = load(authorization.args_hash);\n let authorization_request = CallAuthorizationRequest {\n selector: authorization.get_authorization_selector(),\n inner_hash: inner_hash,\n on_behalf_of: on_behalf_of,\n msg_sender: authorization.msg_sender,\n fn_selector: authorization.selector,\n args_hash: authorization.args_hash,\n };\n emit_offchain_effect(authorization_request.serialize().concat(args))\n}\n\n/// Assert that `on_behalf_of` has authorized the current call with a valid authentication witness\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Additionally, this function emits the identifying information of the call as an offchain effect so PXE can rely the\n/// information to the user/wallet in a readable way. To that effect, it is generic over N, where N is the number of\n/// arguments the authorized functions takes. This is used to load the arguments from the execution cache. This\n/// function is intended to be called via a macro, which will use the turbofish operator to specify the number of\n/// arguments.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call\npub fn assert_current_call_valid_authwit(context: &mut PrivateContext, on_behalf_of: AztecAddress) {\n let args_hash: Field = context.get_args_hash();\n\n let authorization =\n CallAuthorization { msg_sender: context.maybe_msg_sender().unwrap(), selector: context.selector(), args_hash };\n let inner_hash = compute_inner_authwit_hash(authorization.serialize());\n // Safety: Offchain effects are by definition unconstrained. They are emitted via an oracle which we don't use for\n // anything besides its side effects, therefore this is safe to call.\n unsafe { emit_authorization_as_offchain_effect::(authorization, inner_hash, on_behalf_of) };\n\n assert_inner_hash_valid_authwit(context, on_behalf_of, inner_hash);\n}\n\n/// Assert that a specific `inner_hash` is valid for the `on_behalf_of` address\n///\n/// Used as an internal function for `assert_current_call_valid_authwit` and can be used as a standalone function when\n/// the `inner_hash` is from a different source, e.g., say a block of text etc.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call @param inner_hash The hash of the\n/// message to authorize\npub fn assert_inner_hash_valid_authwit(context: &mut PrivateContext, on_behalf_of: AztecAddress, inner_hash: Field) {\n // We perform a static call here and not a standard one to ensure that the account contract cannot re-enter.\n let result: Field = context\n .static_call_private_function(\n on_behalf_of,\n comptime { FunctionSelector::from_signature(\"verify_private_authwit(Field)\") },\n [inner_hash],\n )\n .get_preimage();\n assert(result == IS_VALID_SELECTOR, \"Message not authorized by account\");\n // Compute the nullifier, similar computation to the outer hash, but without the chain_id and version. Those should\n // already be handled in the verification, so we just need something to nullify, that allows the same inner_hash\n // for multiple actors.\n let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash);\n context.push_nullifier(nullifier);\n}\n\n/// Assert that `on_behalf_of` has authorized the current call in the authentication registry\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Note that the authentication registry will take the `msg_sender` into account as the consumer, so this will only\n/// work if the `msg_sender` is the same as the `consumer` when the `message_hash` was inserted into the registry.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call\npub unconstrained fn assert_current_call_valid_authwit_public(context: PublicContext, on_behalf_of: AztecAddress) {\n let inner_hash = compute_inner_authwit_hash([\n context.maybe_msg_sender().unwrap().to_field(),\n context.selector().to_field(),\n context.get_args_hash(),\n ]);\n assert_inner_hash_valid_authwit_public(context, on_behalf_of, inner_hash);\n}\n\n/// Assert that `on_behalf_of` has authorized a specific `inner_hash` in the authentication registry\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Note that the authentication registry will take the `msg_sender` into account as the consumer, so this will only\n/// work if the `msg_sender` is the same as the `consumer` when the `message_hash` was inserted into the registry.\n///\n/// @param on_behalf_of The address that has allegedly authorized the `inner_hash`\npub unconstrained fn assert_inner_hash_valid_authwit_public(\n context: PublicContext,\n on_behalf_of: AztecAddress,\n inner_hash: Field,\n) {\n let results: [Field] = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"consume((Field),Field)\") },\n [on_behalf_of.to_field(), inner_hash],\n GasOpts::default(),\n );\n assert(results.len() == 1, \"Invalid response from registry\");\n assert(results[0] == IS_VALID_SELECTOR, \"Message not authorized by account\");\n}\n\n/// Compute the `message_hash` from a function call to be used by an authentication witness\n///\n/// Useful for when you need a non-account contract to approve during execution. For example if you need a contract to\n/// make a call to nested contract, e.g., contract A wants to exit token T to L1 using bridge B, so it needs to allow B\n/// to transfer T on its behalf.\n///\n/// @param caller The address of the contract that is calling the function, in the example above, this would be B\n/// @param consumer The address of the contract that is consuming the message, in the example above, this would be T\n/// @param chain_id The chain id of the chain that the message is being consumed on @param version The version of the\n/// chain that the message is being consumed on @param selector The function selector of the function that is being\n/// called @param args The arguments of the function that is being called\npub fn compute_authwit_message_hash_from_call(\n caller: AztecAddress,\n consumer: AztecAddress,\n chain_id: Field,\n version: Field,\n selector: FunctionSelector,\n args: [Field; N],\n) -> Field {\n let args_hash = hash_args(args);\n let inner_hash = compute_inner_authwit_hash([caller.to_field(), selector.to_field(), args_hash]);\n compute_authwit_message_hash(consumer, chain_id, version, inner_hash)\n}\n\n/// Computes the `inner_hash` of the authentication witness\n///\n/// This is used internally, but also useful in cases where you want to compute the `inner_hash` for a specific message\n/// that is not necessarily a call, but just some \"bytes\" or text.\n///\n/// @param args The arguments to hash\npub fn compute_inner_authwit_hash(args: [Field; N]) -> Field {\n poseidon2_hash_with_separator(args, DOM_SEP__AUTHWIT_INNER)\n}\n\n/// Computes the `authwit_nullifier` for a specific `on_behalf_of` and `inner_hash`\n///\n/// Using the `on_behalf_of` and the `inner_hash` to ensure that the nullifier is siloed for a specific `on_behalf_of`.\n///\n/// @param on_behalf_of The address that has authorized the `inner_hash` @param inner_hash The hash of the message to\n/// authorize\npub fn compute_authwit_nullifier(on_behalf_of: AztecAddress, inner_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [on_behalf_of.to_field(), inner_hash],\n DOM_SEP__AUTHWIT_NULLIFIER,\n )\n}\n\n/// Computes the `message_hash` for the authentication witness\n///\n/// @param consumer The address of the contract that is consuming the message @param chain_id The chain id of the chain\n/// that the message is being consumed on @param version The version of the chain that the message is being consumed on\n/// @param inner_hash The hash of the \"inner\" message that is being consumed\npub fn compute_authwit_message_hash(\n consumer: AztecAddress,\n chain_id: Field,\n version: Field,\n inner_hash: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [consumer.to_field(), chain_id, version, inner_hash],\n DOM_SEP__AUTHWIT_OUTER,\n )\n}\n\n/// Helper function to set the authorization status of a message hash\n///\n/// Wraps a public call to the authentication registry to set the authorization status of a `message_hash`\n///\n/// @param message_hash The hash of the message to authorize @param authorize True if the message should be authorized,\n/// false if it should be revoked\npub unconstrained fn set_authorized(context: PublicContext, message_hash: Field, authorize: bool) {\n let res = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"set_authorized(Field,bool)\") },\n [message_hash, authorize as Field],\n GasOpts::default(),\n );\n assert(res.len() == 0);\n}\n\n/// Helper function to reject all authwits\n///\n/// Wraps a public call to the authentication registry to set the `reject_all` flag\n///\n/// @param reject True if all authwits should be rejected, false otherwise\npub unconstrained fn set_reject_all(context: PublicContext, reject: bool) {\n let res = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"set_reject_all(bool)\") },\n [reject as Field],\n GasOpts::default(),\n );\n assert(res.len() == 0);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/authwit/auth.nr","function_locations":[{"start":14768,"name":"emit_authorization_as_offchain_effect"},{"start":16200,"name":"assert_current_call_valid_authwit"},{"start":17389,"name":"assert_inner_hash_valid_authwit"},{"start":18929,"name":"assert_current_call_valid_authwit_public"},{"start":19955,"name":"assert_inner_hash_valid_authwit_public"},{"start":21499,"name":"compute_authwit_message_hash_from_call"},{"start":22083,"name":"compute_inner_authwit_hash"},{"start":22585,"name":"compute_authwit_nullifier"},{"start":23238,"name":"compute_authwit_message_hash"},{"start":23815,"name":"set_authorized"},{"start":24381,"name":"set_reject_all"}]},"59":{"source":"use crate::oracle::capsules;\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// A dynamically sized array backed by PXE's non-volatile database (called capsules). Values are persisted until\n/// deleted, so they can be e.g. stored during simulation of a transaction and later retrieved during witness\n/// generation. All values are scoped per contract address, so external contracts cannot access them.\npub struct CapsuleArray {\n contract_address: AztecAddress,\n /// The base slot is where the array length is stored in capsules. Array elements are stored in consecutive slots\n /// after the base slot. For example, with base slot 5: the length is at slot 5, the first element (index 0) is at\n /// slot 6, the second element (index 1) is at slot 7, and so on.\n base_slot: Field,\n /// Scope for capsule isolation. Capsule operations are scoped to the given address, allowing multiple independent\n /// namespaces within the same contract.\n scope: AztecAddress,\n}\n\nimpl CapsuleArray {\n /// Returns a CapsuleArray scoped to a specific address.\n ///\n /// Array elements are stored in contiguous slots\n /// following the base slot, so there should be sufficient space between array base slots to accommodate elements.\n /// A reasonable strategy is to make the base slot a hash of a unique value.\n pub unconstrained fn at(contract_address: AztecAddress, base_slot: Field, scope: AztecAddress) -> Self {\n Self { contract_address, base_slot, scope }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n // An uninitialized array defaults to a length of 0.\n capsules::load(self.contract_address, self.base_slot, self.scope).unwrap_or(0) as u32\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let current_length = self.len();\n\n // The slot corresponding to the index `current_length` is the first slot immediately after the end of the\n // array, which is where we want to place the new value.\n capsules::store(\n self.contract_address,\n self.slot_at(current_length),\n value,\n self.scope,\n );\n\n // Then we simply update the length.\n let new_length = current_length + 1;\n capsules::store(\n self.contract_address,\n self.base_slot,\n new_length,\n self.scope,\n );\n }\n\n /// Retrieves the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n assert(index < self.len(), \"Attempted to read past the length of a CapsuleArray\");\n\n capsules::load(self.contract_address, self.slot_at(index), self.scope).unwrap()\n }\n\n /// Deletes the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n let current_length = self.len();\n assert(index < current_length, \"Attempted to delete past the length of a CapsuleArray\");\n\n // In order to be able to remove elements at arbitrary indices, we need to shift the entire contents of the\n // array past the removed element one slot backward so that we don't end up with a gap and preserve the\n // contiguous slots. We can skip this when deleting the last element however.\n if index != current_length - 1 {\n // The source and destination regions overlap, but `copy` supports this.\n capsules::copy(\n self.contract_address,\n self.slot_at(index + 1),\n self.slot_at(index),\n current_length - index - 1,\n self.scope,\n );\n }\n\n // We can now delete the last element (which has either been copied to the slot immediately before it, or was\n // the element we meant to delete in the first place) and update the length.\n capsules::delete(\n self.contract_address,\n self.slot_at(current_length - 1),\n self.scope,\n );\n capsules::store(\n self.contract_address,\n self.base_slot,\n current_length - 1,\n self.scope,\n );\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. The order in which values\n /// are processed is arbitrary.\n ///\n /// ## Array Mutation\n ///\n /// It is safe to delete the current element (and only the current element) from inside the callback via `remove`:\n /// ```noir\n /// array.for_each(|index, value| {\n /// if some_condition(value) {\n /// array.remove(index); // safe only for this index\n /// }\n /// }\n /// ```\n ///\n /// If all elements in the array need to iterated over and then removed, then using `for_each` results in optimal\n /// efficiency.\n ///\n /// It is **not** safe to push new elements into the array from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n // Iterating over all elements is simple, but we want to do it in such a way that a) deleting the current\n // element is safe to do, and b) deleting *all* elements is optimally efficient. This is because CapsuleArrays\n // are typically used to hold pending tasks, so iterating them while clearing completed tasks (sometimes\n // unconditionally, resulting in a full clear) is a very common access pattern.\n //\n // The way we achieve this is by iterating backwards: each element can always be deleted since it won't change\n // any preceding (lower) indices, and if every element is deleted then every element will (in turn) be the last\n // element. This results in an optimal full clear since `remove` will be able to skip the `capsules::copy` call\n // to shift any elements past the deleted one (because there will be none).\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n\n unconstrained fn slot_at(self, index: u32) -> Field {\n // Elements are stored immediately after the base slot, so we add 1 to it to compute the slot for the first\n // element.\n self.base_slot + 1 + index as Field\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::CapsuleArray;\n\n global SLOT: Field = 1230;\n\n #[test]\n unconstrained fn empty_array() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array: CapsuleArray = CapsuleArray::at(contract_address, SLOT, scope);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn empty_array_read() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n let _: Field = array.get(0);\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn read_past_len() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(5);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 8);\n assert_eq(array.get(2), 9);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We store all values that we were called with and check that all (value, index) tuples are present. Note\n // that we do not care about the order in which each tuple was passed to the closure.\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all_no_copy() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We test that the aztec_utl_copyCapsule was never called, which is the expensive operation we want to\n // avoid.\n let mock = std::test::OracleMock::mock(\"aztec_utl_copyCapsule\");\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(mock.times_called(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_scopes_are_isolated() {\n let mut env = TestEnvironment::new();\n let scope_a = env.create_light_account();\n let scope_b = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array_a = CapsuleArray::at(contract_address, SLOT, scope_a);\n let array_b = CapsuleArray::at(contract_address, SLOT, scope_b);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/capsules/mod.nr","function_locations":[{"start":1478,"name":"CapsuleArray::at"},{"start":1641,"name":"CapsuleArray::len"},{"start":1935,"name":"CapsuleArray::push"},{"start":2748,"name":"CapsuleArray::get"},{"start":3083,"name":"CapsuleArray::remove"},{"start":5345,"name":"CapsuleArray::for_each"},{"start":6413,"name":"CapsuleArray::slot_at"},{"start":6789,"name":"test::empty_array"},{"start":7263,"name":"test::empty_array_read"},{"start":7638,"name":"test::array_push"},{"start":8156,"name":"test::read_past_len"},{"start":8559,"name":"test::array_remove_last"},{"start":8997,"name":"test::array_remove_some"},{"start":9729,"name":"test::array_remove_all"},{"start":10296,"name":"test::for_each_called_with_all_elements"},{"start":11389,"name":"test::for_each_remove_some"},{"start":12081,"name":"test::for_each_remove_all"},{"start":12619,"name":"test::for_each_remove_all_no_copy"},{"start":13383,"name":"test::different_scopes_are_isolated"}]},"68":{"source":"use crate::{\n context::gas::GasOpts,\n hash::{\n compute_l1_to_l2_message_hash, compute_l1_to_l2_message_nullifier, compute_secret_hash,\n compute_siloed_nullifier,\n },\n oracle::avm,\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::{AztecAddress, EthAddress},\n constants::{MAX_U32_VALUE, NULL_MSG_SENDER_CONTRACT_ADDRESS},\n traits::{Empty, FromField, Packable, Serialize, ToField},\n utils::writer::Writer,\n};\n\n/// # PublicContext\n///\n/// The **main interface** between an #[external(\"public\")] function and the Aztec blockchain.\n///\n/// An instance of the PublicContext is initialized automatically at the outset of every public function, within the\n/// #[external(\"public\")] macro, so you'll never need to consciously instantiate this yourself.\n///\n/// The instance is always named `context`, and it will always be available within the body of every\n/// #[external(\"public\")] function in your smart contract.\n///\n/// Typical usage for a smart contract developer will be to call getter methods of the PublicContext.\n///\n/// _Pushing_ data and requests to the context is mostly handled within aztec-nr's own functions, so typically a smart\n/// contract developer won't need to call any setter methods directly.\n///\n/// ## Responsibilities\n/// - Exposes contextual data to a public function:\n/// - Data relating to how this public function was called:\n/// - msg_sender, this_address\n/// - Data relating to the current blockchain state:\n/// - timestamp, block_number, chain_id, version\n/// - Gas and fee information\n/// - Provides state access:\n/// - Read/write public storage (key-value mapping)\n/// - Check existence of notes and nullifiers (Some patterns use notes & nullifiers to store public (not private)\n/// information)\n/// - Enables consumption of L1->L2 messages.\n/// - Enables calls to other public smart contract functions:\n/// - Writes data to the blockchain:\n/// - Updates to public state variables\n/// - New public logs (for events)\n/// - New L2->L1 messages\n/// - New notes & nullifiers (E.g. pushing public info to notes/nullifiers, or for completing \"partial notes\")\n///\n/// ## Key Differences from Private Execution\n///\n/// Unlike private functions -- which are executed on the user's device and which can only reference historic state --\n/// public functions are executed by a block proposer and are executed \"live\" on the _current_ tip of the chain. This\n/// means public functions can:\n/// - Read and write _current_ public state\n/// - Immediately see the effects of earlier transactions in the same block\n///\n/// Also, public functions are executed within a zkVM (the \"AVM\"), so that they can _revert_ whilst still ensuring\n/// payment to the proposer and prover. (Private functions cannot revert: they either succeed, or they cannot be\n/// included).\n///\n/// ## Optimising Public Functions\n///\n/// Using the AVM to execute public functions means they compile down to \"AVM bytecode\" instead of the ACIR that\n/// private functions (standalone circuits) compile to. Therefore the approach to optimising a public function is\n/// fundamentally different from optimising a public function.\n///\npub struct PublicContext {\n pub args_hash: Option,\n pub compute_args_hash: fn() -> Field,\n}\n\nimpl Eq for PublicContext {\n fn eq(self, other: Self) -> bool {\n (self.args_hash == other.args_hash)\n // Can't compare the function compute_args_hash\n }\n}\n\nimpl PublicContext {\n /// Creates a new PublicContext instance.\n ///\n /// Low-level function: This is called automatically by the #[external(\"public\")] macro, so you shouldn't need to\n /// be called directly by smart contract developers.\n ///\n /// # Arguments\n /// * `compute_args_hash` - Function to compute the args_hash\n ///\n /// # Returns\n /// * A new PublicContext instance\n ///\n pub fn new(compute_args_hash: fn() -> Field) -> Self {\n PublicContext { args_hash: Option::none(), compute_args_hash }\n }\n\n /// Emits a _public_ log that will be visible onchain to everyone.\n ///\n /// # Arguments\n /// * `tag` - A tag placed at `fields[0]` of the emitted log. Nodes index logs by this value, allowing\n /// clients to efficiently query for matching logs without scanning all of them.\n /// * `log` - The data to log, must implement Serialize trait.\n ///\n /// ## Safety\n ///\n /// The `tag` should be domain-separated (e.g. via [`crate::protocol::hash::compute_log_tag`]) to prevent\n /// collisions between logs from different sources. Without domain separation, two unrelated log types that\n /// happen to share a raw tag value become indistinguishable. Prefer `self.emit(event)` for events, which\n /// handles tagging automatically.\n pub fn emit_public_log_unsafe(_self: Self, tag: Field, log: T)\n where\n T: Serialize,\n {\n // We use a Writer to serialize the log directly after the tag, avoiding an extra O(n) copy that would\n // result from serializing first and then prepending the tag.\n let mut writer: Writer<1 + ::N> = Writer::new();\n writer.write(tag);\n Serialize::stream_serialize(log, &mut writer);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_public_log(writer.finish().as_vector()) };\n }\n\n /// Checks if a given note hash exists in the note hash tree at a particular leaf_index.\n ///\n /// # Arguments\n /// * `note_hash` - The note hash to check for existence\n /// * `leaf_index` - The index where the note hash should be located\n ///\n /// # Returns\n /// * `bool` - True if the note hash exists at the specified index\n ///\n pub fn note_hash_exists(_self: Self, note_hash: Field, leaf_index: u64) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::note_hash_exists(note_hash, leaf_index)\n }\n }\n\n /// Checks if a specific L1-to-L2 message exists in the L1-to-L2 message tree at a particular leaf index.\n ///\n /// Common use cases include token bridging, cross-chain governance, and triggering L2 actions based on L1 events.\n ///\n /// This function should be called before attempting to consume an L1-to-L2 message.\n ///\n /// # Arguments\n /// * `msg_hash` - Hash of the L1-to-L2 message to check\n /// * `msg_leaf_index` - The index where the message should be located\n ///\n /// # Returns\n /// * `bool` - True if the message exists at the specified index\n ///\n /// # Advanced\n /// * Uses the AVM l1_to_l2_msg_exists opcode for tree lookup\n /// * Messages are copied from L1 Inbox to L2 by block proposers\n ///\n pub fn l1_to_l2_msg_exists(_self: Self, msg_hash: Field, msg_leaf_index: Field) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself TODO(alvaro): Make l1l2msg leaf index a u64 upstream\n unsafe {\n avm::l1_to_l2_msg_exists(msg_hash, msg_leaf_index as u64)\n }\n }\n\n /// Returns `true` if an `unsiloed_nullifier` has been emitted by `contract_address`.\n ///\n /// Note that unsiloed nullifiers are not the actual values stored in the nullifier tree: they are first siloed via\n /// [`crate::hash::compute_siloed_nullifier`] with the emitting contract's address.\n ///\n /// ## Use Cases\n ///\n /// Nullifiers are typically used as a _privacy-preserving_ record of a one-time action, but they can also be used\n /// to efficiently record _public_ one-time actions as well. This is cheaper than using public storage, and has the\n /// added benefit of the nullifier being emittable from a private function.\n ///\n /// An example is to check whether a contract has been published: we emit a nullifier that is deterministic and\n /// which has a _public_ preimage.\n ///\n /// ## Public vs Private\n ///\n /// In general, one should not attempt to prove nullifier non-existence in private, as that will not consider the\n /// possibility of the nullifier having been emitted in any transaction between the anchor block and the inclusion\n /// block. Private functions instead prove existence via\n /// [`crate::context::PrivateContext::assert_nullifier_exists`]\n /// and 'prove' non-existence by _emitting_ the nullifer, which would cause the transaction to fail if the\n /// nullifier existed.\n ///\n /// This is not the case in public functions, which **do** have access to the tip of the blockchain and so can\n /// reliably prove whether a nullifier exists or not.\n ///\n /// ## Safety\n ///\n /// While it is safe to rely on this function's return value to determine if a nullifier exists or not, it is often\n /// **not** safe to infer additional information from that. In particular, it is **unsafe** to infer that the\n /// existence of a nullifier emitted from a private function implies that all other side-effects of said private\n /// execution have been completed, more concretely that any enqueued public calls have been executed.\n ///\n /// For example, if a function in contract `A` privately emits nullifier `X` and then enqueues public function `Y`,\n /// then it is **unsafe** for a contract `B` to infer that `Y` has alredy executed simply because `X` exists.\n ///\n /// This is because **all** private transaction effects are committed _before_ enqueued public functions are run\n /// (in\n /// order to not reveal detailed timing information about the transaction), so it is possible to observe a\n /// nullifier that was emitted alongside the enqueuing of a public call **before** said call has been completed.\n ///\n /// ## Cost\n ///\n /// This emits the `CHECKNULLIFIEREXISTS` opcode, which conceptually performs a merkle inclusion proof on the\n /// nullifier tree (both when the nullifier exists and when it doesn't).\n pub fn nullifier_exists_unsafe(_self: Self, unsiloed_nullifier: Field, contract_address: AztecAddress) -> bool {\n let siloed_nullifier = compute_siloed_nullifier(contract_address, unsiloed_nullifier);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::nullifier_exists(siloed_nullifier)\n }\n }\n\n /// Consumes a message sent from Ethereum (L1) to Aztec (L2) -- effectively marking it as \"read\".\n ///\n /// Use this function if you only want the message to ever be \"referred to\" once. Once consumed using this method,\n /// the message cannot be consumed again, because a nullifier is emitted. If your use case wants for the message to\n /// be read unlimited times, then you can always read any historic message from the L1-to-L2 messages tree, using\n /// the `l1_to_l2_msg_exists` method. Messages never technically get deleted from that tree.\n ///\n /// The message will first be inserted into an Aztec \"Inbox\" smart contract on L1. It will not be available for\n /// consumption immediately. Messages get copied-over from the L1 Inbox to L2 by the next Proposer in batches. So\n /// you will need to wait until the messages are copied before you can consume them.\n ///\n /// # Arguments\n /// * `content` - The message content that was sent from L1\n /// * `secret` - Secret value used for message privacy (if needed)\n /// * `sender` - Ethereum address that sent the message\n /// * `leaf_index` - Index of the message in the L1-to-L2 message tree\n ///\n /// # Advanced\n /// * Validates message existence in the L1-to-L2 message tree\n /// * Prevents double-consumption by emitting a nullifier\n /// * Message hash is computed from all parameters + chain context\n /// * Will revert if message doesn't exist or was already consumed\n ///\n pub fn consume_l1_to_l2_message(self: Self, content: Field, secret: Field, sender: EthAddress, leaf_index: Field) {\n let secret_hash = compute_secret_hash(secret);\n let message_hash = compute_l1_to_l2_message_hash(\n sender,\n self.chain_id(),\n /*recipient=*/\n self.this_address(),\n self.version(),\n content,\n secret_hash,\n leaf_index,\n );\n let nullifier = compute_l1_to_l2_message_nullifier(message_hash, secret);\n\n assert(!self.nullifier_exists_unsafe(nullifier, self.this_address()), \"L1-to-L2 message is already nullified\");\n assert(self.l1_to_l2_msg_exists(message_hash, leaf_index), \"Tried to consume nonexistent L1-to-L2 message\");\n\n self.push_nullifier(nullifier);\n }\n\n /// Sends an \"L2 -> L1 message\" from this function (Aztec, L2) to a smart contract on Ethereum (L1). L1 contracts\n /// which are designed to send/receive messages to/from Aztec are called \"Portal Contracts\".\n ///\n /// Common use cases include withdrawals, cross-chain asset transfers, and triggering L1 actions based on L2 state\n /// changes.\n ///\n /// The message will be inserted into an Aztec \"Outbox\" contract on L1, when this transaction's block is proposed\n /// to L1. Sending the message will not result in any immediate state changes in the target portal contract. The\n /// message will need to be manually consumed from the Outbox through a separate Ethereum transaction: a user will\n /// need to call a function of the portal contract -- a function specifically designed to make a call to the Outbox\n /// to consume the message. The message will only be available for consumption once the _epoch_ proof has been\n /// submitted. Given that there are multiple Aztec blocks within an epoch, it might take some time for this epoch\n /// proof to be submitted -- especially if the block was near the start of an epoch.\n ///\n /// # Arguments\n /// * `recipient` - Ethereum address that will receive the message\n /// * `content` - Message content (32 bytes as a Field element)\n ///\n pub fn message_portal(_self: Self, recipient: EthAddress, content: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::send_l2_to_l1_msg(recipient, content) };\n }\n\n /// Calls a public function on another contract.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Arguments to pass to the function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn call_public_function(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Makes a read-only call to a public function on another contract.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be staticcalls.\n ///\n /// Useful for querying data from other contracts safely.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Array of arguments to pass to the called function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn static_call_public_function(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call_static(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Adds a new note hash to the Aztec blockchain's global Note Hash Tree.\n ///\n /// Notes are ordinarily constructed and emitted by _private_ functions, to ensure that both the content of the\n /// note, and the contract that emitted the note, stay private.\n ///\n /// There are however some useful patterns whereby a note needs to contain _public_ data. The ability to push a new\n /// note_hash from a _public_ function means that notes can be injected with public data immediately -- as soon as\n /// the public value is known. The slower alternative would be to submit a follow-up transaction so that a private\n /// function can inject the data. Both are possible on Aztec.\n ///\n /// Search \"Partial Note\" for a very common pattern which enables a note to be \"partially\" populated with some data\n /// in a _private_ function, and then later \"completed\" with some data in a public function.\n ///\n /// # Arguments\n /// * `note_hash` - The hash of the note to add to the tree\n ///\n /// # Advanced\n /// * The note hash will be siloed with the contract address by the protocol\n ///\n pub fn push_note_hash(_self: Self, note_hash: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_note_hash(note_hash) };\n }\n\n /// Creates a new [nullifier](crate::nullifier).\n ///\n /// While nullifiers are primarily intended as a _privacy-preserving_ record of a one-time action, they can also\n /// be used to efficiently record _public_ one-time actions. This function allows creating nullifiers from public\n /// contract functions, which behave just like those created from private functions.\n ///\n /// ## Safety\n ///\n /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state.\n ///\n /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that\n /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a\n /// variable as initialized). Note nullifiers should only be created via\n /// [`crate::context::PrivateContext::push_nullifier_for_note_hash`].\n ///\n /// ## Advanced\n ///\n /// The raw `nullifier` is not what is inserted into the Aztec state tree: it will be first siloed by contract\n /// address via [`crate::protocol::hash::compute_siloed_nullifier`] in order to prevent accidental or malicious\n /// interference of nullifiers from different contracts.\n pub fn push_nullifier(_self: Self, nullifier: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_nullifier(nullifier) };\n }\n\n /// Returns the address of the current contract being executed.\n ///\n /// This is equivalent to `address(this)` in Solidity (hence the name). Use this to identify the current contract's\n /// address, commonly needed for access control or when interacting with other contracts.\n ///\n /// # Returns\n /// * `AztecAddress` - The contract address of the current function being executed.\n ///\n pub fn this_address(_self: Self) -> AztecAddress {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::address()\n }\n }\n\n /// Returns the contract address that initiated this function call.\n ///\n /// This is similar to `msg.sender` in Solidity (hence the name).\n ///\n /// Important Note: If the calling function is a _private_ function, then it had the option of hiding its address\n /// when enqueuing this public function call. In such cases, this method will return `Option::none`.\n /// If the calling function is a _public_ function, it will always return an `Option::some` (i.e. a\n /// non-null value).\n ///\n /// # Returns\n /// * `Option` - The address of the smart contract that called this function (be it an app contract\n /// or a user's account contract).\n ///\n /// # Advanced\n /// * Value is provided by the AVM sender opcode\n /// * In nested calls, this is the immediate caller, not the original transaction sender\n ///\n pub fn maybe_msg_sender(_self: Self) -> Option {\n // Safety: AVM opcodes are constrained by the AVM itself\n let maybe_msg_sender = unsafe { avm::sender() };\n if maybe_msg_sender == NULL_MSG_SENDER_CONTRACT_ADDRESS {\n Option::none()\n } else {\n Option::some(maybe_msg_sender)\n }\n }\n\n /// Returns the function selector of the currently-executing function.\n ///\n /// This is similar to `msg.sig` in Solidity, returning the first 4 bytes of the function signature.\n ///\n /// # Returns\n /// * `FunctionSelector` - The 4-byte function identifier\n ///\n /// # Advanced\n /// * Extracted from the first element of calldata\n /// * Used internally for function dispatch in the AVM\n ///\n pub fn selector(_self: Self) -> FunctionSelector {\n // The selector is the first element of the calldata when calling a public function through dispatch.\n // Safety: AVM opcodes are constrained by the AVM itself.\n let raw_selector: [Field; 1] = unsafe { avm::calldata_copy(0, 1) };\n FunctionSelector::from_field(raw_selector[0])\n }\n\n /// Returns the hash of the arguments passed to the current function.\n ///\n /// Very low-level function: The #[external(\"public\")] macro uses this internally. Smart contract developers\n /// typically won't need to access this directly as arguments are automatically made available.\n ///\n /// # Returns\n /// * `Field` - Hash of the function arguments\n ///\n pub fn get_args_hash(mut self) -> Field {\n if !self.args_hash.is_some() {\n self.args_hash = Option::some((self.compute_args_hash)());\n }\n\n self.args_hash.unwrap_unchecked()\n }\n\n /// Returns the \"transaction fee\" for the current transaction. This is the final tx fee that will be deducted from\n /// the fee_payer's \"fee-juice\" balance (in the protocol's Base Rollup circuit).\n ///\n /// # Returns\n /// * `Field` - The actual, final cost of the transaction, taking into account: the actual gas used during the\n /// setup and app-logic phases, and the fixed amount of gas that's been allocated by the user for the teardown\n /// phase. I.e. effectiveL2FeePerGas * l2GasUsed + effectiveDAFeePerGas * daGasUsed\n ///\n /// This will return `0` during the \"setup\" and \"app-logic\" phases of tx execution (because the final tx fee is not\n /// known at that time). This will only return a nonzero value during the \"teardown\" phase of execution, where the\n /// final tx fee can actually be computed.\n ///\n /// Regardless of _when_ this function is called during the teardown phase, it will always return the same final tx\n /// fee value. The teardown phase does not consume a variable amount of gas: it always consumes a pre-allocated\n /// amount of gas, as specified by the user when they generate their tx.\n ///\n pub fn transaction_fee(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::transaction_fee()\n }\n }\n\n /// Returns the chain ID of the current network.\n ///\n /// This is similar to `block.chainid` in Solidity. Returns the unique identifier for the blockchain network this\n /// transaction is executing on.\n ///\n /// Helps prevent cross-chain replay attacks. Useful if implementing multi-chain contract logic.\n ///\n /// # Returns\n /// * `Field` - The chain ID as a field element\n ///\n pub fn chain_id(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::chain_id()\n }\n }\n\n /// Returns the Aztec protocol version that this transaction is executing under. Different versions may have\n /// different rules, opcodes, or cryptographic primitives.\n ///\n /// This is similar to how Ethereum has different EVM versions.\n ///\n /// Useful for forward/backward compatibility checks\n ///\n /// Not to be confused with contract versions; this is the protocol version.\n ///\n /// # Returns\n /// * `Field` - The protocol version as a field element\n ///\n pub fn version(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::version()\n }\n }\n /// Returns the current block number.\n ///\n /// This is similar to `block.number` in Solidity.\n ///\n /// Note: the current block number is only available within a public function (as opposed to a private function).\n ///\n /// Note: the time intervals between blocks should not be relied upon as being consistent:\n /// - Timestamps of blocks fall within a range, rather than at exact regular intervals.\n /// - Slots can be missed.\n /// - Protocol upgrades can completely change the intervals between blocks (and indeed the current roadmap plans to\n /// reduce the time between blocks, eventually). Use `context.timestamp()` for more-reliable time-based logic.\n ///\n /// # Returns\n /// * `u32` - The current block number\n ///\n pub fn block_number(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::block_number()\n }\n }\n\n /// Returns the timestamp of the current block.\n ///\n /// This is similar to `block.timestamp` in Solidity.\n ///\n /// All functions of all transactions in a block share the exact same timestamp (even though technically each\n /// transaction is executed one-after-the-other).\n ///\n /// Important note: Timestamps of Aztec blocks are not at reliably-fixed intervals. The proposer of the block has\n /// some flexibility to choose a timestamp which is in a valid _range_: Obviously the timestamp of this block must\n /// be strictly greater than that of the previous block, and must must be less than the timestamp of whichever\n /// ethereum block the aztec block is proposed to. Furthermore, if the timestamp is not deemed close enough to the\n /// actual current time, the committee of validators will not attest to the block.\n ///\n /// # Returns\n /// * `u64` - Unix timestamp in seconds\n ///\n pub fn timestamp(_self: Self) -> u64 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::timestamp()\n }\n }\n\n /// Returns the fee per unit of L2 gas for this transaction (aka the \"L2 gas price\"), as chosen by the user.\n ///\n /// L2 gas covers the cost of executing public functions and handling side-effects within the AVM.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of L2 gas\n ///\n /// Wallet developers should be mindful that the choice of gas price (which is publicly visible) can leak\n /// information about the user, e.g.:\n /// - which wallet software the user is using;\n /// - the amount of time which has elapsed from the time the user's wallet chose a gas price (at the going rate),\n /// to the time of tx submission. This can give clues about the proving time, and hence the nature of the tx.\n /// - the urgency of the transaction (which is kind of unavoidable, if the tx is indeed urgent).\n /// - the wealth of the user.\n /// - the exact user (if the gas price is explicitly chosen by the user to be some unique number like 0.123456789,\n /// or their favorite number). Wallet devs might wish to consider fuzzing the choice of gas price.\n ///\n pub fn min_fee_per_l2_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_l2_gas()\n }\n }\n\n /// Returns the fee per unit of DA (Data Availability) gas (aka the \"DA gas price\").\n ///\n /// DA gas covers the cost of making transaction data available on L1.\n ///\n /// See the warning in `min_fee_per_l2_gas` for how gas prices can be leaky.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of DA gas\n ///\n pub fn min_fee_per_da_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_da_gas()\n }\n }\n\n /// Returns the remaining L2 gas available for this transaction.\n ///\n /// Different AVM opcodes consume different amounts of gas.\n ///\n /// # Returns\n /// * `u32` - Remaining L2 gas units\n ///\n pub fn l2_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::l2_gas_left()\n }\n }\n\n /// Returns the remaining DA (Data Availability) gas available for this transaction.\n ///\n /// DA gas is consumed when emitting data that needs to be made available on L1, such as public logs or state\n /// updates. All of the side-effects from the private part of the tx also consume DA gas before execution of any\n /// public functions even begins.\n ///\n /// # Returns\n /// * `u32` - Remaining DA gas units\n ///\n pub fn da_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::da_gas_left()\n }\n }\n\n /// Checks if the current execution is within a staticcall context, where no state changes or logs are allowed to\n /// be emitted (by this function or any nested function calls).\n ///\n /// # Returns\n /// * `bool` - True if in staticcall context, false otherwise\n ///\n pub fn is_static_call(_self: Self) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::is_static_call()\n }\n }\n\n /// Reads raw field values from public storage. Reads N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to read from\n ///\n /// # Returns\n /// * `[Field; N]` - Array of N field values from consecutive storage slots\n ///\n /// # Generic Parameters\n /// * `N` - the number of consecutive slots to return, starting from the `storage_slot`.\n ///\n pub fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n let mut out = [0; N];\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n out[i] = unsafe { avm::storage_read(storage_slot + i as Field, self.this_address().to_field()) };\n }\n out\n }\n\n /// Reads a typed value from public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to read from\n ///\n /// # Returns\n /// * `T` - The deserialized value from storage\n ///\n /// # Generic Parameters\n /// * `T` - The type that the caller expects to read from the `storage_slot`.\n ///\n pub fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n\n /// Writes raw field values to public storage. Writes to N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// Public storage writes take effect immediately.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to write to\n /// * `values` - Array of N Fields to write to storage\n ///\n pub fn raw_storage_write(_self: Self, storage_slot: Field, values: [Field; N]) {\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::storage_write(storage_slot + i as Field, values[i]) };\n }\n }\n\n /// Writes a typed value to public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to write to\n /// * `value` - The typed value to write to storage\n ///\n /// # Generic Parameters\n /// * `T` - The type to write to storage.\n ///\n pub fn storage_write(self, storage_slot: Field, value: T)\n where\n T: Packable,\n {\n self.raw_storage_write(storage_slot, value.pack());\n }\n}\n\nimpl Empty for PublicContext {\n fn empty() -> Self {\n PublicContext::new(|| 0)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/public_context.nr","function_locations":[{"start":3353,"name":"::eq"},{"start":3938,"name":"PublicContext::new"},{"start":4887,"name":"PublicContext::emit_public_log_unsafe"},{"start":5811,"name":"PublicContext::note_hash_exists"},{"start":6824,"name":"PublicContext::l1_to_l2_msg_exists"},{"start":10039,"name":"PublicContext::nullifier_exists_unsafe"},{"start":11904,"name":"PublicContext::consume_l1_to_l2_message"},{"start":14021,"name":"PublicContext::message_portal"},{"start":14911,"name":"PublicContext::call_public_function"},{"start":16543,"name":"PublicContext::static_call_public_function"},{"start":18327,"name":"PublicContext::push_note_hash"},{"start":19766,"name":"PublicContext::push_nullifier"},{"start":20356,"name":"PublicContext::this_address"},{"start":21451,"name":"PublicContext::maybe_msg_sender"},{"start":22223,"name":"PublicContext::selector"},{"start":22962,"name":"PublicContext::get_args_hash"},{"start":24354,"name":"PublicContext::transaction_fee"},{"start":24943,"name":"PublicContext::chain_id"},{"start":25613,"name":"PublicContext::version"},{"start":26553,"name":"PublicContext::block_number"},{"start":27665,"name":"PublicContext::timestamp"},{"start":28946,"name":"PublicContext::min_fee_per_l2_gas"},{"start":29473,"name":"PublicContext::min_fee_per_da_gas"},{"start":29871,"name":"PublicContext::l2_gas_left"},{"start":30487,"name":"PublicContext::da_gas_left"},{"start":30952,"name":"PublicContext::is_static_call"},{"start":31794,"name":"PublicContext::raw_storage_read"},{"start":32652,"name":"PublicContext::storage_read"},{"start":33320,"name":"PublicContext::raw_storage_write"},{"start":34054,"name":"PublicContext::storage_write"},{"start":34179,"name":"::empty"}]},"70":{"source":"use crate::oracle::{execution::get_utility_context, storage::storage_read};\nuse crate::protocol::{abis::block_header::BlockHeader, address::AztecAddress, traits::Packable};\n\n// If you'll modify this struct don't forget to update utility_context.ts as well.\npub struct UtilityContext {\n block_header: BlockHeader,\n contract_address: AztecAddress,\n}\n\nimpl UtilityContext {\n pub unconstrained fn new() -> Self {\n get_utility_context()\n }\n\n pub unconstrained fn at(contract_address: AztecAddress) -> Self {\n // We get a context with default contract address, and then we construct the final context with the provided\n // contract address.\n let default_context = get_utility_context();\n\n Self { block_header: default_context.block_header, contract_address }\n }\n\n pub fn block_header(self) -> BlockHeader {\n self.block_header\n }\n\n pub fn block_number(self) -> u32 {\n self.block_header.block_number()\n }\n\n pub fn timestamp(self) -> u64 {\n self.block_header.timestamp()\n }\n\n pub fn this_address(self) -> AztecAddress {\n self.contract_address\n }\n\n pub fn version(self) -> Field {\n self.block_header.version()\n }\n\n pub fn chain_id(self) -> Field {\n self.block_header.chain_id()\n }\n\n pub unconstrained fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n storage_read(self.block_header, self.this_address(), storage_slot)\n }\n\n pub unconstrained fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/utility_context.nr","function_locations":[{"start":416,"name":"UtilityContext::new"},{"start":523,"name":"UtilityContext::at"},{"start":855,"name":"UtilityContext::block_header"},{"start":927,"name":"UtilityContext::block_number"},{"start":1011,"name":"UtilityContext::timestamp"},{"start":1104,"name":"UtilityContext::this_address"},{"start":1177,"name":"UtilityContext::version"},{"start":1257,"name":"UtilityContext::chain_id"},{"start":1404,"name":"UtilityContext::raw_storage_read"},{"start":1596,"name":"UtilityContext::storage_read"}]},"72":{"source":"//! The `self` contract value for public execution contexts.\n\nuse crate::{\n context::{calls::{PublicCall, PublicStaticCall}, PublicContext},\n event::{event_emission::emit_event_in_public, event_interface::EventInterface},\n};\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Core interface for interacting with aztec-nr contract features in public execution contexts.\n///\n/// This struct is automatically injected into every [`external`](crate::macros::functions::external) and\n/// [`internal`](crate::macros::functions::internal) contract function marked with `\"public\"` by the Aztec macro\n/// system and is accessible through the `self` variable.\n///\n/// ## Type Parameters\n///\n/// - `Storage`: The contract's storage struct (defined with [`storage`](crate::macros::storage::storage), or `()` if\n/// the contract has no storage\n/// - `CallSelf`: Macro-generated type for calling contract's own non-view functions\n/// - `CallSelfStatic`: Macro-generated type for calling contract's own view functions\n/// - `CallInternal`: Macro-generated type for calling internal functions\npub struct ContractSelfPublic {\n /// The address of this contract\n pub address: AztecAddress,\n\n /// The contract's storage instance, representing the struct to which the\n /// [`storage`](crate::macros::storage::storage) macro was applied in your contract. If the contract has no\n /// storage, the type of this will be `()`.\n ///\n /// This storage instance is specialized for the current execution context (public) and\n /// provides access to the contract's state variables.\n ///\n /// ## Developer Note\n ///\n /// If you've arrived here while trying to access your contract's storage while the `Storage` generic type is set\n /// to unit type `()`, it means you haven't yet defined a Storage struct using the\n /// [`storage`](crate::macros::storage::storage) macro in your contract. For guidance on setting this up, please\n /// refer to our docs: https://docs.aztec.network/developers/docs/guides/smart_contracts/storage\n pub storage: Storage,\n\n /// The public execution context.\n pub context: PublicContext,\n\n /// Provides type-safe methods for calling this contract's own non-view functions.\n ///\n /// Example API:\n /// ```noir\n /// self.call_self.some_public_function(args)\n /// ```\n pub call_self: CallSelf,\n\n /// Provides type-safe methods for calling this contract's own view functions.\n ///\n /// Example API:\n /// ```noir\n /// self.call_self_static.some_view_function(args)\n /// ```\n pub call_self_static: CallSelfStatic,\n\n /// Provides type-safe methods for calling internal functions.\n ///\n /// Example API:\n /// ```noir\n /// self.internal.some_internal_function(args)\n /// ```\n pub internal: CallInternal,\n}\n\nimpl ContractSelfPublic {\n /// Creates a new `ContractSelfPublic` instance for a public function.\n ///\n /// This constructor is called automatically by the macro system and should not be called directly.\n pub fn new(\n context: PublicContext,\n storage: Storage,\n call_self: CallSelf,\n call_self_static: CallSelfStatic,\n internal: CallInternal,\n ) -> Self {\n Self { context, storage, address: context.this_address(), call_self, call_self_static, internal }\n }\n\n /// The address of the contract address that made this function call.\n ///\n /// This is similar to Solidity's `msg.sender` value.\n ///\n /// ## Incognito Calls\n ///\n /// Contracts can call public functions from private ones hiding their identity (see\n ///\n /// [`ContractSelfPrivate::enqueue_incognito`](crate::contract_self::ContractSelfPrivate::enqueue_incognito)).\n /// This function reverts when executed in such a context.\n ///\n /// If you need to handle these cases, use [`PublicContext::maybe_msg_sender`].\n pub fn msg_sender(self: Self) -> AztecAddress {\n self.context.maybe_msg_sender().unwrap()\n }\n\n /// Emits an event publicly.\n ///\n /// Public events are emitted as plaintext and are therefore visible to everyone. This is is the same as Solidity\n /// events on EVM chains.\n ///\n /// Unlike private events, they don't require delivery of an event message.\n ///\n /// # Example\n /// ```noir\n /// #[event]\n /// struct Update { value: Field }\n ///\n /// #[external(\"public\")]\n /// fn publish_update(value: Field) {\n /// self.emit(Update { value });\n /// }\n /// ```\n ///\n /// # Cost\n ///\n /// Public event emission is achieved by emitting public transaction logs. A total of `N+1` fields are emitted,\n /// where `N` is the serialization length of the event.\n pub fn emit(&mut self, event: Event)\n where\n Event: EventInterface + Serialize,\n {\n emit_event_in_public(self.context, event);\n }\n\n /// Makes a public contract call.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `call` - The object representing the public function to invoke.\n ///\n /// # Returns\n /// * `T` - Whatever data the called function has returned.\n ///\n /// # Example\n /// ```noir\n /// self.call(Token::at(address).transfer_in_public(recipient, amount));\n /// ```\n ///\n pub unconstrained fn call(self, call: PublicCall) -> T\n where\n T: Deserialize,\n {\n call.call(self.context)\n }\n\n /// Makes a public read-only contract call.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be static calls.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `call` - The object representing the read-only public function to invoke.\n ///\n /// # Returns\n /// * `T` - Whatever data the called function has returned.\n ///\n /// # Example\n /// ```noir\n /// self.view(Token::at(address).balance_of_public(recipient));\n /// ```\n ///\n pub unconstrained fn view(self, call: PublicStaticCall) -> T\n where\n T: Deserialize,\n {\n call.view(self.context)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/contract_self/contract_self_public.nr","function_locations":[{"start":3401,"name":"ContractSelfPublic::new"},{"start":4116,"name":"ContractSelfPublic::msg_sender"},{"start":5004,"name":"ContractSelfPublic::emit"},{"start":5645,"name":"ContractSelfPublic::call"},{"start":6466,"name":"ContractSelfPublic::view"}]},"75":{"source":"use crate::oracle::ephemeral;\nuse crate::protocol::traits::{Deserialize, Serialize};\n\n/// A dynamically sized array that exists only during a single contract call frame.\n///\n/// Ephemeral arrays are backed by in-memory storage on the PXE side rather than a persistent database. Each contract\n/// call frame gets its own isolated slot space of ephemeral arrays. Child simulations cannot see the parent's\n/// ephemeral arrays, and vice versa.\n///\n/// Each logical array operation (push, pop, get, etc.) is a single oracle call, making ephemeral arrays significantly\n/// cheaper than capsule arrays.\n///\n/// ## Use Cases\n///\n/// Ephemeral arrays are designed for passing data between PXE (TypeScript) and contracts (Noir) during simulation,\n/// for example, note validation requests or event validation responses. This data type is appropriate for data that\n/// is not supposed to be persisted.\n///\n/// For data that needs to persist across simulations, contract calls, etc, use\n/// [`CapsuleArray`](crate::capsules::CapsuleArray) instead.\npub struct EphemeralArray {\n pub slot: Field,\n}\n\nimpl EphemeralArray {\n /// Returns a handle to an ephemeral array at the given slot, which may already contain data (e.g. populated\n /// by an oracle).\n pub unconstrained fn at(slot: Field) -> Self {\n Self { slot }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n ephemeral::len_oracle(self.slot)\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n let _ = ephemeral::push_oracle(self.slot, serialized);\n }\n\n /// Removes and returns the last element. Panics if the array is empty.\n pub unconstrained fn pop(self) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::pop_oracle(self.slot);\n Deserialize::deserialize(serialized)\n }\n\n /// Retrieves the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::get_oracle(self.slot, index);\n Deserialize::deserialize(serialized)\n }\n\n /// Overwrites the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn set(self, index: u32, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n ephemeral::set_oracle(self.slot, index, serialized);\n }\n\n /// Removes the element at `index`, shifting subsequent elements backward. Panics if out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n ephemeral::remove_oracle(self.slot, index);\n }\n\n /// Removes all elements from the array and returns self for chaining (e.g. `EphemeralArray::at(slot).clear()`\n /// to get a guaranteed-empty array at a given slot).\n pub unconstrained fn clear(self) -> Self {\n ephemeral::clear_oracle(self.slot);\n self\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. Iteration proceeds\n /// backwards so that it is safe to remove the current element (and only the current element) inside the\n /// callback.\n ///\n /// It is **not** safe to push new elements from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use crate::test::mocks::MockStruct;\n use super::EphemeralArray;\n\n global SLOT: Field = 1230;\n global OTHER_SLOT: Field = 5670;\n\n #[test]\n unconstrained fn empty_array() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn empty_array_read() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.get(0);\n });\n }\n\n #[test(should_fail_with = \"is empty\")]\n unconstrained fn empty_array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.pop();\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn read_past_len() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.push(10);\n\n let popped: Field = array.pop();\n assert_eq(popped, 10);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test]\n unconstrained fn array_set() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.set(0, 99);\n assert_eq(array.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.remove(0);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_slots_are_isolated() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array_a = EphemeralArray::at(SLOT);\n let array_b = EphemeralArray::at(OTHER_SLOT);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn works_with_multi_field_type() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n\n let a = MockStruct::new(5, 6);\n let b = MockStruct::new(7, 8);\n array.push(a);\n array.push(b);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), a);\n assert_eq(array.get(1), b);\n\n let popped: MockStruct = array.pop();\n assert_eq(popped, b);\n assert_eq(array.len(), 1);\n });\n }\n\n #[test]\n unconstrained fn clear_returns_self() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(array.len(), 0);\n\n array.push(42);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 42);\n });\n }\n\n #[test]\n unconstrained fn clear_wipes_previous_data() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n array.push(1);\n array.push(2);\n array.push(3);\n assert_eq(array.len(), 3);\n\n // Clear the same slot, previous data should be gone.\n let fresh: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(fresh.len(), 0);\n fresh.push(4);\n assert_eq(fresh.get(0), 4);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/ephemeral/mod.nr","function_locations":[{"start":1305,"name":"EphemeralArray::at"},{"start":1438,"name":"EphemeralArray::len"},{"start":1618,"name":"EphemeralArray::push"},{"start":1888,"name":"EphemeralArray::pop"},{"start":2176,"name":"EphemeralArray::get"},{"start":2475,"name":"EphemeralArray::set"},{"start":2743,"name":"EphemeralArray::remove"},{"start":3022,"name":"EphemeralArray::clear"},{"start":3593,"name":"EphemeralArray::for_each"},{"start":3983,"name":"test::empty_array"},{"start":4280,"name":"test::empty_array_read"},{"start":4550,"name":"test::empty_array_pop"},{"start":4783,"name":"test::array_push"},{"start":5122,"name":"test::read_past_len"},{"start":5376,"name":"test::array_pop"},{"start":5783,"name":"test::array_set"},{"start":6081,"name":"test::array_remove_last"},{"start":6376,"name":"test::array_remove_some"},{"start":6847,"name":"test::array_remove_all"},{"start":7273,"name":"test::for_each_called_with_all_elements"},{"start":8009,"name":"test::for_each_remove_some"},{"start":8561,"name":"test::for_each_remove_all"},{"start":8960,"name":"test::different_slots_are_isolated"},{"start":9534,"name":"test::works_with_multi_field_type"},{"start":10148,"name":"test::clear_returns_self"},{"start":10535,"name":"test::clear_wipes_previous_data"}]},"77":{"source":"use crate::{event::EventSelector, messages::logs::event::MAX_EVENT_SERIALIZED_LEN};\nuse crate::protocol::{\n constants::DOM_SEP__EVENT_COMMITMENT,\n hash::{poseidon2_hash_with_separator, poseidon2_hash_with_separator_bounded_vec},\n traits::{Serialize, ToField},\n};\n\npub trait EventInterface {\n fn get_event_type_id() -> EventSelector;\n}\n\n/// A private event's commitment is a value stored on-chain which is used to verify that the event was indeed emitted.\n///\n/// It requires a `randomness` value that must be produced alongside the event in order to perform said validation.\n/// This random value prevents attacks in which someone guesses plausible events (e.g. 'Alice transfers to Bob an\n/// amount of 10'), since they will not be able to test for existence of their guessed events without brute-forcing the\n/// entire `Field` space by guessing `randomness` values.\npub fn compute_private_event_commitment(event: Event, randomness: Field) -> Field\nwhere\n Event: EventInterface + Serialize,\n{\n poseidon2_hash_with_separator(\n [randomness, Event::get_event_type_id().to_field()].concat(event.serialize()),\n DOM_SEP__EVENT_COMMITMENT,\n )\n}\n\n/// Unconstrained variant of [`compute_private_event_commitment`] which takes the event in serialized form.\n///\n/// This function is unconstrained as the mechanism it uses to compute the commitment would be very inefficient in a\n/// constrained environment (due to the hashing of a dynamically sized array). This is not an issue as it is typically\n/// invoked when processing event messages, which is an unconstrained operation.\npub unconstrained fn compute_private_serialized_event_commitment(\n serialized_event: BoundedVec,\n randomness: Field,\n event_type_id: Field,\n) -> Field {\n let mut commitment_preimage =\n BoundedVec::<_, 2 + MAX_EVENT_SERIALIZED_LEN>::from_array([randomness, event_type_id]);\n commitment_preimage.extend_from_bounded_vec(serialized_event);\n\n poseidon2_hash_with_separator_bounded_vec(commitment_preimage, DOM_SEP__EVENT_COMMITMENT)\n}\n\nmod test {\n use crate::event::event_interface::{\n compute_private_event_commitment, compute_private_serialized_event_commitment, EventInterface,\n };\n use crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN;\n use crate::protocol::traits::{Serialize, ToField};\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn max_size_serialized_event_commitment() {\n let serialized_event = BoundedVec::from_array([0; MAX_EVENT_SERIALIZED_LEN]);\n let _ = compute_private_serialized_event_commitment(serialized_event, 0, 0);\n }\n\n #[test]\n unconstrained fn event_commitment_equivalence() {\n let event = MockEvent::new(VALUE).build_event();\n\n assert_eq(\n compute_private_event_commitment(event, RANDOMNESS),\n compute_private_serialized_event_commitment(\n BoundedVec::from_array(event.serialize()),\n RANDOMNESS,\n MockEvent::get_event_type_id().to_field(),\n ),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_interface.nr","function_locations":[{"start":1013,"name":"compute_private_event_commitment"},{"start":1803,"name":"compute_private_serialized_event_commitment"},{"start":2570,"name":"test::max_size_serialized_event_commitment"},{"start":2814,"name":"test::event_commitment_equivalence"}]},"79":{"source":"use crate::protocol::{hash::poseidon2_hash_bytes, traits::{Deserialize, Empty, FromField, Serialize, ToField}};\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct EventSelector {\n // Low 32 bits of the poseidon2 hash of the event signature.\n inner: u32,\n}\n\nimpl FromField for EventSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for EventSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for EventSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl EventSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n EventSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_selector.nr","function_locations":[{"start":337,"name":"::from_field"},{"start":449,"name":"::to_field"},{"start":542,"name":"::empty"},{"start":647,"name":"EventSelector::from_u32"},{"start":751,"name":"EventSelector::from_signature"},{"start":985,"name":"EventSelector::zero"}]},"81":{"source":"//! Aztec hash functions.\n\nuse crate::protocol::{\n address::{AztecAddress, EthAddress},\n constants::{\n DOM_SEP__FUNCTION_ARGS, DOM_SEP__MESSAGE_NULLIFIER, DOM_SEP__PUBLIC_BYTECODE, DOM_SEP__PUBLIC_CALLDATA,\n DOM_SEP__SECRET_HASH, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS,\n },\n hash::{poseidon2_hash_subarray, poseidon2_hash_with_separator, sha256_to_field},\n traits::ToField,\n};\n\npub use crate::protocol::hash::compute_siloed_nullifier;\n\npub fn compute_secret_hash(secret: Field) -> Field {\n poseidon2_hash_with_separator([secret], DOM_SEP__SECRET_HASH)\n}\n\npub fn compute_l1_to_l2_message_hash(\n sender: EthAddress,\n chain_id: Field,\n recipient: AztecAddress,\n version: Field,\n content: Field,\n secret_hash: Field,\n leaf_index: Field,\n) -> Field {\n let mut hash_bytes = [0 as u8; 224];\n let sender_bytes: [u8; 32] = sender.to_field().to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n let recipient_bytes: [u8; 32] = recipient.to_field().to_be_bytes();\n let version_bytes: [u8; 32] = version.to_be_bytes();\n let content_bytes: [u8; 32] = content.to_be_bytes();\n let secret_hash_bytes: [u8; 32] = secret_hash.to_be_bytes();\n let leaf_index_bytes: [u8; 32] = leaf_index.to_be_bytes();\n\n for i in 0..32 {\n hash_bytes[i] = sender_bytes[i];\n hash_bytes[i + 32] = chain_id_bytes[i];\n hash_bytes[i + 64] = recipient_bytes[i];\n hash_bytes[i + 96] = version_bytes[i];\n hash_bytes[i + 128] = content_bytes[i];\n hash_bytes[i + 160] = secret_hash_bytes[i];\n hash_bytes[i + 192] = leaf_index_bytes[i];\n }\n\n sha256_to_field(hash_bytes)\n}\n\n// The nullifier of a l1 to l2 message is the hash of the message salted with the secret\npub fn compute_l1_to_l2_message_nullifier(message_hash: Field, secret: Field) -> Field {\n poseidon2_hash_with_separator([message_hash, secret], DOM_SEP__MESSAGE_NULLIFIER)\n}\n\n// Computes the hash of input arguments or return values for private functions, or for authwit creation.\npub fn hash_args(args: [Field; N]) -> Field {\n if args.len() == 0 {\n 0\n } else {\n poseidon2_hash_with_separator(args, DOM_SEP__FUNCTION_ARGS)\n }\n}\n\n// Computes the hash of calldata for public functions.\npub fn hash_calldata_array(calldata: [Field; N]) -> Field {\n poseidon2_hash_with_separator(calldata, DOM_SEP__PUBLIC_CALLDATA)\n}\n\n/// Computes the public bytecode commitment for a contract class. The commitment is `hash([(length | separator),\n/// ...bytecode])`.\n///\n/// @param packed_bytecode - The packed bytecode of the contract class. 0th word is the length in bytes.\n/// packed_bytecode is mutable so that we can avoid copying the array to construct one starting with first_field\n/// instead of length. @returns The public bytecode commitment.\npub fn compute_public_bytecode_commitment(\n mut packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],\n) -> Field {\n // First field element contains the length of the bytecode\n let bytecode_length_in_bytes: u32 = packed_public_bytecode[0] as u32;\n let bytecode_length_in_fields: u32 = (bytecode_length_in_bytes / 31) + (bytecode_length_in_bytes % 31 != 0) as u32;\n // Don't allow empty public bytecode. AVM doesn't handle execution of contracts that exist with empty bytecode.\n assert(bytecode_length_in_fields != 0);\n assert(bytecode_length_in_fields < MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS);\n\n // Packed_bytecode's 0th entry is the length. Append it to the separator before hashing.\n let first_field = DOM_SEP__PUBLIC_BYTECODE.to_field() + (packed_public_bytecode[0] as u64 << 32) as Field;\n packed_public_bytecode[0] = first_field;\n\n // `fields_to_hash` is the number of fields from the start of `packed_public_bytecode` that should be included in\n // the hash. Fields after this length are ignored. +1 to account for the prepended field.\n let num_fields_to_hash = bytecode_length_in_fields + 1;\n\n poseidon2_hash_subarray(packed_public_bytecode, num_fields_to_hash)\n}\n\n#[test]\nunconstrained fn secret_hash_matches_typescript() {\n let secret = 8;\n let hash = compute_secret_hash(secret);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let secret_hash_from_ts = 0x1848b066724ab0ffb50ecb0ee3398eb839f162823d262bad959721a9c13d1e96;\n\n assert_eq(hash, secret_hash_from_ts);\n}\n\n#[test]\nunconstrained fn var_args_hash_matches_typescript() {\n let mut input = [0; 100];\n for i in 0..100 {\n input[i] = i as Field;\n }\n let hash = hash_args(input);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let var_args_hash_from_ts = 0x262e5e121a8efc0382566ab42f0ae2a78bd85db88484f83018fe07fc2552ba0c;\n\n assert_eq(hash, var_args_hash_from_ts);\n}\n\n#[test]\nunconstrained fn compute_calldata_hash() {\n let mut input = [0; 100];\n for i in 0..input.len() {\n input[i] = i as Field;\n }\n let hash = hash_calldata_array(input);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let calldata_hash_from_ts = 0x14a1539bdb1d26e03097cf4d40c87e02ca03f0bb50a3e617ace5a7bfd3943944;\n\n // Used in cpp vm2 tests:\n assert_eq(hash, calldata_hash_from_ts);\n}\n\n#[test]\nunconstrained fn public_bytecode_commitment() {\n let mut input = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS];\n let len = 99;\n for i in 1..len + 1 {\n input[i] = i as Field;\n }\n input[0] = (len as Field) * 31;\n let hash = compute_public_bytecode_commitment(input);\n // Used in cpp vm2 tests:\n assert_eq(hash, 0x09348974e76c3602893d7a4b4bb52c2ec746f1ade5004ac471d0fbb4587a81a6);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/hash.nr","function_locations":[{"start":519,"name":"compute_secret_hash"},{"start":800,"name":"compute_l1_to_l2_message_hash"},{"start":1858,"name":"compute_l1_to_l2_message_nullifier"},{"start":2110,"name":"hash_args"},{"start":2362,"name":"hash_calldata_array"},{"start":2994,"name":"compute_public_bytecode_commitment"},{"start":4153,"name":"secret_hash_matches_typescript"},{"start":4512,"name":"var_args_hash_matches_typescript"},{"start":4922,"name":"compute_calldata_hash"},{"start":5385,"name":"public_bytecode_commitment"}]},"92":{"source":"use crate::protocol::{\n address::aztec_address::AztecAddress,\n constants::{DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, DOM_SEP__ECDH_FIELD_MASK, DOM_SEP__ECDH_SUBKEY},\n hash::poseidon2_hash_with_separator,\n point::Point,\n scalar::Scalar,\n traits::{FromField, ToField},\n};\nuse std::{embedded_curve_ops::multi_scalar_mul, ops::Neg};\n\n/// Computes a standard ECDH shared secret: secret * public_key = shared_secret.\n///\n/// The input secret is known only to one party. The output shared secret can be derived given knowledge of\n/// `public_key`'s key-pair and the public ephemeral secret, using this same function (with reversed inputs).\n///\n/// E.g.: Epk = esk * G // ephemeral key-pair\n/// Pk = sk * G // recipient key-pair\n/// Shared secret S = esk * Pk = sk * Epk\n///\n/// See also: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman\npub fn derive_ecdh_shared_secret(secret: Scalar, public_key: Point) -> Point {\n // TODO(F-553): Drop the `.to_embedded()` / `.into()` round-trip once the custom `Point` wrapper is removed and we\n // use `EmbeddedCurvePoint` directly.\n multi_scalar_mul([public_key.to_embedded()], [secret]).into()\n}\n\n/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.\n///\n/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`\npub(crate) fn compute_app_siloed_shared_secret(shared_secret: Point, contract_address: AztecAddress) -> Field {\n poseidon2_hash_with_separator(\n [shared_secret.x, shared_secret.y, contract_address.to_field()],\n DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET,\n )\n}\n\n/// Derives an indexed subkey from an app-siloed shared secret, used for AES key/IV derivation.\n///\n/// `s_i = h(DOM_SEP__ECDH_SUBKEY + i, s_app)`\npub(crate) fn derive_shared_secret_subkey(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_SUBKEY + index)\n}\n\n/// Derives an indexed field mask from an app-siloed shared secret, used for masking ciphertext fields.\n///\n/// `m_i = h(DOM_SEP__ECDH_FIELD_MASK + i, s_app)`\npub(crate) fn derive_shared_secret_field_mask(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_FIELD_MASK + index)\n}\n\n#[test]\nunconstrained fn test_consistency_with_typescript() {\n let secret = Scalar {\n lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,\n hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,\n };\n let point = Point {\n x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,\n y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,\n is_infinite: false,\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret, point);\n\n // This is just pasted from a test run. The original typescript code from which this could be generated seems to\n // have been deleted by someone, and soon the typescript code for encryption and decryption won't be needed, so\n // this will have to do.\n let hard_coded_shared_secret = Point {\n x: 0x15d55a5b3b2caa6a6207f313f05c5113deba5da9927d6421bcaa164822b911bc,\n y: 0x0974c3d0825031ae933243d653ebb1a0b08b90ee7f228f94c5c74739ea3c871e,\n is_infinite: false,\n };\n assert_eq(shared_secret, hard_coded_shared_secret);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_from_address_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let mut pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let mut pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let address_b = AztecAddress::from_field(pk_b.x);\n\n // We were lazy in deriving the secret keys, and didn't check the resulting y-coordinates of the pk_a or pk_b to be\n // less than half the field modulus. If needed, we negate the pk's so that they yield valid address points. (We\n // could also have negated the secrets, but there's no negate method for EmbeddedCurvesScalar).\n pk_a = if (AztecAddress::from_field(pk_a.x).to_address_point().unwrap().inner == pk_a) {\n pk_a\n } else {\n pk_a.neg()\n };\n pk_b = if (address_b.to_address_point().unwrap().inner == pk_b) {\n pk_b\n } else {\n pk_b.neg()\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, address_b.to_address_point().unwrap().inner);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_app_siloed_shared_secret_differs_per_contract() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(Scalar { lo: 0x3456, hi: 0x4567 }).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n\n let contract_a = AztecAddress::from_field(0xAAAA);\n let contract_b = AztecAddress::from_field(0xBBBB);\n\n let s_app_a = compute_app_siloed_shared_secret(shared_secret, contract_a);\n let s_app_b = compute_app_siloed_shared_secret(shared_secret, contract_b);\n\n assert(s_app_a != s_app_b, \"app-siloed secrets must differ for different contracts\");\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/keys/ecdh_shared_secret.nr","function_locations":[{"start":954,"name":"derive_ecdh_shared_secret"},{"start":1485,"name":"compute_app_siloed_shared_secret"},{"start":1876,"name":"derive_shared_secret_subkey"},{"start":2194,"name":"derive_shared_secret_field_mask"},{"start":2336,"name":"test_consistency_with_typescript"},{"start":3450,"name":"test_shared_secret_computation_in_both_directions"},{"start":4017,"name":"test_shared_secret_computation_from_address_in_both_directions"},{"start":5278,"name":"test_app_siloed_shared_secret_differs_per_contract"}]},"97":{"source":"// Not all log levels are currently used, but we provide the full set so that new call sites can use any level. Because\n// of that we tag all with `#[allow(dead_code)]` to prevent warnings.\n//\n// All wrappers resolve function paths at comptime via `resolve_fn` so that the emitted `Quoted` code works both inside\n// aztec-nr (where `crate::` = aztec) and inside macro-generated contract code (where `crate::` = the contract).\n\nuse std::meta::ctstring::AsCtString;\n\ncomptime fn log_prefix(msg: str) -> CtString {\n \"[aztec-nr] \".as_ctstring().append_str(msg)\n}\n\n// --- No-args variants (direct call) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log });\n quote { $f($msg) }\n}\n\n// --- Format variants (return lambda for runtime args) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n// See module-level comment for why this is needed.\ncomptime fn resolve_fn(path: Quoted) -> TypedExpr {\n path.as_expr().unwrap().resolve(Option::none())\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/logging.nr","function_locations":[{"start":525,"name":"log_prefix"},{"start":717,"name":"aztecnr_fatal_log"},{"start":943,"name":"aztecnr_error_log"},{"start":1168,"name":"aztecnr_warn_log"},{"start":1392,"name":"aztecnr_info_log"},{"start":1619,"name":"aztecnr_verbose_log"},{"start":1847,"name":"aztecnr_debug_log"},{"start":2073,"name":"aztecnr_trace_log"},{"start":2367,"name":"aztecnr_fatal_log_format"},{"start":2622,"name":"aztecnr_error_log_format"},{"start":2876,"name":"aztecnr_warn_log_format"},{"start":3129,"name":"aztecnr_info_log_format"},{"start":3385,"name":"aztecnr_verbose_log_format"},{"start":3642,"name":"aztecnr_debug_log_format"},{"start":3897,"name":"aztecnr_trace_log_format"},{"start":4151,"name":"resolve_fn"}]},"99":{"source":"use crate::logging;\nuse crate::macros::{notes::NOTES, utils::get_trait_impl_method};\n\n/// Generates two contract library methods called `_compute_note_hash` and `_compute_note_nullifier`, plus a\n/// (deprecated) wrapper called `_compute_note_hash_and_nullifier`, which are used for note discovery (i.e. these are\n/// of the `aztec::messages::discovery::ComputeNoteHash` and `aztec::messages::discovery::ComputeNoteNullifier` types).\npub(crate) comptime fn generate_contract_library_methods_compute_note_hash_and_nullifier() -> Quoted {\n let compute_note_hash = generate_contract_library_method_compute_note_hash();\n let compute_note_nullifier = generate_contract_library_method_compute_note_nullifier();\n\n quote {\n $compute_note_hash\n $compute_note_nullifier\n\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n #[allow(dead_code)]\n unconstrained fn _compute_note_hash_and_nullifier(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n note_nonce: Field,\n ) -> Option {\n _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash| {\n\n let siloed_note_hash = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash);\n let unique_note_hash = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash);\n \n let inner_nullifier = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness);\n\n aztec::messages::discovery::NoteHashAndNullifier {\n note_hash,\n inner_nullifier,\n }\n })\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_hash() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the note hash (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_note_hash = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_note_hash },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n Option::some($compute_note_hash(note, owner, storage_slot, randomness))\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed).\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_nullifier() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the inner nullifier (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_nullifier_unconstrained = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_nullifier_unconstrained },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n // The message discovery process finds settled notes, that is, notes that were created in\n // prior transactions and are therefore already part of the note hash tree. The note hash\n // for nullification is hence the unique note hash.\n $compute_nullifier_unconstrained(note, owner, unique_note_hash)\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data.\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec/compute_note_hash_and_nullifier.nr","function_locations":[{"start":534,"name":"generate_contract_library_methods_compute_note_hash_and_nullifier"},{"start":2449,"name":"generate_contract_library_method_compute_note_hash"},{"start":7674,"name":"generate_contract_library_method_compute_note_nullifier"}]},"100":{"source":"mod compute_note_hash_and_nullifier;\n\nuse crate::{\n macros::{\n calls_generation::{\n external_functions::{generate_external_function_calls, generate_external_function_self_calls_structs},\n internal_functions::generate_call_internal_struct,\n },\n dispatch::generate_public_dispatch,\n emit_public_init_nullifier::generate_emit_public_init_nullifier,\n internals_functions_generation::{create_fn_abi_exports, process_functions},\n offchain_receive::{\n OFFCHAIN_RECEIVE_FN_NAME, OFFCHAIN_RECEIVE_PARAM_NAME, offchain_receive_param_type,\n OFFCHAIN_RECEIVE_RETURN_TYPE,\n },\n storage::STORAGE_LAYOUT_NAME,\n utils::{is_fn_contract_library_method, is_fn_external, is_fn_internal, is_fn_test, module_has_storage},\n },\n messages::discovery::CustomMessageHandler,\n};\n\nuse compute_note_hash_and_nullifier::generate_contract_library_methods_compute_note_hash_and_nullifier;\n\n/// Configuration for the [`aztec`] macro.\n///\n/// This type lets users override different parts of the default aztec-nr contract behavior, such\n/// as message handling. These are advanced features that require careful understanding of\n/// the behavior of these systems.\n///\n/// ## Examples\n///\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyContract { ... }\n/// ```\npub struct AztecConfig {\n custom_message_handler: Option>,\n}\n\nimpl AztecConfig {\n /// Creates a new `AztecConfig` with default values.\n ///\n /// Calling `new` is equivalent to invoking the [`aztec`] macro with no parameters. The different methods\n /// (e.g. [`AztecConfig::custom_message_handler`]) can then be used to change the default behavior.\n pub comptime fn new() -> Self {\n Self { custom_message_handler: Option::none() }\n }\n\n /// Sets a handler for custom messages.\n ///\n /// This enables contracts to process non-standard messages (i.e. any with a message type that is not in\n /// [`crate::messages::msg_type`]).\n ///\n /// `handler` must be a function that conforms to the\n /// [`crate::messages::discovery::CustomMessageHandler`] type signature.\n pub comptime fn custom_message_handler(_self: Self, handler: CustomMessageHandler<()>) -> Self {\n Self { custom_message_handler: Option::some(handler) }\n }\n}\n\n/// Enables aztec-nr features on a `contract`.\n///\n/// All aztec-nr contracts should have this macro invoked on them, as it is the one that processes all contract\n/// functions, notes, storage, generates interfaces for external calls, and creates the message processing\n/// boilerplate.\n///\n/// ## Examples\n///\n/// Most contracts can simply invoke the macro with no parameters, resulting in default aztec-nr behavior:\n/// ```noir\n/// #[aztec]\n/// contract MyContract { ... }\n/// ```\n///\n/// Advanced contracts can use [`AztecConfig`] to customize parts of its behavior, such as message\n/// processing.\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyAdvancedContract { ... }\n/// ```\n#[varargs]\npub comptime fn aztec(m: Module, args: [AztecConfig]) -> Quoted {\n let num_args = args.len();\n let config = if num_args == 0 {\n AztecConfig::new()\n } else if num_args == 1 {\n args[0]\n } else {\n panic(f\"#[aztec] expects 0 or 1 arguments, got {num_args}\")\n };\n\n // Functions that don't have #[external(...)], #[contract_library_method], or #[test] are not allowed in contracts.\n check_each_fn_macroified(m);\n\n // We generate new functions prefixed with `__aztec_nr_internals__` and we replace the original functions' bodies\n // with `static_assert(false, ...)` to prevent them from being called directly from within the contract.\n let functions = process_functions(m);\n\n // We generate structs and their implementations necessary for convenient functions calls.\n let interface = generate_contract_interface(m);\n let self_call_structs = generate_external_function_self_calls_structs(m);\n let call_internal_struct = generate_call_internal_struct(m);\n\n // We generate ABI exports for all the external functions in the contract.\n let fn_abi_exports = create_fn_abi_exports(m);\n\n // We generate `_compute_note_hash`, `_compute_note_nullifier` (and the deprecated\n // `_compute_note_hash_and_nullifier` wrapper) and `sync_state` functions only if they are not already implemented.\n // If they are implemented we just insert empty quotes.\n let contract_library_method_compute_note_hash_and_nullifier = if !m.functions().any(|f| {\n // Note that we don't test for `_compute_note_hash` or `_compute_note_nullifier` in order to make this simpler\n // - users must either implement all three or none.\n // Down the line we'll remove this check and use `AztecConfig`.\n f.name() == quote { _compute_note_hash_and_nullifier }\n }) {\n generate_contract_library_methods_compute_note_hash_and_nullifier()\n } else {\n quote {}\n };\n let process_custom_message_option = if config.custom_message_handler.is_some() {\n let handler = config.custom_message_handler.unwrap();\n quote { Option::some($handler) }\n } else {\n quote { Option::>::none() }\n };\n\n let offchain_inbox_sync_option = quote {\n Option::some(aztec::messages::processing::offchain::sync_inbox)\n };\n\n let sync_state_fn_and_abi_export = if !m.functions().any(|f| f.name() == quote { sync_state }) {\n generate_sync_state(process_custom_message_option, offchain_inbox_sync_option)\n } else {\n quote {}\n };\n\n if m.functions().any(|f| f.name() == quote { offchain_receive }) {\n panic(\n \"User-defined 'offchain_receive' is not allowed. The function is auto-injected by the #[aztec] macro. See https://docs.aztec.network/errors/7\",\n );\n }\n let offchain_receive_fn_and_abi_export = generate_offchain_receive();\n\n let (has_public_init_nullifier_fn, emit_public_init_nullifier_fn_body) = generate_emit_public_init_nullifier(m);\n let public_dispatch = generate_public_dispatch(m, has_public_init_nullifier_fn);\n\n quote {\n $interface\n $self_call_structs\n $call_internal_struct\n $functions\n $fn_abi_exports\n $contract_library_method_compute_note_hash_and_nullifier\n $public_dispatch\n $sync_state_fn_and_abi_export\n $emit_public_init_nullifier_fn_body\n $offchain_receive_fn_and_abi_export\n }\n}\n\ncomptime fn generate_contract_interface(m: Module) -> Quoted {\n let calls = generate_external_function_calls(m);\n\n let module_name = m.name();\n\n let has_storage_layout = module_has_storage(m) & STORAGE_LAYOUT_NAME.get(m).is_some();\n let storage_layout_getter = if has_storage_layout {\n let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap();\n quote {\n pub fn storage_layout() -> StorageLayoutFields {\n $storage_layout_name.fields\n }\n }\n } else {\n quote {}\n };\n\n let library_storage_layout_getter = if has_storage_layout {\n quote {\n #[contract_library_method]\n $storage_layout_getter\n }\n } else {\n quote {}\n };\n\n quote {\n pub struct $module_name {\n pub target_contract: aztec::protocol::address::AztecAddress\n }\n\n impl $module_name {\n $calls\n\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> Self {\n Self { target_contract: addr }\n }\n\n pub fn interface() -> Self {\n Self { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $storage_layout_getter\n }\n\n #[contract_library_method]\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> $module_name {\n $module_name { target_contract: addr }\n }\n\n #[contract_library_method]\n pub fn interface() -> $module_name {\n $module_name { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $library_storage_layout_getter\n\n }\n}\n\n/// Generates the `sync_state` utility function that performs message discovery.\ncomptime fn generate_sync_state(process_custom_message_option: Quoted, offchain_inbox_sync_option: Quoted) -> Quoted {\n quote {\n pub struct sync_state_parameters {\n pub scope: aztec::protocol::address::AztecAddress,\n }\n\n #[abi(functions)]\n pub struct sync_state_abi {\n parameters: sync_state_parameters,\n }\n\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn sync_state(scope: aztec::protocol::address::AztecAddress) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::discovery::do_sync_state(\n address,\n _compute_note_hash,\n _compute_note_nullifier,\n $process_custom_message_option,\n $offchain_inbox_sync_option,\n scope,\n );\n }\n }\n}\n\n/// Generates an `offchain_receive` utility function that lets callers add messages to the offchain message inbox.\n///\n/// For more details, see `aztec::messages::processing::offchain::receive`.\ncomptime fn generate_offchain_receive() -> Quoted {\n let param_type = offchain_receive_param_type(quote { aztec });\n let parameters_struct_name = f\"{OFFCHAIN_RECEIVE_FN_NAME}_parameters\".quoted_contents();\n let abi_struct_name = f\"{OFFCHAIN_RECEIVE_FN_NAME}_abi\".quoted_contents();\n\n quote {\n pub struct $parameters_struct_name {\n pub $OFFCHAIN_RECEIVE_PARAM_NAME: $param_type,\n }\n\n #[abi(functions)]\n pub struct $abi_struct_name {\n parameters: $parameters_struct_name,\n }\n\n /// Receives offchain messages into this contract's offchain inbox for subsequent processing.\n ///\n /// Each message is routed to the inbox scoped to its `recipient` field.\n ///\n /// For more details, see `aztec::messages::processing::offchain::receive`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn $OFFCHAIN_RECEIVE_FN_NAME($OFFCHAIN_RECEIVE_PARAM_NAME: $param_type) -> $OFFCHAIN_RECEIVE_RETURN_TYPE {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::processing::offchain::receive(address, $OFFCHAIN_RECEIVE_PARAM_NAME);\n }\n }\n}\n\n/// Checks that all functions in the module have a context macro applied.\n///\n/// Non-macroified functions are not allowed in contracts. They must all be one of\n/// [`crate::macros::functions::external`], [`crate::macros::functions::internal`] or `test`.\ncomptime fn check_each_fn_macroified(m: Module) {\n for f in m.functions() {\n let name = f.name();\n if !is_fn_external(f) & !is_fn_contract_library_method(f) & !is_fn_internal(f) & !is_fn_test(f) {\n // We don't suggest that #[contract_library_method] is allowed because we don't want to introduce another\n // concept\n panic(\n f\"Function {name} must be marked as either #[external(...)], #[internal(...)], or #[test]\",\n );\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec.nr","function_locations":[{"start":1825,"name":"AztecConfig::new"},{"start":2333,"name":"AztecConfig::custom_message_handler"},{"start":3227,"name":"aztec"},{"start":6704,"name":"generate_contract_interface"},{"start":8566,"name":"generate_sync_state"},{"start":9620,"name":"generate_offchain_receive"},{"start":11209,"name":"check_each_fn_macroified"}]},"105":{"source":"use crate::macros::internals_functions_generation::external_functions_registry::get_public_functions;\nuse crate::protocol::meta::utils::get_params_len_quote;\nuse crate::utils::cmap::CHashMap;\nuse super::functions::initialization_utils::EMIT_PUBLIC_INIT_NULLIFIER_FN_NAME;\nuse super::utils::compute_fn_selector;\nuse std::panic;\n\n/// Generates a `public_dispatch` function for an Aztec contract module `m`.\n///\n/// The generated function dispatches public calls based on selector to the appropriate contract function. If\n/// `generate_emit_public_init_nullifier` is true, it also handles dispatch to the macro-generated\n/// `__emit_public_init_nullifier` function.\npub comptime fn generate_public_dispatch(m: Module, generate_emit_public_init_nullifier: bool) -> Quoted {\n let functions = get_public_functions(m);\n\n let unit = get_type::<()>();\n\n let seen_selectors = &mut CHashMap::::new();\n\n let mut ifs = functions.map(|function: FunctionDefinition| {\n let parameters = function.parameters();\n let return_type = function.return_type();\n\n let fn_name = function.name();\n let selector: Field = compute_fn_selector(fn_name, parameters);\n\n // Since function selectors are computed as the first 4 bytes of the hash of the function signature, it's\n // possible to have collisions. With the following check, we ensure it doesn't happen within the same contract.\n let existing_fn = seen_selectors.get(selector);\n if existing_fn.is_some() {\n let existing_fn = existing_fn.unwrap();\n panic(\n f\"Public function selector collision detected between functions '{fn_name}' and '{existing_fn}'\",\n );\n }\n seen_selectors.insert(selector, fn_name);\n\n let params_len_quote = get_params_len_quote(parameters);\n\n let initial_read = if parameters.len() == 0 {\n quote {}\n } else {\n // The initial calldata_copy offset is 1 to skip the Field selector The expected calldata is the\n // serialization of\n // - FunctionSelector: the selector of the function intended to dispatch\n // - Parameters: the parameters of the function intended to dispatch That is, exactly what is expected for\n // a call to the target function, but with a selector added at the beginning.\n quote {\n let input_calldata: [Field; $params_len_quote] = aztec::oracle::avm::calldata_copy(1, $params_len_quote);\n let mut reader = aztec::protocol::utils::reader::Reader::new(input_calldata);\n }\n };\n\n let parameter_index: &mut u32 = &mut 0;\n let reads = parameters.map(|param: (Quoted, Type)| {\n let parameter_index_value = *parameter_index;\n let param_name = f\"arg{parameter_index_value}\".quoted_contents();\n let param_type = param.1;\n let read = quote {\n let $param_name: $param_type = aztec::protocol::traits::Deserialize::stream_deserialize(&mut reader);\n };\n *parameter_index += 1;\n quote { $read }\n });\n let read = reads.join(quote { });\n\n let mut args = @[];\n for parameter_index in 0..parameters.len() {\n let param_name = f\"arg{parameter_index}\".quoted_contents();\n args = args.push_back(quote { $param_name });\n }\n\n // We call a function whose name is prefixed with `__aztec_nr_internals__`. This is necessary because the\n // original function is intentionally made uncallable, preventing direct invocation within the contract.\n // Instead, a new function with the same name, but prefixed by `__aztec_nr_internals__`, has been generated to\n // be called here. For more details see the `process_functions` function.\n let name = f\"__aztec_nr_internals__{fn_name}\".quoted_contents();\n let args = args.join(quote { , });\n let call = quote { $name($args) };\n\n let return_code = if return_type == unit {\n quote {\n $call;\n // Force early return.\n aztec::oracle::avm::avm_return([]);\n }\n } else {\n quote {\n let return_value = aztec::protocol::traits::Serialize::serialize($call);\n aztec::oracle::avm::avm_return(return_value.as_vector());\n }\n };\n\n let if_ = quote {\n if selector == $selector {\n $initial_read\n $read\n $return_code\n }\n };\n if_\n });\n\n // If we injected the auto-generated public function to emit the public initialization nullifier, then\n // we'll also need to handle its dispatch.\n if generate_emit_public_init_nullifier {\n let name = EMIT_PUBLIC_INIT_NULLIFIER_FN_NAME;\n let init_nullifier_selector: Field = compute_fn_selector(name, @[]);\n\n ifs = ifs.push_back(\n quote {\n if selector == $init_nullifier_selector {\n $name();\n aztec::oracle::avm::avm_return([]);\n }\n },\n );\n }\n\n if ifs.len() == 0 {\n // No dispatch function if there are no public functions\n quote {}\n } else {\n let ifs = ifs.push_back(quote { panic(f\"Unknown selector {selector}\") });\n let dispatch = ifs.join(quote { });\n\n let body = quote {\n // We mark this as public because our whole system depends on public functions having this attribute.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]\n pub unconstrained fn public_dispatch(selector: Field) {\n $dispatch\n }\n };\n\n body\n }\n}\n\ncomptime fn get_type() -> Type {\n let t: T = std::mem::zeroed();\n std::meta::type_of(t)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/dispatch.nr","function_locations":[{"start":768,"name":"generate_public_dispatch"},{"start":5832,"name":"get_type"}]},"113":{"source":"use crate::macros::{\n functions::auth_registry::AUTHORIZE_ONCE_REGISTRY,\n utils::{is_fn_initializer, is_fn_only_self, is_fn_view},\n};\n\n/// Gathers all attributes relevant to the function's ABI and returns a quote that can be applied to the newly\n/// generated function. We apply the abi marker attributes instead of the original ones (e.g. abi_view instead of view)\n/// to avoid the relevant attribute's functionality from getting triggered.\npub(crate) comptime fn get_abi_relevant_attributes(f: FunctionDefinition) -> Quoted {\n let mut attributes = quote {};\n\n if is_fn_view(f) {\n attributes = quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_view] };\n }\n\n if is_fn_only_self(f) {\n attributes =\n quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_only_self] };\n }\n\n if is_fn_initializer(f) {\n attributes =\n quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_initializer] };\n }\n\n attributes\n}\n\n/// Injects an authwit verification check of the form:\n/// ```\n/// if (!from.eq(context.maybe_msg_sender().unwrap())) {\n/// assert_current_call_valid_authwit::(&mut context, from);\n/// } else {\n/// assert(authwit_nonce, \"Invalid authwit nonce. When 'from' and 'msg_sender' are the\n/// same, authwit_nonce must be zero\");\n/// }\n/// ```\n/// where `from` and `authwit_nonce` are the names of the parameters that are expected to be present in the function\n/// definition. This check is injected by the `#[authorize_once(\"from_arg_name\", \"nonce_arg_name\")]`, which allows the\n/// user to define which parameters to use.\n///\n/// # Arguments\n/// * `f` - The function definition to inject the authwit verification check into. The function must have parameters\n/// matching the names specified in the `#[authorize_once]` attribute.\n/// * `is_private` - Whether the function is a private function (`true`) or a public function (`false`). This\n/// determines which authwit verification method to use: `assert_current_call_valid_authwit` for private functions or\n/// `assert_current_call_valid_authwit_public` for public functions.\npub(crate) comptime fn create_authorize_once_check(f: FunctionDefinition, is_private: bool) -> Quoted {\n let maybe_authorize_once_args = AUTHORIZE_ONCE_REGISTRY.get(f);\n let authorize_once_args = if maybe_authorize_once_args.is_some() {\n maybe_authorize_once_args.unwrap()\n } else {\n // We need to for authorize_once to have already executed so that we can retrieve its params - this depends on\n // the order in which the attributes are applied.\n panic(\n f\"Functions marked with #[authorize_once] must have the #[external(\\\"private\\\")] or #[external(\\\"public\\\")] attribute placed last\",\n )\n };\n\n let (from_arg_name, nonce_arg_name) = authorize_once_args;\n let name: Quoted = f.name();\n\n let from_arg_candidates = f.parameters().filter(|(name, _)| name == f\"{from_arg_name}\".quoted_contents());\n let (from_arg_name_quoted, from_arg_type) = if from_arg_candidates.len() == 1 {\n from_arg_candidates[0]\n } else {\n panic(\n f\"Function {name} does not have a {from_arg_name} parameter. Please specify which one to use in #[authorize_once(\\\"...\\\", \\\"authwit_nonce\\\")]\",\n )\n };\n if from_arg_type != quote { crate::protocol::address::aztec_address::AztecAddress }.as_type() {\n panic(\n f\"Argument {from_arg_name_quoted} in function {name} must be of type AztecAddress, but is of type {from_arg_type}\",\n )\n }\n\n let nonce_arg_candidates = f.parameters().filter(|(name, _)| name == f\"{nonce_arg_name}\".quoted_contents());\n let (nonce_arg_name_quoted, nonce_arg_type) = if nonce_arg_candidates.len() == 1 {\n nonce_arg_candidates[0]\n } else {\n panic(\n f\"Function {name} does not have a {nonce_arg_name}. Please specify which one to use in #[authorize_once(\\\"from\\\", \\\"...\\\")]\",\n )\n };\n if nonce_arg_type != quote { Field }.as_type() {\n panic(\n f\"Argument {nonce_arg_name_quoted} in function {name} must be of type Field, but is of type {nonce_arg_type}\",\n );\n }\n\n let nonce_check_quote = f\"{nonce_arg_name_quoted} == 0\".quoted_contents();\n\n let fn_call = if is_private {\n let params = f.parameters();\n let serialized_len_quote = if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as aztec::protocol::traits::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n };\n quote { aztec::authwit::auth::assert_current_call_valid_authwit::<($serialized_len_quote)> }\n } else {\n quote { aztec::authwit::auth::assert_current_call_valid_authwit_public }\n };\n let invalid_nonce_message = f\"Invalid authwit nonce. When '{from_arg_name}' and 'msg_sender' are the same, '{nonce_arg_name}' must be zero\"\n .as_quoted_str();\n quote { \n if (!$from_arg_name_quoted.eq(self.msg_sender())) {\n $fn_call(self.context, $from_arg_name_quoted);\n } else {\n assert($nonce_check_quote, $invalid_nonce_message);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr","function_locations":[{"start":532,"name":"get_abi_relevant_attributes"},{"start":2334,"name":"create_authorize_once_check"}]},"116":{"source":"use crate::macros::{\n internals_functions_generation::external::helpers::{create_authorize_once_check, get_abi_relevant_attributes},\n utils::{\n fn_has_authorize_once, fn_has_noinitcheck, is_fn_initializer, is_fn_only_self, is_fn_view,\n module_has_initializer, module_has_storage,\n },\n};\n\npub(crate) comptime fn generate_public_external(f: FunctionDefinition) -> Quoted {\n let module_has_initializer = module_has_initializer(f.module());\n let module_has_storage = module_has_storage(f.module());\n\n // Public functions undergo a lot of transformations from their Aztec.nr form.\n let original_params = f.parameters();\n\n let args_len_quote = if original_params.len() == 0 {\n // If the function has no parameters, we set the args_len to 0.\n quote { 0 }\n } else {\n // The following will give us ::N + ::N + ...\n original_params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::protocol::traits::Serialize>::N\n }\n })\n .join(quote {+})\n };\n\n let storage_init = if module_has_storage {\n quote {\n let storage = Storage::init(context);\n }\n } else {\n // Contract does not have Storage defined, so we set storage to the unit type `()`. ContractSelfPublic requires\n // a storage struct in its constructor. Using an Option type would lead to worse developer experience and\n // higher constraint counts so we use the unit type `()` instead.\n quote {\n let storage = ();\n }\n };\n\n // Unlike in the private case, in public the `context` does not need to receive the hash of the original params.\n let contract_self_creation = quote {\n #[allow(unused_variables)]\n let mut self = {\n let context = aztec::context::PublicContext::new(|| {\n // We start from 1 because we skip the selector for the dispatch function.\n let serialized_args : [Field; $args_len_quote] = aztec::oracle::avm::calldata_copy(1, $args_len_quote);\n aztec::hash::hash_args(serialized_args)\n });\n $storage_init\n let self_address = context.this_address();\n let call_self: CallSelf = CallSelf { address: self_address, context };\n let call_self_static: CallSelfStatic = CallSelfStatic { address: self_address, context };\n let internal: CallInternal = CallInternal { context };\n aztec::contract_self::ContractSelfPublic::new(context, storage, call_self, call_self_static, internal)\n };\n };\n\n let original_function_name = f.name();\n\n // Modifications introduced by the different marker attributes.\n let internal_check = if is_fn_only_self(f) {\n let assertion_message = f\"Function {original_function_name} can only be called by the same contract\";\n quote { assert(self.msg_sender() == self.address, $assertion_message); }\n } else {\n quote {}\n };\n\n let view_check = if is_fn_view(f) {\n let assertion_message = f\"Function {original_function_name} can only be called statically\".as_quoted_str();\n quote { assert(self.context.is_static_call(), $assertion_message); }\n } else {\n quote {}\n };\n\n let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) {\n (\n quote { aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_public(self.context); },\n quote { aztec::macros::functions::initialization_utils::mark_as_initialized_from_public_initializer(self.context); },\n )\n } else {\n (quote {}, quote {})\n };\n\n // Initialization checks are not included in contracts that don't have initializers.\n let init_check = if module_has_initializer & !fn_has_noinitcheck(f) & !is_fn_initializer(f) {\n quote { aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); }\n } else {\n quote {}\n };\n\n // Inject the authwit check if the function is marked with #[authorize_once].\n let authorize_once_check = if fn_has_authorize_once(f) {\n create_authorize_once_check(f, false)\n } else {\n quote {}\n };\n\n let to_prepend = quote {\n $contract_self_creation\n $assert_initializer\n $init_check\n $internal_check\n $view_check\n $authorize_once_check\n };\n\n // `mark_as_initialized` is placed after the user's function body. If it ran at the beginning, the contract\n // would appear initialized while the initializer is still running, allowing contracts called by the initializer\n // to re-enter into a half-initialized contract.\n let to_append = quote {\n $mark_as_initialized\n };\n\n let fn_name = f\"__aztec_nr_internals__{original_function_name}\".quoted_contents();\n let body = f.body();\n let return_type = f.return_type();\n\n // New function parameters are the same as the original function's ones.\n let params = original_params.map(|(param_name, param_type)| quote { $param_name: $param_type }).join(quote {, });\n\n // Preserve all attributes that are relevant to the function's ABI.\n let abi_relevant_attributes = get_abi_relevant_attributes(f);\n\n // All public functions are automatically made unconstrained, even if they were not marked as such. This is because\n // instead of compiling into a circuit, they will compile to bytecode that will be later transpiled into AVM\n // bytecode.\n quote {\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]\n $abi_relevant_attributes\n unconstrained fn $fn_name($params) -> pub $return_type {\n $to_prepend\n $body\n $to_append\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr","function_locations":[{"start":392,"name":"generate_public_external"}]},"127":{"source":"use crate::logging::{aztecnr_debug_log, aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\npub(crate) mod nonce_discovery;\npub(crate) mod partial_notes;\npub(crate) mod private_events;\npub mod private_notes;\npub mod process_message;\n\nuse crate::{\n messages::{\n discovery::process_message::process_message_ciphertext,\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{\n MessageContext, offchain::OffchainInboxSync, OffchainMessageWithContext,\n pending_tagged_log::PendingTaggedLog, validate_and_store_enqueued_notes_and_events,\n },\n },\n oracle::message_processing,\n utils::array,\n};\n\npub struct NoteHashAndNullifier {\n /// The result of [`crate::note::note_interface::NoteHash::compute_note_hash`].\n pub note_hash: Field,\n /// The result of [`crate::note::note_interface::NoteHash::compute_nullifier_unconstrained`].\n ///\n /// This value is unconstrained, as all of message discovery is unconstrained. It is `None` if the nullifier\n /// cannot be computed (e.g. because the nullifier hiding key is not available).\n pub inner_nullifier: Option,\n}\n\n/// A contract's way of computing note hashes.\n///\n/// Each contract in the network is free to compute their note's hash as they see fit - the hash function itself is not\n/// enshrined or standardized. Some aztec-nr functions however do need to know the details of this computation (e.g.\n/// when finding new notes), which is what this type represents.\n///\n/// This function takes a note's packed content, storage slot, note type ID, address of the emitting contract and\n/// randomness, and attempts to compute its inner note hash (not siloed by address nor uniqued by nonce).\n///\n/// ## Transient Notes\n///\n/// This function is meant to always be used on **settled** notes, i.e. those that have been inserted into the trees\n/// and for which the nonce is known. It is never invoked in the context of a transient note, as those are not involved\n/// in message processing.\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract by inspecting all note types in use and the storage layout. This injected function is a\n/// `#[contract_library_method]` called `_compute_note_hash`, and it looks something like this:\n///\n/// ```noir\n/// |packed_note, owner, storage_slot, note_type_id, _contract_address, randomness| {\n/// if note_type_id == MyNoteType::get_id() {\n/// if packed_note.len() != MY_NOTE_TYPE_SERIALIZATION_LENGTH {\n/// Option::none()\n/// } else {\n/// let note = MyNoteType::unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n/// Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n/// }\n/// } else if note_type_id == MyOtherNoteType::get_id() {\n/// ... // Similar to above but calling MyOtherNoteType::unpack\n/// } else {\n/// Option::none() // Unknown note type ID\n/// };\n/// }\n/// ```\npub type ComputeNoteHash = unconstrained fn(/* packed_note */BoundedVec, /*\n owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress, /*\nrandomness */ Field) -> Option;\n\n/// A contract's way of computing note nullifiers.\n///\n/// Like [`ComputeNoteHash`], each contract is free to derive nullifiers as they see fit. This function takes the\n/// unique note hash (used as the note hash for nullification for settled notes), plus the note's packed content and\n/// metadata, and attempts to compute the inner nullifier (not siloed by address).\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract called `_compute_note_nullifier`. It dispatches on `note_type_id` similarly to\n/// [`ComputeNoteHash`], then calls the note's\n/// [`compute_nullifier_unconstrained`](crate::note::note_interface::NoteHash::compute_nullifier_unconstrained) method.\npub type ComputeNoteNullifier = unconstrained fn(/* unique_note_hash */Field, /* packed_note */ BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/* randomness */ Field) -> Option;\n\n/// Deprecated: use [`ComputeNoteHash`] and [`ComputeNoteNullifier`] instead.\npub type ComputeNoteHashAndNullifier = unconstrained fn[Env](/* packed_note */BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/*randomness */ Field, /* note nonce */ Field) -> Option;\n\n/// A handler for custom messages.\n///\n/// Contracts that emit custom messages (i.e. any with a message type that is not in [`crate::messages::msg_type`])\n/// need to use [`crate::macros::AztecConfig::custom_message_handler`] with a function of this type in order to\n/// process them. They will otherwise be **silently ignored**.\npub type CustomMessageHandler = unconstrained fn[Env](\n/* contract_address */AztecAddress,\n/* msg_type_id */ u64,\n/* msg_metadata */ u64,\n/* msg_content */ BoundedVec,\n/* message_context */ MessageContext,\n/* scope */ AztecAddress);\n\n/// Synchronizes the contract's private state with the network.\n///\n/// As blocks are mined, it is possible for a contract's private state to change (e.g. with new notes being created),\n/// but because these changes are private they will be invisible to most actors. This is the function that processes\n/// new transactions in order to discover new notes, events, and other kinds of private state changes.\n///\n/// The private state will be synchronized up to the block that will be used for private transactions (i.e. the anchor\n/// block. This will typically be close to the tip of the chain.\npub unconstrained fn do_sync_state(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n offchain_inbox_sync: Option>,\n scope: AztecAddress,\n) {\n aztecnr_debug_log!(\"Performing state synchronization\");\n\n // First we process all private logs, which can contain different kinds of messages e.g. private notes, partial\n // notes, private events, etc.\n let logs = message_processing::get_pending_tagged_logs(scope);\n logs.for_each(|_i, pending_tagged_log: PendingTaggedLog| {\n if pending_tagged_log.log.len() == 0 {\n aztecnr_warn_log_format!(\"Skipping empty log from tx {0}\")([pending_tagged_log.context.tx_hash]);\n } else {\n aztecnr_debug_log_format!(\"Processing log with tag {0}\")([pending_tagged_log.log.get(0)]);\n\n // We remove the tag from the pending tagged log and process the message ciphertext contained in it.\n let message_ciphertext = array::subbvec(pending_tagged_log.log, 1);\n\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_ciphertext,\n pending_tagged_log.context,\n scope,\n );\n }\n });\n\n if offchain_inbox_sync.is_some() {\n let msgs = offchain_inbox_sync.unwrap()(contract_address, scope);\n msgs.for_each(|_i, msg: OffchainMessageWithContext| {\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n msg.message_ciphertext,\n msg.message_context,\n scope,\n );\n });\n }\n\n // Then we process all pending partial notes, regardless of whether they were found in the current or previous\n // executions.\n partial_notes::fetch_and_process_partial_note_completion_logs(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n scope,\n );\n\n // Finally we validate all notes and events that were found as part of the previous processes, resulting in them\n // being added to PXE's database and retrievable via oracles (get_notes) and our TS API (PXE::getPrivateEvents).\n validate_and_store_enqueued_notes_and_events(scope);\n}\n\nmod test {\n use crate::ephemeral::EphemeralArray;\n use crate::messages::{\n discovery::{CustomMessageHandler, do_sync_state},\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{offchain::OffchainInboxSync, pending_tagged_log::PendingTaggedLog},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n\n #[test]\n unconstrained fn do_sync_state_does_not_panic_on_empty_logs() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n\n let contract_address = AztecAddress { inner: 0xdeadbeef };\n\n env.utility_context_at(contract_address, |_| {\n // Mock the oracle call to return a known base slot, then populate an ephemeral\n // array at that slot so do_sync_state processes a non-empty log list.\n let base_slot = 42;\n let mock = std::test::OracleMock::mock(\"aztec_utl_getPendingTaggedLogs_v2\");\n let _ = mock.returns(base_slot);\n\n let logs: EphemeralArray = EphemeralArray::at(base_slot);\n logs.push(PendingTaggedLog { log: BoundedVec::new(), context: std::mem::zeroed() });\n assert_eq(logs.len(), 1);\n\n let no_handler: Option> = Option::none();\n let no_inbox_sync: Option> = Option::none();\n do_sync_state(\n contract_address,\n dummy_compute_note_hash,\n dummy_compute_note_nullifier,\n no_handler,\n no_inbox_sync,\n scope,\n );\n });\n }\n\n unconstrained fn dummy_compute_note_hash(\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n\n unconstrained fn dummy_compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr","function_locations":[{"start":6465,"name":"do_sync_state"},{"start":9175,"name":"test::do_sync_state_does_not_panic_on_empty_logs"},{"start":10673,"name":"test::dummy_compute_note_hash"},{"start":11034,"name":"test::dummy_compute_note_nullifier"}]},"128":{"source":"use crate::messages::{discovery::{ComputeNoteHash, ComputeNoteNullifier}, logs::note::MAX_NOTE_PACKED_LEN};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{\n address::AztecAddress,\n constants::MAX_NOTE_HASHES_PER_TX,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::ToField,\n};\n\n/// A struct with the discovered information of a complete note, required for delivery to PXE. Note that this is *not*\n/// the complete note information, since it does not include content, storage slot, etc.\npub(crate) struct DiscoveredNoteInfo {\n pub(crate) note_nonce: Field,\n pub(crate) note_hash: Field,\n pub(crate) inner_nullifier: Field,\n}\n\n/// Searches for note nonces that will result in a note that was emitted in a transaction. While rare, it is possible\n/// for multiple notes to have the exact same packed content and storage slot but different nonces, resulting in\n/// different unique note hashes. Because of this this function returns a *vector* of discovered notes, though in most\n/// cases it will contain a single element.\n///\n/// Due to how nonces are computed, this function requires knowledge of the transaction in which the note was created,\n/// more specifically the list of all unique note hashes in it plus the value of its first nullifier.\npub(crate) unconstrained fn attempt_note_nonce_discovery(\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) -> BoundedVec {\n let discovered_notes = &mut BoundedVec::new();\n\n aztecnr_debug_log_format!(\n \"Attempting nonce discovery on {0} potential notes on contract {1} for storage slot {2}\",\n )(\n [unique_note_hashes_in_tx.len() as Field, contract_address.to_field(), storage_slot],\n );\n\n let maybe_note_hash = compute_note_hash(\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_note_hash.is_none() {\n aztecnr_warn_log_format!(\n \"Unable to compute note hash for note of id {0} with packed length {1}, skipping nonce discovery\",\n )(\n [note_type_id, packed_note.len() as Field],\n );\n } else {\n let note_hash = maybe_note_hash.unwrap();\n let siloed_note_hash = compute_siloed_note_hash(contract_address, note_hash);\n\n // We need to find nonces (typically just one) that result in the siloed note hash that being uniqued into one\n // of the transaction's effects.\n // The nonce is meant to be derived from the index of the note hash in the transaction effects array. However,\n // due to an issue in the kernels the nonce might actually use any of the possible note hash indices - not\n // necessarily the one that corresponds to the note hash. Hence, we need to try them all.\n for i in 0..MAX_NOTE_HASHES_PER_TX {\n let nonce_for_i = compute_note_hash_nonce(first_nullifier_in_tx, i);\n let unique_note_hash_for_i = compute_unique_note_hash(nonce_for_i, siloed_note_hash);\n\n let matching_notes = bvec_filter(\n unique_note_hashes_in_tx,\n |unique_note_hash_in_tx| unique_note_hash_in_tx == unique_note_hash_for_i,\n );\n if matching_notes.len() > 1 {\n let identical_note_hashes = matching_notes.len();\n // Note that we don't actually check that the note hashes array contains unique values, only that the\n // note we found is unique. We don't expect for this to ever happen (it'd indicate a malicious node or\n // PXE, which are both assumed to be cooperative) so testing for it just in case is unnecessary, but we\n // _do_ need to handle it if we find a duplicate.\n panic(\n f\"Received {identical_note_hashes} identical note hashes for a transaction - these should all be unique\",\n )\n } else if matching_notes.len() == 1 {\n let maybe_inner_nullifier_for_i = compute_note_nullifier(\n unique_note_hash_for_i,\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_inner_nullifier_for_i.is_none() {\n // TODO: down the line we want to be able to store notes for which we don't know their nullifier,\n // e.g. notes that belong to someone that is not us (and for which we therefore don't know their\n // associated app-siloed nullifer hiding secret key).\n // https://linear.app/aztec-labs/issue/F-265/store-external-notes\n aztecnr_warn_log_format!(\n \"Unable to compute nullifier of unique note {0} with note type id {1} and owner {2}, skipping PXE insertion\",\n )(\n [unique_note_hash_for_i, note_type_id, owner.to_field()],\n );\n } else {\n // Note that while we did check that the note hash is the preimage of a unique note hash, we\n // perform no validations on the nullifier - we fundamentally cannot, since only the application\n // knows how to compute nullifiers. We simply trust it to have provided the correct one: if it\n // hasn't, then PXE may fail to realize that a given note has been nullified already, and calls to\n // the application could result in invalid transactions (with duplicate nullifiers). This is not a\n // concern because an application already has more direct means of making a call to it fail the\n // transaction.\n discovered_notes.push(\n DiscoveredNoteInfo {\n note_nonce: nonce_for_i,\n note_hash,\n inner_nullifier: maybe_inner_nullifier_for_i.unwrap(),\n },\n );\n }\n // We don't exit the loop - it is possible (though rare) for the exact same note content to be present\n // multiple times in the same transaction with different nonces. This typically doesn't happen due to\n // notes containing random values in order to hide their contents.\n }\n }\n }\n\n *discovered_notes\n}\n\n// There is no BoundedVec::filter in the stdlib, so we use this until that is implemented.\nunconstrained fn bvec_filter(\n bvec: BoundedVec,\n filter: fn[Env](T) -> bool,\n) -> BoundedVec {\n let filtered = &mut BoundedVec::new();\n\n bvec.for_each(|value| {\n if filter(value) {\n filtered.push(value);\n }\n });\n\n *filtered\n}\n\nmod test {\n use crate::{\n messages::logs::note::MAX_NOTE_PACKED_LEN,\n note::{\n note_interface::{NoteHash, NoteType},\n note_metadata::SettledNoteMetadata,\n utils::compute_note_hash_for_nullification,\n },\n oracle::random::random,\n test::mocks::mock_note::MockNote,\n utils::array,\n };\n\n use crate::protocol::{\n address::AztecAddress,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::{FromField, Packable},\n };\n\n use super::attempt_note_nonce_discovery;\n\n // This implementation could be simpler, but this serves as a nice example of the expected flow in a real\n // implementation, and as a sanity check that the interface is sufficient.\n\n unconstrained fn compute_note_hash(\n packed_note: BoundedVec,\n owner: AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n } else {\n Option::none()\n }\n }\n\n unconstrained fn compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n note.compute_nullifier_unconstrained(owner, unique_note_hash)\n } else {\n Option::none()\n }\n }\n\n global VALUE: Field = 7;\n global FIRST_NULLIFIER_IN_TX: Field = 47;\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress::from_field(13);\n global OWNER: AztecAddress = AztecAddress::from_field(14);\n global STORAGE_SLOT: Field = 99;\n global RANDOMNESS: Field = 99;\n\n #[test]\n unconstrained fn no_note_hashes() {\n let unique_note_hashes_in_tx = BoundedVec::new();\n let packed_note = BoundedVec::new();\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n packed_note,\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_hash_computation_is_ignored() {\n let unique_note_hashes_in_tx = BoundedVec::from_array([random()]);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n |_, _, _, _, _, _| Option::none(),\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::new(),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_nullifier_computation_is_ignored() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n |_, _, _, _, _, _, _| Option::none(),\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n struct NoteAndData {\n note: MockNote,\n note_nonce: Field,\n note_hash: Field,\n unique_note_hash: Field,\n inner_nullifier: Field,\n }\n\n unconstrained fn construct_note(value: Field, note_index_in_tx: u32) -> NoteAndData {\n let note_nonce = compute_note_hash_nonce(FIRST_NULLIFIER_IN_TX, note_index_in_tx);\n\n let hinted_note = MockNote::new(value)\n .contract_address(CONTRACT_ADDRESS)\n .owner(OWNER)\n .randomness(RANDOMNESS)\n .storage_slot(STORAGE_SLOT)\n .note_metadata(SettledNoteMetadata::new(note_nonce).into())\n .build_hinted_note();\n let note = hinted_note.note;\n\n let note_hash = note.compute_note_hash(OWNER, STORAGE_SLOT, RANDOMNESS);\n let unique_note_hash = compute_unique_note_hash(\n note_nonce,\n compute_siloed_note_hash(CONTRACT_ADDRESS, note_hash),\n );\n let inner_nullifier = note\n .compute_nullifier_unconstrained(OWNER, compute_note_hash_for_nullification(hinted_note))\n .expect(f\"Could not compute nullifier for note owned by {OWNER}\");\n\n NoteAndData { note, note_nonce, note_hash, unique_note_hash, inner_nullifier }\n }\n\n #[test]\n unconstrained fn single_note() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn multiple_notes_same_preimage() {\n let first_note_index_in_tx = 3;\n let first_note_and_data = construct_note(VALUE, first_note_index_in_tx);\n\n let second_note_index_in_tx = 5;\n let second_note_and_data = construct_note(VALUE, second_note_index_in_tx);\n\n // Both notes have the same preimage (and therefore packed representation), so both should be found in the same\n // call.\n assert_eq(first_note_and_data.note, second_note_and_data.note);\n let packed_note = first_note_and_data.note.pack();\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(first_note_index_in_tx, first_note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(second_note_index_in_tx, second_note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(packed_note),\n );\n\n assert_eq(discovered_notes.len(), 2);\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == first_note_and_data.note_nonce)\n & (discovered_note.note_hash == first_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == first_note_and_data.inner_nullifier)\n }));\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == second_note_and_data.note_nonce)\n & (discovered_note.note_hash == second_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == second_note_and_data.inner_nullifier)\n }));\n }\n\n #[test]\n unconstrained fn single_note_misaligned_nonce() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The note is not at the correct index\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn single_note_nonce_with_index_past_note_hashes_in_tx() {\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The nonce is computed with an index that does not exist in the tx\n let note_index_in_tx = unique_note_hashes_in_tx.len() + 5;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n // The note is inserted at an arbitrary index - its true index is out of the array's bounds\n unique_note_hashes_in_tx.set(2, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test(should_fail_with = \"identical note hashes for a transaction\")]\n unconstrained fn duplicate_unique_note_hashes() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The same unique note hash is present in two indices in the array, which is not allowed. Note that we don't\n // test all note hashes for uniqueness, only those that we actually find.\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let _ = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/nonce_discovery.nr","function_locations":[{"start":1866,"name":"attempt_note_nonce_discovery"},{"start":7210,"name":"bvec_filter"},{"start":8458,"name":"test::compute_note_hash"},{"start":9107,"name":"test::compute_note_nullifier"},{"start":9764,"name":"test::no_note_hashes"},{"start":10362,"name":"test::failed_hash_computation_is_ignored"},{"start":10959,"name":"test::failed_nullifier_computation_is_ignored"},{"start":12052,"name":"test::construct_note"},{"start":13085,"name":"test::single_note"},{"start":14249,"name":"test::multiple_notes_same_preimage"},{"start":16275,"name":"test::single_note_misaligned_nonce"},{"start":17515,"name":"test::single_note_nonce_with_index_past_note_hashes_in_tx"},{"start":18937,"name":"test::duplicate_unique_note_hashes"}]},"129":{"source":"use crate::{\n capsules::CapsuleArray,\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::partial_note::{decode_partial_note_private_message, MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN},\n processing::{\n enqueue_note_for_validation,\n get_pending_partial_notes_completion_logs,\n log_retrieval_response::{LogRetrievalResponse, MAX_LOG_CONTENT_LEN},\n },\n },\n utils::array,\n};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{address::AztecAddress, hash::sha256_to_field, traits::{Deserialize, Serialize}};\n\n/// The slot in the PXE capsules where we store a `CapsuleArray` of `DeliveredPendingPartialNote`.\npub(crate) global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT\".as_bytes(),\n);\n\n/// A partial note that was delivered but is still pending completion. Contains the information necessary to find the\n/// log that will complete it and lead to a note being discovered and delivered.\n#[derive(Serialize, Deserialize)]\npub(crate) struct DeliveredPendingPartialNote {\n pub(crate) owner: AztecAddress,\n pub(crate) randomness: Field,\n pub(crate) note_completion_log_tag: Field,\n pub(crate) note_type_id: Field,\n pub(crate) packed_private_note_content: BoundedVec,\n}\n\npub(crate) unconstrained fn process_partial_note_private_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n scope: AztecAddress,\n) {\n let decoded = decode_partial_note_private_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n // We store the information of the partial note we found in a persistent capsule in PXE, so that we can later\n // search for the public log that will complete it.\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content) = decoded.unwrap();\n\n let pending = DeliveredPendingPartialNote {\n owner,\n randomness,\n note_completion_log_tag,\n note_type_id,\n packed_private_note_content,\n };\n\n CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n )\n .push(pending);\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode partial note private message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Searches for logs that would result in the completion of pending partial notes, ultimately resulting in the notes\n/// being delivered to PXE if completed.\npub(crate) unconstrained fn fetch_and_process_partial_note_completion_logs(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n scope: AztecAddress,\n) {\n let pending_partial_notes = CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n );\n\n aztecnr_debug_log_format!(\"{} pending partial notes\")([pending_partial_notes.len() as Field]);\n\n // Each of the pending partial notes might get completed by a log containing its public values. For performance\n // reasons, we fetch all of these logs concurrently and then process them one by one, minimizing the amount of time\n // waiting for the node roundtrip.\n let maybe_completion_logs = get_pending_partial_notes_completion_logs(contract_address, pending_partial_notes);\n\n // Each entry in the maybe completion logs array corresponds to the entry in the pending partial notes array at the\n // same index. This means we can use the same index as we iterate through the responses to get both the partial\n // note and the log that might complete it.\n assert_eq(maybe_completion_logs.len(), pending_partial_notes.len());\n\n maybe_completion_logs.for_each(|i, maybe_log: Option| {\n let pending_partial_note = pending_partial_notes.get(i);\n\n if maybe_log.is_none() {\n aztecnr_debug_log_format!(\"Found no completion logs for partial note with tag {}\")(\n [pending_partial_note.note_completion_log_tag],\n );\n\n // Note that we're not removing the pending partial note from the capsule array, so we will continue\n // searching for this tagged log when performing message discovery in the future until we either find it or\n // the entry is somehow removed from the array.\n } else {\n aztecnr_debug_log_format!(\"Completion log found for partial note with tag {}\")([\n pending_partial_note.note_completion_log_tag,\n ]);\n let log = maybe_log.unwrap();\n\n // The first field in the completion log payload is the storage slot, followed by the public note\n // content fields.\n let storage_slot = log.log_payload.get(0);\n let public_note_content: BoundedVec = array::subbvec(log.log_payload, 1);\n\n // Public fields are assumed to all be placed at the end of the packed representation, so we combine\n // the private and public packed fields (i.e. the contents of the private message and public log\n // plaintext) to get the complete packed content.\n let complete_packed_note = array::append(\n pending_partial_note.packed_private_note_content,\n public_note_content,\n );\n\n let discovered_notes = attempt_note_nonce_discovery(\n log.unique_note_hashes_in_tx,\n log.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n pending_partial_note.note_type_id,\n complete_packed_note,\n );\n\n // TODO(#11627): is there anything reasonable we can do if we get a log but it doesn't result in a note\n // being found?\n if discovered_notes.len() == 0 {\n panic(\n f\"A partial note's completion log did not result in any notes being found - this should never happen\",\n );\n }\n\n aztecnr_debug_log_format!(\"Discovered {0} notes for partial note with tag {1}\")([\n discovered_notes.len() as Field,\n pending_partial_note.note_completion_log_tag,\n ]);\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n discovered_note.note_nonce,\n complete_packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n log.tx_hash,\n );\n });\n\n // Because there is only a single log for a given tag, once we've processed the tagged log then we simply\n // delete the pending work entry, regardless of whether it was actually completed or not.\n pending_partial_notes.remove(i);\n }\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr","function_locations":[{"start":1784,"name":"process_partial_note_private_msg"},{"start":3162,"name":"fetch_and_process_partial_note_completion_logs"}]},"130":{"source":"use crate::{\n event::event_interface::compute_private_serialized_event_commitment,\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::MAX_MESSAGE_CONTENT_LEN, logs::event::decode_private_event_message,\n processing::enqueue_event_for_validation,\n },\n};\nuse crate::protocol::{address::AztecAddress, traits::ToField};\n\npub(crate) unconstrained fn process_private_event_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n) {\n let decoded = decode_private_event_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (event_type_id, randomness, serialized_event) = decoded.unwrap();\n\n let event_commitment =\n compute_private_serialized_event_commitment(serialized_event, randomness, event_type_id.to_field());\n\n enqueue_event_for_validation(\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private event message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_events.nr","function_locations":[{"start":547,"name":"process_private_event_msg"}]},"131":{"source":"use crate::{\n logging::{aztecnr_debug_log_format, aztecnr_warn_log_format},\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::{decode_private_note_message, MAX_NOTE_PACKED_LEN},\n processing::enqueue_note_for_validation,\n },\n protocol::{address::AztecAddress, constants::MAX_NOTE_HASHES_PER_TX, traits::ToField},\n};\n\npub(crate) unconstrained fn process_private_note_msg(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n msg_metadata: u64,\n msg_content: BoundedVec,\n) {\n let decoded = decode_private_note_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (note_type_id, owner, storage_slot, randomness, packed_note) = decoded.unwrap();\n\n attempt_note_discovery(\n contract_address,\n tx_hash,\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private note message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Attempts discovery of a note given information about its contents and the transaction in which it is suspected the\n/// note was created.\npub unconstrained fn attempt_note_discovery(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) {\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n\n if discovered_notes.len() == 0 {\n // A private note message that results in no discovered notes means none of the computed note hashes matched\n // any unique note hash in the transaction. This could indicate a malformed or malicious message (e.g. a sender\n // providing bogus note content).\n aztecnr_warn_log_format!(\n \"Discarding private note message from tx {0} for contract {1}: no matching note hash found in the tx\",\n )(\n [tx_hash, contract_address.to_field()],\n );\n } else {\n aztecnr_debug_log_format!(\n \"Discovered {0} notes from a private message for contract {1}\",\n )(\n [discovered_notes.len() as Field, contract_address.to_field()],\n );\n }\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n owner,\n storage_slot,\n randomness,\n discovered_note.note_nonce,\n packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n tx_hash,\n );\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_notes.nr","function_locations":[{"start":861,"name":"process_private_note_msg"},{"start":2185,"name":"attempt_note_discovery"}]},"132":{"source":"use crate::messages::{\n discovery::{\n ComputeNoteHash, ComputeNoteNullifier, CustomMessageHandler, partial_notes::process_partial_note_private_msg,\n private_events::process_private_event_msg, private_notes::process_private_note_msg,\n },\n encoding::{decode_message, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN},\n encryption::{aes128::AES128, message_encryption::MessageEncryption},\n msg_type::{\n MIN_CUSTOM_MSG_TYPE_ID, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID, PRIVATE_EVENT_MSG_TYPE_ID, PRIVATE_NOTE_MSG_TYPE_ID,\n },\n processing::MessageContext,\n};\n\nuse crate::logging::{aztecnr_debug_log, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\n/// Processes a message that can contain notes, partial notes, or events.\n///\n/// Notes result in nonce discovery being performed prior to delivery, which requires knowledge of the transaction hash\n/// in which the notes would've been created (typically the same transaction in which the log was emitted), along with\n/// the list of unique note hashes in said transaction and the `compute_note_hash` and `compute_note_nullifier`\n/// functions. Once discovered, the notes are enqueued for validation.\n///\n/// Partial notes result in a pending partial note entry being stored in a PXE capsule, which will later be retrieved\n/// to search for the note's completion public log.\n///\n/// Events are processed by computing an event commitment from the serialized event data and its randomness field, then\n/// enqueueing the event data and commitment for validation.\npub unconstrained fn process_message_ciphertext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_ciphertext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n let message_plaintext_option = AES128::decrypt(message_ciphertext, recipient, contract_address);\n\n if message_plaintext_option.is_some() {\n process_message_plaintext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_plaintext_option.unwrap(),\n message_context,\n recipient,\n );\n } else {\n aztecnr_warn_log_format!(\"Could not decrypt message ciphertext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n\npub(crate) unconstrained fn process_message_plaintext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_plaintext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n // The first thing to do after decrypting the message is to determine what type of message we're processing. We\n // have 3 message types: private notes, partial notes and events.\n\n // We decode the message to obtain the message type id, metadata and content.\n let decoded = decode_message(message_plaintext);\n\n if decoded.is_some() {\n let (msg_type_id, msg_metadata, msg_content) = decoded.unwrap();\n\n if msg_type_id == PRIVATE_NOTE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private note msg\");\n\n process_private_note_msg(\n contract_address,\n message_context.tx_hash,\n message_context.unique_note_hashes_in_tx,\n message_context.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n msg_metadata,\n msg_content,\n );\n } else if msg_type_id == PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing partial note private msg\");\n\n process_partial_note_private_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n recipient,\n );\n } else if msg_type_id == PRIVATE_EVENT_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private event msg\");\n\n process_private_event_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n );\n } else if msg_type_id < MIN_CUSTOM_MSG_TYPE_ID {\n // The message type ID falls in the range reserved for aztec.nr built-in types but wasn't matched above.\n // This most likely means the message is malformed or a custom message was incorrectly assigned a reserved\n // ID. Custom message types must use IDs allocated via `custom_msg_type_id`.\n aztecnr_warn_log_format!(\n \"Message type ID {0} is in the reserved range but is not recognized, ignoring. See https://docs.aztec.network/errors/3\",\n )(\n [msg_type_id as Field],\n );\n } else if process_custom_message.is_some() {\n process_custom_message.unwrap()(\n contract_address,\n msg_type_id,\n msg_metadata,\n msg_content,\n message_context,\n recipient,\n );\n } else {\n // A custom message was received but no handler is configured. This likely means the contract emits custom\n // messages but forgot to register a handler via `AztecConfig::custom_message_handler`.\n aztecnr_warn_log_format!(\n \"Received custom message with type id {0} but no handler is configured, ignoring. See https://docs.aztec.network/errors/2\",\n )(\n [msg_type_id as Field],\n );\n }\n } else {\n aztecnr_warn_log_format!(\"Could not decode message plaintext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/process_message.nr","function_locations":[{"start":1975,"name":"process_message_ciphertext"},{"start":2968,"name":"process_message_plaintext"}]},"133":{"source":"// TODO(#12750): don't make these values assume we're using AES.\nuse crate::protocol::constants::PRIVATE_LOG_CIPHERTEXT_LEN;\nuse crate::utils::array;\n\n// We reassign to the constant here to communicate the distinction between a log and a message. In Aztec.nr, unlike in\n// protocol circuits, we have a concept of a message that can be emitted either as a private log or as an offchain\n// message. Message is a piece of data that is to be eventually delivered to a contract via the `process_message(...)`\n// utility function function that is injected by the #[aztec] macro. Note: PRIVATE_LOG_CIPHERTEXT_LEN is an amount of\n// fields, so MESSAGE_CIPHERTEXT_LEN is the size of the message in fields.\npub global MESSAGE_CIPHERTEXT_LEN: u32 = PRIVATE_LOG_CIPHERTEXT_LEN;\n\n// TODO(#12750): The global variables below should not be here as they are AES128 specific.\n// The header plaintext is 2 bytes (ciphertext length), padded to the 16-byte AES block size by PKCS#7.\npub(crate) global HEADER_CIPHERTEXT_SIZE_IN_BYTES: u32 = 16;\n// AES PKCS#7 always adds at least one byte of padding. Since each plaintext field is 32 bytes (a multiple of the\n// 16-byte AES block size), a full 16-byte padding block is always appended.\npub(crate) global AES128_PKCS7_EXPANSION_IN_BYTES: u32 = 16;\n\npub global EPH_PK_X_SIZE_IN_FIELDS: u32 = 1;\n\n// (15 - 1) * 31 - 16 - 16 = 402. Note: We multiply by 31 because ciphertext bytes are stored in fields using\n// encode_bytes_as_fields, which packs 31 bytes per field (since a Field is ~254 bits and can safely store 31 whole\n// bytes).\npub(crate) global MESSAGE_PLAINTEXT_SIZE_IN_BYTES: u32 = (MESSAGE_CIPHERTEXT_LEN - EPH_PK_X_SIZE_IN_FIELDS) * 31\n - HEADER_CIPHERTEXT_SIZE_IN_BYTES\n - AES128_PKCS7_EXPANSION_IN_BYTES;\n// The plaintext bytes represent Field values that were originally serialized using encode_fields_as_bytes, which\n// converts each Field to 32 bytes. To convert the plaintext bytes back to fields, we divide by 32. 402 / 32 = 12\npub global MESSAGE_PLAINTEXT_LEN: u32 = MESSAGE_PLAINTEXT_SIZE_IN_BYTES / 32;\n\npub global MESSAGE_EXPANDED_METADATA_LEN: u32 = 1;\n\n// The standard message layout is composed of:\n// - an initial field called the 'expanded metadata'\n// - an arbitrary number of fields following that called the 'message content'\n//\n// ```\n// message: [ msg_expanded_metadata, ...msg_content ]\n// ```\n//\n// The expanded metadata itself is interpreted as a u128, of which:\n// - the upper 64 bits are the message type id\n// - the lower 64 bits are called the 'message metadata'\n//\n// ```\n// msg_expanded_metadata: [ msg_type_id | msg_metadata ]\n// <--- 64 bits --->|<--- 64 bits --->\n// ```\n//\n// The meaning of the message metadata and message content depend on the value of the message type id. Note that there\n// is nothing special about the message metadata, it _can_ be considered part of the content. It just has a different\n// name to make it distinct from the message content given that it is not a full field.\n\n/// The maximum length of a message's content, i.e. not including the expanded message metadata.\npub global MAX_MESSAGE_CONTENT_LEN: u32 = MESSAGE_PLAINTEXT_LEN - MESSAGE_EXPANDED_METADATA_LEN;\n\n/// Encodes a message following aztec-nr's standard message encoding. This message can later be decoded with\n/// `decode_message` to retrieve the original values.\n///\n/// - The `msg_type` is an identifier that groups types of messages that are all processed the same way, e.g. private\n/// notes or events. Possible values are defined in `aztec::messages::msg_type`.\n/// - The `msg_metadata` and `msg_content` are the values stored in the message, whose meaning depends on the\n/// `msg_type`. The only special thing about `msg_metadata` that separates it from `msg_content` is that it is a u64\n/// instead of a full Field (due to details of how messages are encoded), allowing applications that can fit values\n/// into this smaller variable to achieve higher data efficiency.\npub fn encode_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; N],\n) -> [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] {\n std::static_assert(\n msg_content.len() <= MAX_MESSAGE_CONTENT_LEN,\n \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\",\n );\n\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n let mut message: [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] = std::mem::zeroed();\n\n message[0] = to_expanded_metadata(msg_type, msg_metadata);\n for i in 0..msg_content.len() {\n message[MESSAGE_EXPANDED_METADATA_LEN + i] = msg_content[i];\n }\n\n message\n}\n\n/// Decodes a standard aztec-nr message, i.e. one created via `encode_message`, returning the original encoded values.\n///\n/// Returns `None` if the message is empty or has invalid (>128 bit) expanded metadata.\n///\n/// Note that `encode_message` returns a fixed size array while this function takes a `BoundedVec`: this is because\n/// prior to decoding the message type is unknown, and consequentially not known at compile time. If working with\n/// fixed-size messages, consider using `BoundedVec::from_array` to convert them.\npub unconstrained fn decode_message(\n message: BoundedVec,\n) -> Option<(u64, u64, BoundedVec)> {\n Option::some(message)\n .and_then(|message| {\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring\n // of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n if message.len() < MESSAGE_EXPANDED_METADATA_LEN {\n Option::none()\n } else {\n Option::some(message.get(0))\n }\n })\n .and_then(|msg_expanded_metadata| from_expanded_metadata(msg_expanded_metadata))\n .map(|(msg_type_id, msg_metadata)| {\n let msg_content = array::subbvec(message, MESSAGE_EXPANDED_METADATA_LEN);\n (msg_type_id, msg_metadata, msg_content)\n })\n}\n\nglobal U64_SHIFT_MULTIPLIER: Field = 2.pow_32(64);\n\nfn to_expanded_metadata(msg_type: u64, msg_metadata: u64) -> Field {\n // We use multiplication instead of bit shifting operations to shift the type bits as bit shift operations are\n // expensive in circuits.\n let type_field: Field = (msg_type as Field) * U64_SHIFT_MULTIPLIER;\n let msg_metadata_field = msg_metadata as Field;\n\n type_field + msg_metadata_field\n}\n\nglobal TWO_POW_128: Field = 2.pow_32(128);\n\n/// Unpacks expanded metadata into (msg_type, msg_metadata). Returns `None` if `input >= 2^128`.\nfn from_expanded_metadata(input: Field) -> Option<(u64, u64)> {\n if input.lt(TWO_POW_128) {\n let msg_metadata = (input as u64);\n let msg_type = ((input - (msg_metadata as Field)) / U64_SHIFT_MULTIPLIER) as u64;\n // Use division instead of bit shift since bit shifts are expensive in circuits\n Option::some((msg_type, msg_metadata))\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray::subarray;\n use super::{\n decode_message, encode_message, from_expanded_metadata, MAX_MESSAGE_CONTENT_LEN, to_expanded_metadata,\n TWO_POW_128,\n };\n\n global U64_MAX: u64 = (2.pow_32(64) - 1) as u64;\n global U128_MAX: Field = (2.pow_32(128) - 1);\n\n #[test]\n unconstrained fn encode_decode_empty_message(msg_type: u64, msg_metadata: u64) {\n let encoded = encode_message(msg_type, msg_metadata, []);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), 0);\n }\n\n #[test]\n unconstrained fn encode_decode_short_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN / 2],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn encode_decode_full_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn to_expanded_metadata_packing() {\n // Test case 1: All bits set\n let packed = to_expanded_metadata(U64_MAX, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let packed = to_expanded_metadata(U64_MAX, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let packed = to_expanded_metadata(0, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let packed = to_expanded_metadata(0, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn from_expanded_metadata_packing() {\n // Test case 1: All bits set\n let input = U128_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let input = (U128_MAX - U64_MAX as Field);\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let input = U64_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let input = 0;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn to_from_expanded_metadata(original_msg_type: u64, original_msg_metadata: u64) {\n let packed = to_expanded_metadata(original_msg_type, original_msg_metadata);\n let (unpacked_msg_type, unpacked_msg_metadata) = from_expanded_metadata(packed).unwrap();\n\n assert_eq(original_msg_type, unpacked_msg_type);\n assert_eq(original_msg_metadata, unpacked_msg_metadata);\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_message() {\n let msg_type_id: u64 = 42;\n let msg_metadata: u64 = 99;\n let mut msg_content = [0; MAX_MESSAGE_CONTENT_LEN];\n for i in 0..MAX_MESSAGE_CONTENT_LEN {\n msg_content[i] = i as Field;\n }\n\n let encoded = encode_message(msg_type_id, msg_metadata, msg_content);\n let (decoded_type_id, decoded_metadata, decoded_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_type_id, msg_type_id);\n assert_eq(decoded_metadata, msg_metadata);\n assert_eq(decoded_content, BoundedVec::from_array(msg_content));\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_message_fails() {\n let msg_content = [0; MAX_MESSAGE_CONTENT_LEN + 1];\n let _ = encode_message(0, 0, msg_content);\n }\n\n #[test]\n unconstrained fn decode_empty_message_returns_none() {\n assert(decode_message(BoundedVec::new()).is_none());\n }\n\n #[test]\n unconstrained fn decode_message_with_oversized_metadata_returns_none() {\n let message = BoundedVec::from_array([TWO_POW_128]);\n assert(decode_message(message).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encoding.nr","function_locations":[{"start":4136,"name":"encode_message"},{"start":5594,"name":"decode_message"},{"start":6617,"name":"to_expanded_metadata"},{"start":7131,"name":"from_expanded_metadata"},{"start":7894,"name":"tests::encode_decode_empty_message"},{"start":8444,"name":"tests::encode_decode_short_message"},{"start":9090,"name":"tests::encode_decode_full_message"},{"start":9628,"name":"tests::to_expanded_metadata_packing"},{"start":10713,"name":"tests::from_expanded_metadata_packing"},{"start":11770,"name":"tests::to_from_expanded_metadata"},{"start":12151,"name":"tests::encode_decode_max_size_message"},{"start":12934,"name":"tests::encode_oversized_message_fails"},{"start":13123,"name":"tests::decode_empty_message_returns_none"},{"start":13280,"name":"tests::decode_message_with_oversized_metadata_returns_none"}]},"134":{"source":"use crate::protocol::{address::AztecAddress, public_keys::AddressPoint, traits::ToField};\n\nuse crate::{\n keys::{\n ecdh_shared_secret::{\n compute_app_siloed_shared_secret, derive_ecdh_shared_secret, derive_shared_secret_field_mask,\n derive_shared_secret_subkey,\n },\n ephemeral::generate_positive_ephemeral_key_pair,\n },\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::{\n EPH_PK_X_SIZE_IN_FIELDS, HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN,\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES,\n },\n encryption::message_encryption::MessageEncryption,\n logs::arithmetic_generics_utils::{\n get_arr_of_size__message_bytes__from_PT, get_arr_of_size__message_bytes_padding__from_PT,\n },\n },\n oracle::{aes128_decrypt::try_aes128_decrypt, random::random, shared_secret::get_shared_secret},\n utils::{\n array,\n conversion::{\n bytes_as_fields::{decode_bytes_from_fields, encode_bytes_as_fields},\n fields_as_bytes::{encode_fields_as_bytes, try_decode_fields_from_bytes},\n },\n point::point_from_x_coord_and_sign,\n },\n};\n\nuse std::aes128::aes128_encrypt;\n\n/// Computes N close-to-uniformly-random 256 bits from a given app-siloed shared secret.\n///\n/// NEVER re-use the same iv and sym_key. DO NOT call this function more than once with the same s_app.\n///\n/// This function is only known to be safe if s_app is derived from combining a random ephemeral key with an\n/// address point and a contract address. See big comment within the body of the function.\nfn extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app: Field) -> [[u8; 32]; N] {\n /*\n * Unsafe because of https://eprint.iacr.org/2010/264.pdf Page 13, Lemma 2 (and the two paragraphs below it).\n *\n * If you call this function, you need to be careful and aware of how the arg `s_app` has been derived.\n *\n * The paper says that the way you derive aes keys and IVs should be fine with poseidon2 (modelled as a RO),\n * as long as you _don't_ use Poseidon2 as a PRG to generate the two exponents x & y which multiply to the\n * shared secret S:\n *\n * S = [x*y]*G.\n *\n * (Otherwise, you would have to \"key\" poseidon2, i.e. generate a uniformly string K which can be public and\n * compute Hash(x) as poseidon(K,x)).\n * In that lemma, k would be 2*254=508, and m would be the number of points on the grumpkin curve (which is\n * close to r according to the Hasse bound).\n *\n * Our shared secret S is [esk * address_sk] * G, and the question is: Can we compute hash(S) using poseidon2\n * instead of sha256?\n *\n * Well, esk is random and not generated with poseidon2, so that's good.\n * What about address_sk?\n * Well, address_sk = poseidon2(stuff) + ivsk, so there was some discussion about whether address_sk is\n * independent of poseidon2. Given that ivsk is random and independent of poseidon2, the address_sk is also\n * independent of poseidon2.\n *\n * Tl;dr: we believe it's safe to hash S = [esk * address_sk] * G using poseidon2, in order to derive a\n * symmetric key.\n *\n * If you're calling this function for a differently-derived `s_app`, be careful.\n */\n \n\n /* The output of this function needs to be 32 random bytes.\n * A single field won't give us 32 bytes of entropy. So we compute two \"random\" fields, by poseidon-hashing\n * with two different indices. We then extract the last 16 (big endian) bytes of each \"random\" field.\n * Note: we use to_be_bytes because it's slightly more efficient. But we have to be careful not to take bytes\n * from the \"big end\", because the \"big\" byte is not uniformly random over the byte: it only has < 6 bits of\n * randomness, because it's the big end of a 254-bit field element.\n */\n\n let mut all_bytes: [[u8; 32]; N] = std::mem::zeroed();\n std::static_assert(N < 256, \"N too large\");\n for k in 0..N {\n let rand1: Field = derive_shared_secret_subkey(s_app, 2 * k);\n let rand2: Field = derive_shared_secret_subkey(s_app, 2 * k + 1);\n\n let rand1_bytes: [u8; 32] = rand1.to_be_bytes();\n let rand2_bytes: [u8; 32] = rand2.to_be_bytes();\n\n let mut bytes: [u8; 32] = [0; 32];\n for i in 0..16 {\n // We take bytes from the \"little end\" of the be-bytes arrays:\n let j = 32 - i - 1;\n bytes[i] = rand1_bytes[j];\n bytes[16 + i] = rand2_bytes[j];\n }\n\n all_bytes[k] = bytes;\n }\n\n all_bytes\n}\n\nfn derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(\n many_random_256_bits: [[u8; 32]; N],\n) -> [([u8; 16], [u8; 16]); N] {\n // Many (sym_key, iv) pairs:\n let mut many_pairs: [([u8; 16], [u8; 16]); N] = std::mem::zeroed();\n for k in 0..N {\n let random_256_bits = many_random_256_bits[k];\n let mut sym_key = [0; 16];\n let mut iv = [0; 16];\n for i in 0..16 {\n sym_key[i] = random_256_bits[i];\n iv[i] = random_256_bits[i + 16];\n }\n many_pairs[k] = (sym_key, iv);\n }\n\n many_pairs\n}\n\npub fn derive_aes_symmetric_key_and_iv_from_shared_secret(s_app: Field) -> [([u8; 16], [u8; 16]); N] {\n let many_random_256_bits: [[u8; 32]; N] = extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app);\n\n derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(many_random_256_bits)\n}\n\npub struct AES128 {}\n\nimpl MessageEncryption for AES128 {\n\n /// AES128-CBC encryption for Aztec protocol messages.\n ///\n /// ## Overview\n ///\n /// The plaintext is an array of up to `MESSAGE_PLAINTEXT_LEN` (12) fields. The output is always exactly\n /// `MESSAGE_CIPHERTEXT_LEN` (15) fields, regardless of plaintext size. All output fields except the\n /// ephemeral public key are uniformly random `Field` values to any observer without knowledge of the\n /// shared secret, making all encrypted messages indistinguishable by size or content.\n ///\n /// ## PKCS#7 Padding\n ///\n /// AES operates on 16-byte blocks, so the plaintext must be padded to a multiple of 16. PKCS#7 padding always\n /// adds at least 1 byte (so the receiver can always detect and strip it), which means:\n /// - 1 B plaintext -> 15 B padding -> 16 B total\n /// - 15 B plaintext -> 1 B padding -> 16 B total\n /// - 16 B plaintext -> 16 B padding -> 32 B total (full extra block)\n ///\n /// In general: if the plaintext is already a multiple of 16, a full 16-byte padding block is appended.\n ///\n /// ## Encryption Steps\n ///\n /// **1. Body encryption.** The plaintext fields are serialized to bytes (32 bytes per field) and AES-128-CBC\n /// encrypted. Since 32 is a multiple of 16, PKCS#7 always adds a full 16-byte padding block (see above):\n ///\n /// ```text\n /// +---------------------------------------------+\n /// | body ct |\n /// | PlaintextLen*32 + 16 B |\n /// +-------------------------------+--------------+\n /// | encrypted plaintext fields | PKCS#7 (16B) |\n /// | (serialized at 32 B each) | |\n /// +-------------------------------+--------------+\n /// ```\n ///\n /// **2. Header encryption.** The byte length of `body_ct` is stored as a 2-byte big-endian integer. This 2-byte\n /// header plaintext is then AES-encrypted; PKCS#7 pads the remaining 14 bytes to fill one 16-byte AES block,\n /// producing a 16-byte header ciphertext:\n ///\n /// ```text\n /// +---------------------------+\n /// | header ct |\n /// | 16 B |\n /// +--------+------------------+\n /// | body ct| PKCS#7 (14B) |\n /// | length | |\n /// | (2 B) | |\n /// +--------+------------------+\n /// ```\n ///\n /// ## Wire Format\n ///\n /// Messages are transmitted as fields, not bytes. A field is ~254 bits and can safely store 31 whole bytes, so\n /// we need to pack our byte data into 31-byte chunks. This packing drives the wire format.\n ///\n /// **Step 1 -- Assemble bytes.** The ciphertexts are laid out in a byte array, padded with zero bytes to a\n /// multiple of 31 so it divides evenly into fields:\n ///\n /// ```text\n /// +------------+-------------------------+---------+\n /// | header ct | body ct | byte pad|\n /// | 16 B | PlaintextLen*32 + 16 B | (zeros) |\n /// +------------+-------------------------+---------+\n /// |<-------- padded to a multiple of 31 B -------->|\n /// ```\n ///\n /// **Step 2 -- Pack and mask.** The byte array is split into 31-byte chunks, each stored in one field. A\n /// Poseidon2-derived mask (see `derive_shared_secret_field_mask`) is added to each so that the resulting\n /// fields appear as uniformly random `Field` values to any observer without knowledge of the shared secret,\n /// hiding the fact that the underlying ciphertext consists of 128-bit AES blocks.\n ///\n /// **Step 3 -- Assemble ciphertext.** The ephemeral public key x-coordinate is prepended and random field padding\n /// is appended to fill to 15 fields:\n ///\n /// ```text\n /// +----------+-------------------------+-------------------+\n /// | eph_pk.x | masked message fields | random field pad |\n /// | | (packed 31 B per field) | (fills to 15) |\n /// +----------+-------------------------+-------------------+\n /// |<---------- MESSAGE_CIPHERTEXT_LEN = 15 fields -------->|\n /// ```\n ///\n /// ## Key Derivation\n ///\n /// The raw ECDH shared secret point is first app-siloed into a scalar `s_app` by hashing with the contract\n /// address (see\n /// [`compute_app_siloed_shared_secret`](crate::keys::ecdh_shared_secret::compute_app_siloed_shared_secret)).\n /// Two (key, IV) pairs are then derived from `s_app` via indexed Poseidon2 hashing: one pair for the body\n /// ciphertext and one for the header ciphertext.\n fn encrypt(\n plaintext: [Field; PlaintextLen],\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> [Field; MESSAGE_CIPHERTEXT_LEN] {\n std::static_assert(\n PlaintextLen <= MESSAGE_PLAINTEXT_LEN,\n \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\",\n );\n\n // AES 128 operates on bytes, not fields, so we need to convert the fields to bytes. (This process is then\n // reversed when processing the message in `process_message_ciphertext`)\n let plaintext_bytes = encode_fields_as_bytes(plaintext);\n\n // Derive ECDH shared secret with recipient using a fresh ephemeral keypair.\n let (eph_sk, eph_pk) = generate_positive_ephemeral_key_pair();\n\n let raw_shared_secret = derive_ecdh_shared_secret(\n eph_sk,\n recipient\n .to_address_point()\n .unwrap_or_else(|| {\n aztecnr_warn_log_format!(\n \"Attempted to encrypt message for an invalid recipient ({0})\",\n )(\n [recipient.to_field()],\n );\n\n // Safety: if the recipient is an invalid address, then it is not possible to encrypt a message for\n // them because we cannot establish a shared secret. This is never expected to occur during normal\n // operation. However, it is technically possible for us to receive an invalid address, and we must\n // therefore handle it. We could simply fail, but that'd introduce a potential security issue in\n // which an attacker forces a contract to encrypt a message for an invalid address, resulting in an\n // impossible transaction - this is sometimes called a 'king of the hill' attack. We choose instead\n // to not fail and encrypt the plaintext regardless using the shared secret that results from a\n // random valid address. The sender is free to choose this address and hence shared secret, but\n // this has no security implications as they already know not only the full plaintext but also the\n // ephemeral private key anyway.\n unsafe {\n random_address_point()\n }\n })\n .inner,\n );\n\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n // It is safe to derive AES keys from `s_app` using Poseidon2 because `s_app` was derived from an ECDH shared\n // secret using an AztecAddress (the recipient). See the block comment in\n // `extract_many_close_to_uniformly_random_256_bits_using_poseidon2` for more info.\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n let ciphertext_bytes = aes128_encrypt(plaintext_bytes, body_iv, body_sym_key);\n\n // Each plaintext field is 32 bytes (a multiple of the 16-byte AES block\n // size), so PKCS#7 always appends a full 16-byte padding block:\n // |ciphertext| = PlaintextLen*32 + 16 = 16 * (1 + PlaintextLen*32 / 16)\n std::static_assert(\n ciphertext_bytes.len() == 16 * (1 + (PlaintextLen * 32) / 16),\n \"unexpected ciphertext length\",\n );\n\n // Encrypt a 2-byte header containing the body ciphertext length.\n let header_plaintext = encode_header(ciphertext_bytes.len());\n\n // Note: the aes128_encrypt builtin fn automatically appends bytes to the input, according to pkcs#7; hence why\n // the output `header_ciphertext_bytes` is 16 bytes larger than the input in this case.\n let header_ciphertext_bytes = aes128_encrypt(header_plaintext, header_iv, header_sym_key);\n // Verify expected header ciphertext size at compile time.\n std::static_assert(\n header_ciphertext_bytes.len() == HEADER_CIPHERTEXT_SIZE_IN_BYTES,\n \"unexpected ciphertext header length\",\n );\n\n // Assemble the message byte array:\n // [header_ct (16B)] [body_ct] [padding to mult of 31]\n let message_bytes_padding_to_mult_31 = get_arr_of_size__message_bytes_padding__from_PT::();\n\n let mut message_bytes = get_arr_of_size__message_bytes__from_PT::();\n\n std::static_assert(\n message_bytes.len() % 31 == 0,\n \"Unexpected error: message_bytes.len() should be divisible by 31, by construction.\",\n );\n\n let mut offset = 0;\n for i in 0..header_ciphertext_bytes.len() {\n message_bytes[offset + i] = header_ciphertext_bytes[i];\n }\n offset += header_ciphertext_bytes.len();\n\n for i in 0..ciphertext_bytes.len() {\n message_bytes[offset + i] = ciphertext_bytes[i];\n }\n offset += ciphertext_bytes.len();\n\n for i in 0..message_bytes_padding_to_mult_31.len() {\n message_bytes[offset + i] = message_bytes_padding_to_mult_31[i];\n }\n offset += message_bytes_padding_to_mult_31.len();\n\n // Ideally we would be able to have a static assert where we check that the offset would be such that we've\n // written to the entire log_bytes array, but we cannot since Noir does not treat the offset as a comptime\n // value (despite the values that it goes through being known at each stage). We instead check that the\n // computation used to obtain the offset computes the expected value (which we _can_ do in a static check), and\n // then add a cheap runtime check to also validate that the offset matches this.\n std::static_assert(\n header_ciphertext_bytes.len() + ciphertext_bytes.len() + message_bytes_padding_to_mult_31.len()\n == message_bytes.len(),\n \"unexpected message length\",\n );\n assert(offset == message_bytes.len(), \"unexpected encrypted message length\");\n\n // Pack message bytes into fields (31 bytes per field) and prepend eph_pk.x.\n let message_bytes_as_fields = encode_bytes_as_fields(message_bytes);\n\n let mut ciphertext: [Field; MESSAGE_CIPHERTEXT_LEN] = [0; MESSAGE_CIPHERTEXT_LEN];\n\n ciphertext[0] = eph_pk.x;\n\n // Mask each content field with a Poseidon2-derived value, so that they appear as uniformly random `Field`\n // values\n let mut offset = 1;\n for i in 0..message_bytes_as_fields.len() {\n let mask = derive_shared_secret_field_mask(s_app, i as u32);\n ciphertext[offset + i] = message_bytes_as_fields[i] + mask;\n }\n offset += message_bytes_as_fields.len();\n\n // Pad with random fields so that padding is indistinguishable from masked data fields.\n for i in offset..MESSAGE_CIPHERTEXT_LEN {\n // Safety: we assume that the sender wants for the message to be private - a malicious one could simply\n // reveal its contents publicly. It is therefore fine to trust the sender to provide random padding.\n ciphertext[i] = unsafe { random() };\n }\n\n ciphertext\n }\n\n unconstrained fn decrypt(\n ciphertext: BoundedVec,\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> Option> {\n // Extract the ephemeral public key x-coordinate and masked fields, returning None for empty ciphertext.\n if ciphertext.len() > 0 {\n let masked_fields: BoundedVec =\n array::subbvec(ciphertext, EPH_PK_X_SIZE_IN_FIELDS);\n Option::some((ciphertext.get(0), masked_fields))\n } else {\n Option::none()\n }\n .and_then(|(eph_pk_x, masked_fields)| {\n // With the x-coordinate of the ephemeral public key we can reconstruct the point as we know that the\n // y-coordinate must be positive. This may fail however, as not all x-coordinates are on the curve. In\n // that case, we simply return `Option::none`.\n point_from_x_coord_and_sign(eph_pk_x, true).and_then(|eph_pk| {\n let s_app = get_shared_secret(recipient, eph_pk, contract_address);\n\n let unmasked_fields = masked_fields.mapi(|i, field| {\n let unmasked = unmask_field(s_app, i, field);\n // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it\n // later, so we can simply set it to 0\n unmasked.unwrap_or(0)\n });\n let ciphertext_without_eph_pk_x = decode_bytes_from_fields(unmasked_fields);\n\n // Derive symmetric keys:\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n // Extract the header ciphertext\n let header_start = 0;\n let header_ciphertext: [u8; HEADER_CIPHERTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), header_start);\n // We need to convert the array to a BoundedVec because the oracle expects a BoundedVec as it's\n // designed to work with messages with unknown length at compile time. This would not be necessary\n // here as the header ciphertext length is fixed. But we do it anyway to not have to have duplicate\n // oracles.\n let header_ciphertext_bvec =\n BoundedVec::::from_array(header_ciphertext);\n\n try_aes128_decrypt(header_ciphertext_bvec, header_iv, header_sym_key)\n // Extract ciphertext length from header (2 bytes, big-endian)\n .and_then(|header_plaintext| extract_ciphertext_length(header_plaintext))\n .filter(|ciphertext_length| ciphertext_length <= MESSAGE_PLAINTEXT_SIZE_IN_BYTES)\n .map(|ciphertext_length| {\n // Extract and decrypt main ciphertext\n let ciphertext_start = header_start + HEADER_CIPHERTEXT_SIZE_IN_BYTES;\n let ciphertext_with_padding: [u8; MESSAGE_PLAINTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), ciphertext_start);\n BoundedVec::from_parts(ciphertext_with_padding, ciphertext_length)\n })\n // Decrypt main ciphertext and return it\n .and_then(|ciphertext| try_aes128_decrypt(ciphertext, body_iv, body_sym_key))\n // Convert bytes back to fields (32 bytes per field). Returns None if the actual bytes are\n // not valid.\n .and_then(|plaintext_bytes| try_decode_fields_from_bytes(plaintext_bytes))\n })\n })\n }\n}\n\n/// Encodes the body ciphertext length into a 2-byte big-endian header.\nfn encode_header(ciphertext_length: u32) -> [u8; 2] {\n [(ciphertext_length >> 8) as u8, ciphertext_length as u8]\n}\n\n/// Extracts the body ciphertext length from a decrypted header as a 2-byte big-endian integer.\n///\n/// Returns `Option::none()` if the header has fewer than 2 bytes.\nunconstrained fn extract_ciphertext_length(header: BoundedVec) -> Option {\n if header.len() >= 2 {\n Option::some(((header.get(0) as u32) << 8) | (header.get(1) as u32))\n } else {\n Option::none()\n }\n}\n\n/// 2^248: upper bound for values that fit in 31 bytes\nglobal TWO_POW_248: Field = 2.pow_32(248);\n\n/// Removes the Poseidon2-derived mask from a ciphertext field. Returns the unmasked value if it fits in 31 bytes\n/// (a content field), or `None` if it doesn't (random padding). Unconstrained to prevent accidental use in\n/// constrained context.\nunconstrained fn unmask_field(s_app: Field, index: u32, masked: Field) -> Option {\n let unmasked = masked - derive_shared_secret_field_mask(s_app, index);\n if unmasked.lt(TWO_POW_248) {\n Option::some(unmasked)\n } else {\n Option::none()\n }\n}\n\n/// Produces a random valid address point, i.e. one that is on the curve. This is equivalent to calling\n/// [`AztecAddress::to_address_point`] on a random valid address.\nunconstrained fn random_address_point() -> AddressPoint {\n let mut result = std::mem::zeroed();\n\n loop {\n // We simply produce random x coordinates until we find one that is on the curve. About half of the x\n // coordinates fulfill this condition, so this should only take a few iterations at most.\n let x_coord = random();\n let point = point_from_x_coord_and_sign(x_coord, true);\n if point.is_some() {\n result = AddressPoint { inner: point.unwrap() };\n break;\n }\n }\n\n result\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::{compute_app_siloed_shared_secret, derive_ecdh_shared_secret},\n messages::{\n encoding::{HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_PLAINTEXT_LEN, MESSAGE_PLAINTEXT_SIZE_IN_BYTES},\n encryption::message_encryption::MessageEncryption,\n },\n test::helpers::test_environment::TestEnvironment,\n };\n use crate::protocol::{address::AztecAddress, traits::FromField};\n use super::{AES128, encode_header, random_address_point};\n use std::{embedded_curve_ops::EmbeddedCurveScalar, test::OracleMock};\n\n #[test]\n unconstrained fn encrypt_decrypt_deterministic() {\n let env = TestEnvironment::new();\n\n // Message decryption requires oracles that are only available during private execution\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n\n let recipient = AztecAddress::from_field(\n 0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70c,\n );\n\n // Mock random values for deterministic test\n let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(eph_sk).times(1);\n\n let randomness = 0x0101010101010101010101010101010101010101010101010101010101010101;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(randomness).times(1000000);\n\n let _ = OracleMock::mock(\"aztec_prv_getNextAppTagAsSender\").returns(42);\n\n // Encrypt the message\n let encrypted_message = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n // Compute the same app-siloed shared secret that the oracle would return\n let raw_shared_secret = derive_ecdh_shared_secret(\n EmbeddedCurveScalar::from_field(eph_sk),\n recipient.to_address_point().unwrap().inner,\n );\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n let _ = OracleMock::mock(\"aztec_utl_getSharedSecret\").returns(s_app);\n\n // Decrypt the message\n let decrypted = AES128::decrypt(encrypted_message, recipient, contract_address).unwrap();\n\n // The decryption function spits out a BoundedVec because it's designed to work with messages with unknown\n // length at compile time. For this reason we need to convert the original input to a BoundedVec.\n let plaintext_bvec = BoundedVec::::from_array(plaintext);\n\n // Verify decryption matches original plaintext\n assert_eq(decrypted, plaintext_bvec, \"Decrypted bytes should match original plaintext\");\n\n // The following is a workaround of \"struct is never constructed\" Noir compilation error (we only ever use\n // static methods of the struct).\n let _ = AES128 {};\n });\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_random() {\n // Same as `encrypt_decrypt_deterministic`, except we don't mock any of the oracles and rely on\n // `TestEnvironment` instead.\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test]\n unconstrained fn encrypt_to_invalid_address() {\n // x = 3 is a non-residue for this curve, resulting in an invalid address\n let invalid_address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n\n let _ = AES128::encrypt([1, 2, 3, 4], invalid_address, contract_address);\n }\n\n // Documents the PKCS#7 padding behavior that `encrypt` relies on (see its static_assert).\n #[test]\n fn pkcs7_padding_always_adds_at_least_one_byte() {\n let key = [0 as u8; 16];\n let iv = [0 as u8; 16];\n\n // 1 byte input + 15 bytes padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 1], iv, key).len(), 16);\n\n // 15 bytes input + 1 byte padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 15], iv, key).len(), 16);\n\n // 16 bytes input (block-aligned) + full 16-byte padding block = 32 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 16], iv, key).len(), 32);\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_max_size_plaintext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let mut plaintext = [0; MESSAGE_PLAINTEXT_LEN];\n for i in 0..MESSAGE_PLAINTEXT_LEN {\n plaintext[i] = i as Field;\n }\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test(should_fail_with = \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\")]\n unconstrained fn encrypt_oversized_plaintext() {\n let address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n let plaintext: [Field; MESSAGE_PLAINTEXT_LEN + 1] = [0; MESSAGE_PLAINTEXT_LEN + 1];\n let _ = AES128::encrypt(plaintext, address, contract_address);\n }\n\n #[test]\n unconstrained fn random_address_point_produces_valid_points() {\n // About half of random addresses are invalid, so testing just a couple gives us high confidence that\n // `random_address_point` is indeed producing valid addresses.\n for _ in 0..10 {\n let random_address = AztecAddress { inner: random_address_point().inner.x };\n assert(random_address.to_address_point().is_some());\n }\n }\n\n #[test]\n unconstrained fn decrypt_invalid_ephemeral_public_key() {\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3, 4];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n // The first field of the ciphertext is the x-coordinate of the ephemeral public key. We set it to a known\n // non-residue (3), causing `decrypt` to fail to produce a decryption shared secret.\n let mut bad_ciphertext = BoundedVec::from_array(ciphertext);\n bad_ciphertext.set(0, 3);\n\n assert(AES128::decrypt(bad_ciphertext, recipient, contract_address).is_none());\n });\n }\n\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_ciphertext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n assert(AES128::decrypt(BoundedVec::new(), recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header AES decrypt oracle to return an empty result. The TS oracle never throws on invalid\n // input: it decrypts to garbage bytes or returns empty\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_header() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let empty_header = BoundedVec::::new();\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(empty_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header oracle to return a 2-byte header that decodes to a ciphertext_length one past the maximum\n // allowed value, verifying the edge case is handled correctly.\n #[test]\n unconstrained fn decrypt_returns_none_on_oversized_ciphertext_length() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let bad_header = BoundedVec::::from_array(encode_header(\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES + 1,\n ));\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(bad_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr","function_locations":[{"start":1764,"name":"extract_many_close_to_uniformly_random_256_bits_using_poseidon2"},{"start":4783,"name":"derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits"},{"start":5332,"name":"derive_aes_symmetric_key_and_iv_from_shared_secret"},{"start":10365,"name":"::encrypt"},{"start":17702,"name":"::decrypt"},{"start":21732,"name":"encode_header"},{"start":22063,"name":"extract_ciphertext_length"},{"start":22648,"name":"unmask_field"},{"start":23061,"name":"random_address_point"},{"start":24228,"name":"test::encrypt_decrypt_deterministic"},{"start":26706,"name":"test::encrypt_decrypt_random"},{"start":27552,"name":"test::encrypt_to_invalid_address"},{"start":28002,"name":"test::pkcs7_padding_always_adds_at_least_one_byte"},{"start":28566,"name":"test::encrypt_decrypt_max_size_plaintext"},{"start":29465,"name":"test::encrypt_oversized_plaintext"},{"start":29823,"name":"test::random_address_point_produces_valid_points"},{"start":30274,"name":"test::decrypt_invalid_ephemeral_public_key"},{"start":31119,"name":"test::decrypt_returns_none_on_empty_ciphertext"},{"start":31673,"name":"test::decrypt_returns_none_on_empty_header"},{"start":32599,"name":"test::decrypt_returns_none_on_oversized_ciphertext_length"}]},"139":{"source":"use crate::{\n event::{event_interface::EventInterface, EventSelector},\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n utils::array,\n};\nuse crate::protocol::traits::{FromField, Serialize, ToField};\n\n/// The number of fields in a private event message content that are not the event's serialized representation (1 field\n/// for randomness).\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 1;\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 0;\n\n/// The maximum length of the packed representation of an event's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, randomness, etc.).\npub global MAX_EVENT_SERIALIZED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_event_message`].\npub fn encode_private_event_message(\n event: Event,\n randomness: Field,\n) -> [Field; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Event: EventInterface + Serialize,\n{\n std::static_assert(\n ::N <= MAX_EVENT_SERIALIZED_LEN,\n \"event's serialized length exceeds the maximum allowed for private events\",\n );\n\n // We use `Serialize` because we want for events to be processable by off-chain actors, e.g. block explorers,\n // wallets and apps, without having to rely on contract invocation. If we used `Packable` we'd need to call utility\n // functions in order to unpack events, which would introduce a level of complexity we don't currently think is\n // worth the savings in DA (for public events) and proving time (when encrypting private event messages).\n let serialized_event = event.serialize();\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_plaintext = [0; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n\n for i in 0..serialized_event.len() {\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = serialized_event[i];\n }\n\n // The event type id is stored in the message metadata\n encode_message(\n PRIVATE_EVENT_MSG_TYPE_ID,\n Event::get_event_type_id().to_field() as u64,\n msg_plaintext,\n )\n}\n\n/// Decodes the plaintext from a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_event_message`].\n///\n/// Note that while [`encode_private_event_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_event_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(EventSelector, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let event_type_id = EventSelector::from_field(msg_metadata as Field);\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // destructuring of the private event message encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let randomness = msg_content.get(PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let serialized_event = array::subbvec(msg_content, PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((event_type_id, randomness, serialized_event))\n }\n}\n\nmod test {\n use crate::{\n event::event_interface::EventInterface,\n messages::{\n encoding::decode_message,\n logs::event::{decode_private_event_message, encode_private_event_message},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n };\n use crate::protocol::traits::Serialize;\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let event = MockEvent::new(VALUE).build_event();\n\n let message_plaintext = encode_private_event_message(event, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_EVENT_MSG_TYPE_ID);\n\n let (event_type_id, randomness, serialized_event) =\n decode_private_event_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(event_type_id, MockEvent::get_event_type_id());\n assert_eq(randomness, RANDOMNESS);\n assert_eq(serialized_event, BoundedVec::from_array(event.serialize()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_event_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0]);\n assert(decode_private_event_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/event.nr","function_locations":[{"start":1377,"name":"encode_private_event_message"},{"start":3755,"name":"decode_private_event_message"},{"start":5127,"name":"test::encode_decode"},{"start":5869,"name":"test::decode_empty_content_returns_none"},{"start":6064,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"141":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\n\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX: u32 = 1;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 2;\n\n/// The maximum length of the packed representation of a note's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, storage slot, randomness, etc.).\npub global MAX_NOTE_PACKED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_note_message`].\npub fn encode_private_note_message(\n note: Note,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n) -> [Field; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Note: NoteType + Packable,\n{\n let packed_note = note.pack();\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_content = [0; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX] = storage_slot;\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n for i in 0..packed_note.len() {\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_note[i];\n }\n\n // Notes use the note type id for metadata\n encode_message(PRIVATE_NOTE_MSG_TYPE_ID, Note::get_id() as u64, msg_content)\n}\n\n/// Decodes the plaintext from a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_note_message`].\n///\n/// Note that while [`encode_private_note_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_note_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(Field, AztecAddress, Field, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // decoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let owner = AztecAddress::from_field(msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX));\n let storage_slot = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX);\n let randomness = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let packed_note = array::subbvec(msg_content, PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((note_type_id, owner, storage_slot, randomness, packed_note))\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::note::{decode_private_note_message, encode_private_note_message, MAX_NOTE_PACKED_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global STORAGE_SLOT: Field = 9;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[derive(Packable)]\n struct MaxSizeNote {\n data: [Field; MAX_NOTE_PACKED_LEN],\n }\n\n impl NoteType for MaxSizeNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_note() {\n let mut data = [0; MAX_NOTE_PACKED_LEN];\n for i in 0..MAX_NOTE_PACKED_LEN {\n data[i] = i as Field;\n }\n let note = MaxSizeNote { data };\n\n let encoded = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n let (msg_type_id, msg_metadata, msg_content) = decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MaxSizeNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(data));\n }\n\n #[derive(Packable)]\n struct OversizedNote {\n data: [Field; MAX_NOTE_PACKED_LEN + 1],\n }\n\n impl NoteType for OversizedNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_note_fails() {\n let note = OversizedNote { data: [0; MAX_NOTE_PACKED_LEN + 1] };\n let _ = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_note_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0, 0, 0]);\n assert(decode_private_note_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/note.nr","function_locations":[{"start":1518,"name":"encode_private_note_message"},{"start":3312,"name":"decode_private_note_message"},{"start":5000,"name":"test::encode_decode"},{"start":5923,"name":"test::::get_id"},{"start":6019,"name":"test::encode_decode_max_size_note"},{"start":7035,"name":"test::::get_id"},{"start":7221,"name":"test::encode_oversized_note_fails"},{"start":7456,"name":"test::decode_empty_content_returns_none"},{"start":7650,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"142":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 1;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX: u32 = 2;\n\n/// Partial notes have a maximum packed length of their private fields bound by extra content in their private message\n/// (e.g. the storage slot, note completion log tag, etc.).\npub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 =\n MAX_MESSAGE_CONTENT_LEN - PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a partial note private message (i.e. one of type [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_partial_note_private_message`].\npub fn encode_partial_note_private_message(\n partial_note_private_content: PartialNotePrivateContent,\n owner: AztecAddress,\n randomness: Field,\n note_completion_log_tag: Field,\n ) -> [Field; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n PartialNotePrivateContent: NoteType + Packable,\n{\n let packed_private_content = partial_note_private_content.pack();\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail, then\n // the encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n let mut msg_content =\n [0; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX] = note_completion_log_tag;\n\n for i in 0..packed_private_content.len() {\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_private_content[i];\n }\n\n encode_message(\n PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n // Notes use the note type id for metadata\n PartialNotePrivateContent::get_id() as u64,\n msg_content,\n )\n}\n\n/// Decodes the plaintext from a partial note private message (i.e. one of type\n/// [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_partial_note_private_message`].\n///\n/// Note that while [`encode_partial_note_private_message`] returns a fixed-size array, this function takes a\n/// [`BoundedVec`] instead. This is because when decoding we're typically processing runtime-sized plaintexts, more\n/// specifically, those that originate from\n/// [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_partial_note_private_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(AztecAddress, Field, Field, Field, BoundedVec)> {\n if msg_content.len() < PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id: Field = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail,\n // then the destructuring of the partial note private message encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n // We currently have three fields that are not the partial note's packed representation, which are the owner,\n // the randomness, and the note completion log tag.\n let owner = AztecAddress::from_field(\n msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX),\n );\n let randomness = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let note_completion_log_tag = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX);\n\n let packed_private_note_content: BoundedVec = array::subbvec(\n msg_content,\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN,\n );\n\n Option::some(\n (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content),\n )\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::partial_note::{decode_partial_note_private_message, encode_partial_note_private_message},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global RANDOMNESS: Field = 10;\n global NOTE_COMPLETION_LOG_TAG: Field = 11;\n\n #[test]\n unconstrained fn encode_decode() {\n // Note that here we use MockNote as the private fields of a partial note\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_partial_note_private_message(note, OWNER, RANDOMNESS, NOTE_COMPLETION_LOG_TAG);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID);\n\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_note) =\n decode_partial_note_private_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(note_completion_log_tag, NOTE_COMPLETION_LOG_TAG);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_partial_note_private_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_succeeds_with_only_reserved_fields() {\n let content = BoundedVec::from_array([0, 0, 0]);\n let (_, _, _, _, packed_note) = decode_partial_note_private_message(0, content).unwrap();\n assert_eq(packed_note.len(), 0);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/partial_note.nr","function_locations":[{"start":1715,"name":"encode_partial_note_private_message"},{"start":3810,"name":"decode_partial_note_private_message"},{"start":6022,"name":"test::encode_decode"},{"start":6999,"name":"test::decode_empty_content_returns_none"},{"start":7197,"name":"test::decode_succeeds_with_only_reserved_fields"}]},"152":{"source":"pub(crate) mod event_validation_request;\npub mod offchain;\n\nmod message_context;\npub use message_context::MessageContext;\n\npub(crate) mod note_validation_request;\npub(crate) mod log_retrieval_request;\npub(crate) mod log_retrieval_response;\npub(crate) mod pending_tagged_log;\n\nuse crate::{\n capsules::CapsuleArray,\n ephemeral::EphemeralArray,\n event::EventSelector,\n messages::{\n discovery::partial_notes::DeliveredPendingPartialNote,\n encoding::MESSAGE_CIPHERTEXT_LEN,\n logs::{event::MAX_EVENT_SERIALIZED_LEN, note::MAX_NOTE_PACKED_LEN},\n processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse,\n note_validation_request::NoteValidationRequest,\n },\n },\n oracle::message_processing,\n};\nuse crate::protocol::{\n address::AztecAddress,\n constants::DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n hash::{compute_log_tag, sha256_to_field},\n traits::{Deserialize, Serialize},\n};\nuse event_validation_request::EventValidationRequest;\n\nglobal NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\n/// An offchain-delivered message with resolved context, ready for processing during sync.\n#[derive(Serialize, Deserialize)]\npub struct OffchainMessageWithContext {\n pub message_ciphertext: BoundedVec,\n pub message_context: MessageContext,\n}\n\n/// Enqueues a note for validation and storage by PXE.\n///\n/// Once validated, the note becomes retrievable via the `get_notes` oracle. The note will be scoped to\n/// `contract_address`, meaning other contracts will not be able to access it unless authorized.\n///\n/// In order for the note validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many note validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// The `packed_note` is what `getNotes` will later return. PXE indexes notes by `storage_slot`, so this value is\n/// typically used to filter notes that correspond to different state variables. `note_hash` and `nullifier` are the\n/// inner hashes, i.e. the raw hashes returned by `NoteHash::compute_note_hash` and `NoteHash::compute_nullifier`. PXE\n/// will verify that the siloed unique note hash was inserted into the tree at `tx_hash`, and will store the nullifier\n/// to later check for nullification.\n///\n/// `owner` is the address used in note hash and nullifier computation, often requiring knowledge of their nullifier\n/// secret key.\n///\n/// `scope` is the account to which the note message was delivered (i.e. the address the message was encrypted to).\n/// This determines which PXE account can see the note - other accounts will not be able to access it (e.g. other\n/// accounts will not be able to see one another's token balance notes, even in the same PXE) unless authorized. In\n/// most cases `recipient` equals `owner`, but they can differ in scenarios like delegated discovery.\npub unconstrained fn enqueue_note_for_validation(\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_nonce: Field,\n packed_note: BoundedVec,\n note_hash: Field,\n nullifier: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n NoteValidationRequest {\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_nonce,\n packed_note,\n note_hash,\n nullifier,\n tx_hash,\n },\n )\n}\n\n/// Enqueues an event for validation and storage by PXE.\n///\n/// This is the primary way for custom message handlers (registered via\n/// [`crate::macros::AztecConfig::custom_message_handler`]) to deliver reassembled events back to PXE after processing\n/// application-specific message formats.\n///\n/// In order for the event validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many event validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// Note that `validate_and_store_enqueued_notes_and_events` is called by Aztec.nr after processing messages, so custom\n/// message processors do not need to be concerned with this.\npub unconstrained fn enqueue_event_for_validation(\n contract_address: AztecAddress,\n event_type_id: EventSelector,\n randomness: Field,\n serialized_event: BoundedVec,\n event_commitment: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n EventValidationRequest {\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n },\n )\n}\n\n/// Validates and stores all enqueued notes and events.\n///\n/// Processes all requests enqueued via [`enqueue_note_for_validation`] and [`enqueue_event_for_validation`], inserting\n/// them into the note database and event store respectively, making them queryable via `get_notes` oracle and our TS\n/// API (PXE::getPrivateEvents).\npub unconstrained fn validate_and_store_enqueued_notes_and_events(scope: AztecAddress) {\n message_processing::validate_and_store_enqueued_notes_and_events(\n NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n MAX_NOTE_PACKED_LEN as Field,\n MAX_EVENT_SERIALIZED_LEN as Field,\n scope,\n );\n\n // Defensive clearing: purge the queues after processing to prevent double-processing if this function is called\n // more than once in the same call frame. It is currently defensive because we only call this once per sync run.\n let _ = EphemeralArray::::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n let _ = EphemeralArray::::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n}\n\n/// Efficiently queries the node for logs that result in the completion of all `DeliveredPendingPartialNote`s stored in\n/// a `CapsuleArray` by performing all node communication concurrently. Returns an `EphemeralArray` with Options\n/// for the responses that correspond to the pending partial notes at the same index.\n///\n/// For example, given an array with pending partial notes `[ p1, p2, p3 ]`, where `p1` and `p3` have corresponding\n/// completion logs but `p2` does not, the returned `EphemeralArray` will have contents `[some(p1_log), none(),\n/// some(p3_log)]`.\npub(crate) unconstrained fn get_pending_partial_notes_completion_logs(\n contract_address: AztecAddress,\n pending_partial_notes: CapsuleArray,\n) -> EphemeralArray> {\n let log_retrieval_requests = EphemeralArray::at(LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT);\n\n // We create a LogRetrievalRequest for each PendingPartialNote in the EphemeralArray. Because we need the indices in\n // the request array to match the indices in the partial note array, we can't use EphemeralArray::for_each, as that\n // function has arbitrary iteration order. Instead, we manually iterate the array from the beginning and push into\n // the requests array, which we expect to be empty.\n let mut i = 0;\n let pending_partial_notes_count = pending_partial_notes.len();\n while i < pending_partial_notes_count {\n let pending_partial_note = pending_partial_notes.get(i);\n // Partial note completion logs are emitted with a domain-separated tag. To find matching logs, we apply the\n // same domain separation to the stored raw tag.\n let log_tag = compute_log_tag(\n pending_partial_note.note_completion_log_tag,\n DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n );\n log_retrieval_requests.push(LogRetrievalRequest { contract_address, unsiloed_tag: log_tag });\n i += 1;\n }\n\n let responses = message_processing::get_logs_by_tag(log_retrieval_requests);\n\n // Defensive clearing: prevent stale requests if this function is called more than once in the same call frame.\n let _ = log_retrieval_requests.clear();\n\n responses\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/mod.nr","function_locations":[{"start":3763,"name":"enqueue_note_for_validation"},{"start":5177,"name":"enqueue_event_for_validation"},{"start":5884,"name":"validate_and_store_enqueued_notes_and_events"},{"start":7412,"name":"get_pending_partial_notes_completion_logs"}]},"154":{"source":"use crate::{\n capsules::CapsuleArray,\n context::UtilityContext,\n ephemeral::EphemeralArray,\n messages::{encoding::MESSAGE_CIPHERTEXT_LEN, processing::OffchainMessageWithContext},\n oracle::contract_sync::set_contract_sync_cache_invalid,\n protocol::{\n address::AztecAddress,\n constants::MAX_TX_LIFETIME,\n hash::sha256_to_field,\n traits::{Deserialize, Serialize},\n },\n};\n\n/// Base capsule slot for the persistent inbox of [`PendingOffchainMsg`] entries.\n///\n/// This is the slot where we accumulate messages received through [`receive`].\nglobal OFFCHAIN_INBOX_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_INBOX_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to pass tx hash resolution requests to PXE.\nglobal OFFCHAIN_CONTEXT_REQUESTS_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_CONTEXT_REQUESTS_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to collect messages ready for processing.\nglobal OFFCHAIN_READY_MESSAGES_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_READY_MESSAGES_SLOT\".as_bytes());\n\n/// Maximum number of offchain messages accepted by `offchain_receive` in a single call.\npub global MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL: u32 = 16;\n\n/// Tolerance added to the `MAX_TX_LIFETIME` cap for message expiration.\nglobal TX_EXPIRATION_TOLERANCE: u64 = 7200; // 2 hours\n\n/// Maximum time-to-live for a tx-bound offchain message.\n///\n/// After `anchor_block_timestamp + MAX_MSG_TTL`, the message is evicted from the inbox.\nglobal MAX_MSG_TTL: u64 = MAX_TX_LIFETIME + TX_EXPIRATION_TOLERANCE;\n\n/// A function that manages offchain-delivered messages for processing during sync.\n///\n/// Offchain messages are messages that are not broadcasted via onchain logs. They are instead delivered to the\n/// recipient by calling the `offchain_receive` utility function (injected by the `#[aztec]` macro). Message transport\n/// is the app's responsibility. Typical examples of transport methods are: messaging apps, email, QR codes, etc.\n///\n/// Once offchain messages are delivered to the recipient's private environment via `offchain_receive`, messages are\n/// locally stored in a persistent inbox.\n///\n/// This function determines when each message in said inbox is ready for processing, when it can be safely disposed\n/// of, etc.\n///\n/// The only current implementation of an `OffchainInboxSync` is [`sync_inbox`], which manages an inbox with expiration\n/// based eviction and automatic transaction context resolution.\npub(crate) type OffchainInboxSync = unconstrained fn[Env](\n/* contract_address */AztecAddress, /* scope */ AztecAddress) -> EphemeralArray;\n\n/// A message delivered via the `offchain_receive` utility function.\n#[derive(Serialize, Deserialize)]\npub struct OffchainMessage {\n /// The encrypted message payload.\n pub ciphertext: BoundedVec,\n /// The intended recipient of the message.\n pub recipient: AztecAddress,\n /// The hash of the transaction that produced this message. `Option::none` indicates a tx-less message.\n pub tx_hash: Option,\n /// Anchor block timestamp at message emission.\n pub anchor_block_timestamp: u64,\n}\n\n/// An offchain message awaiting processing (or re-processing) in the inbox.\n///\n/// Messages remain in the inbox until they expire, even if they have already been processed. This is necessary to\n/// handle reorgs: a processed message may need to be re-processed if the transaction that provided its context is\n/// reverted. On each sync, resolved messages are promoted to [`OffchainMessageWithContext`] for processing.\n#[derive(Serialize, Deserialize)]\nstruct PendingOffchainMsg {\n /// The encrypted message payload.\n ciphertext: BoundedVec,\n /// The intended recipient of the message.\n recipient: AztecAddress,\n /// The hash of the transaction that produced this message. A value of 0 indicates a tx-less message.\n tx_hash: Field,\n /// Anchor block timestamp at message emission. Used to compute the effective expiration: messages are evicted\n /// after `anchor_block_timestamp + MAX_MSG_TTL`.\n anchor_block_timestamp: u64,\n}\n\n/// Delivers offchain messages to the given contract's offchain inbox for subsequent processing.\n///\n/// Offchain messages are transaction effects that are not broadcasted via onchain logs. Instead, the sender shares the\n/// message to the recipient through an external channel (e.g. a URL accessible by the recipient). The recipient then\n/// calls this function to hand the messages to the contract so they can be processed through the same mechanisms as\n/// onchain messages.\n///\n/// Each message is routed to the inbox scoped to its `recipient` field, so messages for different accounts are\n/// automatically isolated.\n///\n/// Messages are processed when their originating transaction is found onchain (providing the context needed to\n/// validate resulting notes and events).\n///\n/// Messages are kept in the inbox until they expire. The effective expiration is\n/// `anchor_block_timestamp + MAX_MSG_TTL`.\n///\n/// Processing order is not guaranteed.\npub unconstrained fn receive(\n contract_address: AztecAddress,\n messages: BoundedVec,\n) {\n // May contain duplicates if multiple messages target the same recipient. This is harmless since\n // cache invalidation on the TS side is idempotent (deleting an already-deleted key is a no-op).\n let mut scopes: BoundedVec = BoundedVec::new();\n let mut i = 0;\n let messages_len = messages.len();\n while i < messages_len {\n let msg = messages.get(i);\n let tx_hash = if msg.tx_hash.is_some() {\n msg.tx_hash.unwrap()\n } else {\n 0\n };\n let inbox: CapsuleArray =\n CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, msg.recipient);\n inbox.push(\n PendingOffchainMsg {\n ciphertext: msg.ciphertext,\n recipient: msg.recipient,\n tx_hash,\n anchor_block_timestamp: msg.anchor_block_timestamp,\n },\n );\n scopes.push(msg.recipient);\n i += 1;\n }\n\n set_contract_sync_cache_invalid(contract_address, scopes);\n}\n\n/// Returns offchain-delivered messages to process during sync.\n///\n/// Messages remain in the inbox and are reprocessed on each sync until their originating transaction is no longer at\n/// risk of being dropped by a reorg.\npub unconstrained fn sync_inbox(\n contract_address: AztecAddress,\n scope: AztecAddress,\n) -> EphemeralArray {\n let inbox: CapsuleArray = CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, scope);\n let context_resolution_requests: EphemeralArray = EphemeralArray::at(OFFCHAIN_CONTEXT_REQUESTS_SLOT).clear();\n let ready_to_process: EphemeralArray =\n EphemeralArray::at(OFFCHAIN_READY_MESSAGES_SLOT).clear();\n\n // Build a request list aligned with the inbox indices.\n let mut i = 0;\n let inbox_len = inbox.len();\n while i < inbox_len {\n let msg = inbox.get(i);\n context_resolution_requests.push(msg.tx_hash);\n i += 1;\n }\n\n // Ask PXE to resolve contexts for all requested tx hashes. The oracle returns responses in a new\n // ephemeral array.\n let resolved_contexts =\n crate::oracle::message_processing::get_message_contexts_by_tx_hash(context_resolution_requests);\n\n assert_eq(resolved_contexts.len(), inbox_len);\n\n let now = UtilityContext::new().timestamp();\n\n let mut j = inbox_len;\n while j > 0 {\n // This loop decides what to do with each message in the offchain message inbox. We need to handle 3\n // different scenarios for each message.\n //\n // 1. The TX that emitted this message is still not known to PXE: in this case we can't yet process this\n // message, as any notes or events discovered will fail to be validated. So we leave the message in the inbox,\n // awaiting for future syncs to detect that the TX became available.\n //\n // 2. The message is not associated to a TX to begin with. The current version of offchain message processing\n // does not support this case, but in the future it will. Right now, a message without an associated TX will\n // sit in the inbox until it expires.\n //\n // 3. The TX that emitted this message has been found by PXE. That gives us all the information needed to\n // process the message. We add the message to the `ready_to_process` EphemeralArray so that the `sync_state`\n // loop\n // processes it.\n //\n // In all cases, if the message has expired (i.e. `now > anchor_block_timestamp + MAX_MSG_TTL`), we remove it\n // from the inbox.\n //\n // Note: the loop runs backwards because it might call `inbox.remove(j)` to purge expired messages and we also\n // need to align it with `resolved_contexts.get(j)`. Going from last to first simplifies the algorithm as\n // not yet visited element indexes remain stable.\n j -= 1;\n let maybe_ctx = resolved_contexts.get(j);\n let msg = inbox.get(j);\n\n // Compute the message's effective expiration timestamp to determine if we can purge it from the inbox.\n let effective_expiration = msg.anchor_block_timestamp + MAX_MSG_TTL;\n\n // Message expired. We remove it from the inbox.\n if now > effective_expiration {\n inbox.remove(j);\n }\n\n // Scenario 1: associated TX not yet available. We keep the message in the inbox, as it might become\n // processable as new blocks get mined.\n // Scenario 2: no TX associated to message. The message will sit in the inbox until it expires.\n if maybe_ctx.is_none() {\n continue;\n }\n\n // Scenario 3: Message is ready to process, add to result array. Note we still keep it in the inbox unless we\n // consider it has expired: this is because we need to account for reorgs. If reorg occurs after we processed\n // a message, the effects of processing the message get rewind. However, the associated TX can be included in\n // a subsequent block. Should that happen, the message must be re-processed to ensure consistency.\n let message_context = maybe_ctx.unwrap();\n ready_to_process.push(OffchainMessageWithContext { message_ciphertext: msg.ciphertext, message_context });\n }\n\n ready_to_process\n}\n\nmod test {\n use crate::{\n capsules::CapsuleArray, oracle::random::random, protocol::address::AztecAddress,\n test::helpers::test_environment::TestEnvironment,\n };\n use super::{\n MAX_MSG_TTL, MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL, OFFCHAIN_INBOX_SLOT, OffchainMessage, PendingOffchainMsg,\n receive, sync_inbox,\n };\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n /// Creates an `OffchainMessage` with dummy ciphertext and the given scope as recipient.\n fn make_msg(recipient: AztecAddress, tx_hash: Option, anchor_block_timestamp: u64) -> OffchainMessage {\n OffchainMessage { ciphertext: BoundedVec::new(), recipient, tx_hash, anchor_block_timestamp }\n }\n\n /// Advances the TXE block timestamp by `offset` seconds and returns the resulting timestamp.\n unconstrained fn advance_by(env: TestEnvironment, offset: u64) -> u64 {\n env.advance_next_block_timestamp_by(offset);\n env.mine_block();\n env.last_block_timestamp()\n }\n\n #[test]\n unconstrained fn empty_inbox_returns_empty_result() {\n let (env, scope) = setup();\n env.utility_context(|context| {\n let result = sync_inbox(context.this_address(), scope);\n let inbox: CapsuleArray =\n CapsuleArray::at(context.this_address(), OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0);\n assert_eq(inbox.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_not_expired_before_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance, but not past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn tx_less_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::none(), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn unresolved_tx_stays_in_inbox() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // not resolved, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn multiple_messages_mixed_expiration() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n let survivor_tx_hash = random();\n\n env.utility_context(|context| {\n let address = context.this_address();\n let mut msgs: BoundedVec = BoundedVec::new();\n // Message 0: tx-bound, anchor_ts in the past so it expires at\n // anchor_ts + MAX_MSG_TTL. We set anchor to 0 so it expires quickly.\n msgs.push(make_msg(scope, Option::some(random()), 0));\n // Message 1: tx-bound, anchor_ts is recent so it survives.\n msgs.push(make_msg(scope, Option::some(survivor_tx_hash), anchor_ts));\n // Message 2: tx-less, anchor_ts=0 so it also expires.\n msgs.push(make_msg(scope, Option::none(), 0));\n receive(address, msgs);\n });\n\n // Advance past MAX_MSG_TTL for anchor_ts=0, but not for anchor_ts=anchor_ts.\n let _now = advance_by(env, MAX_MSG_TTL);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // all contexts are None\n // Message 0 expired (anchor=0), message 1 survived (anchor=anchor_ts),\n // Message 2 expired (anchor=0).\n assert_eq(inbox.len(), 1);\n assert_eq(inbox.get(0).tx_hash, survivor_tx_hash);\n });\n }\n\n // -- Resolved context (ready to process) ------------------------------\n\n #[test]\n unconstrained fn resolved_msg_is_ready_to_process() {\n let (env, scope) = setup();\n // TestEnvironment::new() deploys protocol contracts, creating blocks with tx effects.\n // In TXE, tx hashes equal Fr(blockNumber), so Fr(1) is the tx effect from block 1.\n // We use this as a \"known resolvable\" tx hash.\n let known_tx_hash: Field = 1;\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(known_tx_hash), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n // The message should be ready to process since its tx context was resolved.\n assert_eq(result.len(), 1);\n\n let ctx = result.get(0).message_context;\n assert_eq(ctx.tx_hash, known_tx_hash);\n assert(ctx.first_nullifier_in_tx != 0, \"resolved context must have a first nullifier\");\n\n // Message stays in inbox (not expired) for potential reorg reprocessing.\n assert_eq(inbox.len(), 1);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/offchain.nr","function_locations":[{"start":5332,"name":"receive"},{"start":6775,"name":"sync_inbox"},{"start":11145,"name":"test::setup"},{"start":11475,"name":"test::make_msg"},{"start":11758,"name":"test::advance_by"},{"start":11949,"name":"test::empty_inbox_returns_empty_result"},{"start":12412,"name":"test::tx_bound_msg_expires_after_max_msg_ttl"},{"start":13377,"name":"test::tx_bound_msg_not_expired_before_max_msg_ttl"},{"start":14335,"name":"test::tx_less_msg_expires_after_max_msg_ttl"},{"start":15277,"name":"test::unresolved_tx_stays_in_inbox"},{"start":16171,"name":"test::multiple_messages_mixed_expiration"},{"start":17910,"name":"test::resolved_msg_is_ready_to_process"}]},"172":{"source":"#[oracle(aztec_utl_decryptAes128)]\nunconstrained fn aes128_decrypt_oracle(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {}\n\n/// Attempts to decrypt a ciphertext using AES128.\n///\n/// Returns `Option::some(plaintext)` on success, or `Option::none()` if decryption fails (e.g. due to malformed\n/// ciphertext or invalid PKCS#7 padding). Note that decryption with the wrong key will almost always return `None`\n/// because the decrypted garbage data will have invalid PKCS#7 padding.\n///\n/// Note that we accept ciphertext as a BoundedVec, not as an array. This is because this function is typically used\n/// when processing logs and at that point we don't have comptime information about the length of the ciphertext as\n/// the log is not specific to any individual note.\n// TODO(F-498): review naming consistency\npub unconstrained fn try_aes128_decrypt(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {\n aes128_decrypt_oracle(ciphertext, iv, sym_key)\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::compute_app_siloed_shared_secret,\n messages::encryption::aes128::derive_aes_symmetric_key_and_iv_from_shared_secret,\n utils::{array::subarray::subarray, point::point_from_x_coord},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::try_aes128_decrypt;\n use std::aes128::aes128_encrypt;\n\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress { inner: 42 };\n global TEST_PLAINTEXT_LENGTH: u32 = 10;\n global TEST_CIPHERTEXT_LENGTH: u32 = 16;\n global TEST_PADDING_LENGTH: u32 = TEST_CIPHERTEXT_LENGTH - TEST_PLAINTEXT_LENGTH;\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n\n let received_plaintext = try_aes128_decrypt(ciphertext_bvec, iv, sym_key).unwrap();\n assert_eq(received_plaintext.len(), TEST_PLAINTEXT_LENGTH);\n assert_eq(received_plaintext.max_len(), TEST_CIPHERTEXT_LENGTH);\n assert_eq(subarray::<_, _, TEST_PLAINTEXT_LENGTH>(received_plaintext.storage(), 0), plaintext);\n assert_eq(\n subarray::<_, _, TEST_PADDING_LENGTH>(received_plaintext.storage(), TEST_PLAINTEXT_LENGTH),\n [0 as u8; TEST_PADDING_LENGTH],\n );\n })\n }\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt_with_bad_sym_key_is_caught() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n // Decrypting with the wrong key results in garbage data with invalid PKCS#7 padding,\n // so the oracle returns None.\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let mut bad_sym_key = sym_key;\n bad_sym_key[0] = 0;\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n // Decryption with wrong key returns None because the garbage output has invalid PKCS#7 padding.\n let result = try_aes128_decrypt(ciphertext_bvec, iv, bad_sym_key);\n assert(result.is_none(), \"decryption with bad key should return None\");\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/aes128_decrypt.nr","function_locations":[{"start":194,"name":"aes128_decrypt_oracle"},{"start":1046,"name":"try_aes128_decrypt"},{"start":1860,"name":"test::aes_encrypt_then_decrypt"},{"start":3150,"name":"test::aes_encrypt_then_decrypt_with_bad_sym_key_is_caught"}]},"174":{"source":"//! AVM oracles.\n//!\n//! There are only available during public execution. Calling any of them from a private or utility function will\n//! result in runtime errors.\n\nuse crate::protocol::address::{AztecAddress, EthAddress};\n\npub unconstrained fn address() -> AztecAddress {\n address_opcode()\n}\npub unconstrained fn sender() -> AztecAddress {\n sender_opcode()\n}\npub unconstrained fn transaction_fee() -> Field {\n transaction_fee_opcode()\n}\npub unconstrained fn chain_id() -> Field {\n chain_id_opcode()\n}\npub unconstrained fn version() -> Field {\n version_opcode()\n}\npub unconstrained fn block_number() -> u32 {\n block_number_opcode()\n}\npub unconstrained fn timestamp() -> u64 {\n timestamp_opcode()\n}\npub unconstrained fn min_fee_per_l2_gas() -> u128 {\n min_fee_per_l2_gas_opcode()\n}\npub unconstrained fn min_fee_per_da_gas() -> u128 {\n min_fee_per_da_gas_opcode()\n}\npub unconstrained fn l2_gas_left() -> u32 {\n l2_gas_left_opcode()\n}\npub unconstrained fn da_gas_left() -> u32 {\n da_gas_left_opcode()\n}\npub unconstrained fn is_static_call() -> bool {\n is_static_call_opcode()\n}\npub unconstrained fn note_hash_exists(note_hash: Field, leaf_index: u64) -> bool {\n note_hash_exists_opcode(note_hash, leaf_index)\n}\npub unconstrained fn emit_note_hash(note_hash: Field) {\n emit_note_hash_opcode(note_hash)\n}\npub unconstrained fn nullifier_exists(siloed_nullifier: Field) -> bool {\n nullifier_exists_opcode(siloed_nullifier)\n}\npub unconstrained fn emit_nullifier(nullifier: Field) {\n emit_nullifier_opcode(nullifier)\n}\npub unconstrained fn emit_public_log(message: [Field]) {\n emit_public_log_opcode(message)\n}\npub unconstrained fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: u64) -> bool {\n l1_to_l2_msg_exists_opcode(msg_hash, msg_leaf_index)\n}\npub unconstrained fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {\n send_l2_to_l1_msg_opcode(recipient, content)\n}\n\npub unconstrained fn call(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn call_static(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_static_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn calldata_copy(cdoffset: u32, copy_size: u32) -> [Field; N] {\n calldata_copy_opcode(cdoffset, copy_size)\n}\n\n/// `success_copy` is placed immediately after the CALL opcode to get the success value\npub unconstrained fn success_copy() -> bool {\n success_copy_opcode()\n}\n\npub unconstrained fn returndata_size() -> u32 {\n returndata_size_opcode()\n}\n\npub unconstrained fn returndata_copy(rdoffset: u32, copy_size: u32) -> [Field] {\n returndata_copy_opcode(rdoffset, copy_size)\n}\n\n/// The additional prefix is to avoid clashing with the `return` Noir keyword.\npub unconstrained fn avm_return(returndata: [Field]) {\n return_opcode(returndata)\n}\n\n/// This opcode reverts using the exact data given. In general it should only be used to do rethrows, where the revert\n/// data is the same as the original revert data. For normal reverts, use Noir's `assert` which, on top of reverting,\n/// will also add an error selector to the revert data.\npub unconstrained fn revert(revertdata: [Field]) {\n revert_opcode(revertdata)\n}\n\npub unconstrained fn storage_read(storage_slot: Field, contract_address: Field) -> Field {\n storage_read_opcode(storage_slot, contract_address)\n}\n\npub unconstrained fn storage_write(storage_slot: Field, value: Field) {\n storage_write_opcode(storage_slot, value);\n}\n\n#[oracle(aztec_avm_address)]\nunconstrained fn address_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_sender)]\nunconstrained fn sender_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_transactionFee)]\nunconstrained fn transaction_fee_opcode() -> Field {}\n\n#[oracle(aztec_avm_chainId)]\nunconstrained fn chain_id_opcode() -> Field {}\n\n#[oracle(aztec_avm_version)]\nunconstrained fn version_opcode() -> Field {}\n\n#[oracle(aztec_avm_blockNumber)]\nunconstrained fn block_number_opcode() -> u32 {}\n\n#[oracle(aztec_avm_timestamp)]\nunconstrained fn timestamp_opcode() -> u64 {}\n\n#[oracle(aztec_avm_minFeePerL2Gas)]\nunconstrained fn min_fee_per_l2_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_minFeePerDaGas)]\nunconstrained fn min_fee_per_da_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_l2GasLeft)]\nunconstrained fn l2_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_daGasLeft)]\nunconstrained fn da_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_isStaticCall)]\nunconstrained fn is_static_call_opcode() -> bool {}\n\n#[oracle(aztec_avm_noteHashExists)]\nunconstrained fn note_hash_exists_opcode(note_hash: Field, leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_emitNoteHash)]\nunconstrained fn emit_note_hash_opcode(note_hash: Field) {}\n\n#[oracle(aztec_avm_nullifierExists)]\nunconstrained fn nullifier_exists_opcode(siloed_nullifier: Field) -> bool {}\n\n#[oracle(aztec_avm_emitNullifier)]\nunconstrained fn emit_nullifier_opcode(nullifier: Field) {}\n\n#[oracle(aztec_avm_emitPublicLog)]\nunconstrained fn emit_public_log_opcode(message: [Field]) {}\n\n#[oracle(aztec_avm_l1ToL2MsgExists)]\nunconstrained fn l1_to_l2_msg_exists_opcode(msg_hash: Field, msg_leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_sendL2ToL1Msg)]\nunconstrained fn send_l2_to_l1_msg_opcode(recipient: EthAddress, content: Field) {}\n\n#[oracle(aztec_avm_calldataCopy)]\nunconstrained fn calldata_copy_opcode(cdoffset: u32, copy_size: u32) -> [Field; N] {}\n\n#[oracle(aztec_avm_returndataSize)]\nunconstrained fn returndata_size_opcode() -> u32 {}\n\n#[oracle(aztec_avm_returndataCopy)]\nunconstrained fn returndata_copy_opcode(rdoffset: u32, copy_size: u32) -> [Field] {}\n\n#[oracle(aztec_avm_return)]\nunconstrained fn return_opcode(returndata: [Field]) {}\n\n#[oracle(aztec_avm_revert)]\nunconstrained fn revert_opcode(revertdata: [Field]) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_call)]\nunconstrained fn call_opcode(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_staticCall)]\nunconstrained fn call_static_opcode(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n#[oracle(aztec_avm_successCopy)]\nunconstrained fn success_copy_opcode() -> bool {}\n\n#[oracle(aztec_avm_storageRead)]\nunconstrained fn storage_read_opcode(storage_slot: Field, contract_address: Field) -> Field {}\n\n#[oracle(aztec_avm_storageWrite)]\nunconstrained fn storage_write_opcode(storage_slot: Field, value: Field) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/avm.nr","function_locations":[{"start":272,"name":"address"},{"start":343,"name":"sender"},{"start":415,"name":"transaction_fee"},{"start":489,"name":"chain_id"},{"start":555,"name":"version"},{"start":623,"name":"block_number"},{"start":693,"name":"timestamp"},{"start":770,"name":"min_fee_per_l2_gas"},{"start":856,"name":"min_fee_per_da_gas"},{"start":934,"name":"l2_gas_left"},{"start":1005,"name":"da_gas_left"},{"start":1080,"name":"is_static_call"},{"start":1193,"name":"note_hash_exists"},{"start":1302,"name":"emit_note_hash"},{"start":1414,"name":"nullifier_exists"},{"start":1518,"name":"emit_nullifier"},{"start":1614,"name":"emit_public_log"},{"start":1741,"name":"l1_to_l2_msg_exists"},{"start":1880,"name":"send_l2_to_l1_msg"},{"start":2080,"name":"call"},{"start":2310,"name":"call_static"},{"start":2486,"name":"calldata_copy"},{"start":2669,"name":"success_copy"},{"start":2746,"name":"returndata_size"},{"start":2859,"name":"returndata_copy"},{"start":3044,"name":"avm_return"},{"start":3421,"name":"revert"},{"start":3545,"name":"storage_read"},{"start":3676,"name":"storage_write"},{"start":3807,"name":"address_opcode"},{"start":3888,"name":"sender_opcode"},{"start":3979,"name":"transaction_fee_opcode"},{"start":4056,"name":"chain_id_opcode"},{"start":4132,"name":"version_opcode"},{"start":4215,"name":"block_number_opcode"},{"start":4293,"name":"timestamp_opcode"},{"start":4386,"name":"min_fee_per_l2_gas_opcode"},{"start":4479,"name":"min_fee_per_da_gas_opcode"},{"start":4559,"name":"l2_gas_left_opcode"},{"start":4639,"name":"da_gas_left_opcode"},{"start":4726,"name":"is_static_call_opcode"},{"start":4850,"name":"note_hash_exists_opcode"},{"start":4945,"name":"emit_note_hash_opcode"},{"start":5060,"name":"nullifier_exists_opcode"},{"start":5156,"name":"emit_nullifier_opcode"},{"start":5253,"name":"emit_public_log_opcode"},{"start":5384,"name":"l1_to_l2_msg_exists_opcode"},{"start":5504,"name":"send_l2_to_l1_msg_opcode"},{"start":5637,"name":"calldata_copy_opcode"},{"start":5726,"name":"returndata_size_opcode"},{"start":5848,"name":"returndata_copy_opcode"},{"start":5932,"name":"return_opcode"},{"start":6016,"name":"revert_opcode"},{"start":6463,"name":"call_opcode"},{"start":6923,"name":"call_static_opcode"},{"start":7007,"name":"success_copy_opcode"},{"start":7136,"name":"storage_read_opcode"},{"start":7247,"name":"storage_write_opcode"}]},"178":{"source":"use crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Stores arbitrary information in a per-contract non-volatile database, which can later be retrieved with `load`. If\n/// data was already stored at this slot, it is overwritten.\n// TODO(F-498): review naming consistency\npub unconstrained fn store(contract_address: AztecAddress, slot: Field, value: T, scope: AztecAddress)\nwhere\n T: Serialize,\n{\n let serialized = value.serialize();\n set_capsule_oracle(contract_address, slot, serialized, scope);\n}\n\n/// Returns data previously stored via `storeCapsule` in the per-contract non-volatile database. Returns\n/// Option::none() if nothing was stored at the given slot.\n// TODO(F-498): review naming consistency\npub unconstrained fn load(contract_address: AztecAddress, slot: Field, scope: AztecAddress) -> Option\nwhere\n T: Deserialize,\n{\n let serialized_option = get_capsule_oracle(contract_address, slot, ::N, scope);\n serialized_option.map(|arr| Deserialize::deserialize(arr))\n}\n\n/// Deletes data in the per-contract non-volatile database. Does nothing if no data was present.\npub unconstrained fn delete(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {\n delete_oracle(contract_address, slot, scope);\n}\n\n/// Copies a number of contiguous entries in the per-contract non-volatile database. This allows for efficient data\n/// structures by avoiding repeated calls to `loadCapsule` and `storeCapsule`. Supports overlapping source and\n/// destination regions (which will result in the overlapped source values being overwritten). All copied slots must\n/// exist in the database (i.e. have been stored and not deleted)\npub unconstrained fn copy(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {\n copy_oracle(contract_address, src_slot, dst_slot, num_entries, scope);\n}\n\n#[oracle(aztec_utl_setCapsule)]\nunconstrained fn set_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n values: [Field; N],\n scope: AztecAddress,\n) {}\n\n/// We need to pass in `array_len` (the value of N) as a parameter to tell the oracle how many fields the response must\n/// have.\n///\n/// Note that the oracle returns an Option<[Field; N]> because we cannot return an Option directly. That would\n/// require for the oracle resolver to know the shape of T (e.g. if T were a struct of 3 u32 values then the expected\n/// response shape would be 3 single items, whereas it were a struct containing `u32, [Field;10], u32` then the\n/// expected shape would be single, array, single.). Instead, we return the serialization and deserialize in Noir.\n#[oracle(aztec_utl_getCapsule)]\nunconstrained fn get_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n array_len: u32,\n scope: AztecAddress,\n) -> Option<[Field; N]> {}\n\n#[oracle(aztec_utl_deleteCapsule)]\nunconstrained fn delete_oracle(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {}\n\n#[oracle(aztec_utl_copyCapsule)]\nunconstrained fn copy_oracle(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {}\n\nmod test {\n // These tests are sort of redundant since we already test the oracle implementation directly in TypeScript, but\n // they are cheap regardless and help ensure both that the TXE implementation works accordingly and that the Noir\n // oracles are hooked up correctly.\n\n use crate::{\n oracle::capsules::{copy, delete, load, store},\n test::{helpers::test_environment::TestEnvironment, mocks::MockStruct},\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, ToField}};\n\n global SLOT: Field = 1;\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n #[test]\n unconstrained fn stores_and_loads() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), value);\n });\n }\n\n #[test]\n unconstrained fn store_overwrites() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n let new_value = MockStruct::new(7, 8);\n store(contract_address, SLOT, new_value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), new_value);\n });\n }\n\n #[test]\n unconstrained fn loads_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_stored_value() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n delete(contract_address, SLOT, scope);\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n delete(contract_address, SLOT, scope);\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn copies_non_overlapping_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 5;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 10;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_src_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 1;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 2;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[1] and src[2] should have been overwritten since they are also dst[0] and dst[1]\n assert_eq(load(contract_address, src, scope).unwrap(), values[0]); // src[0] (unchanged)\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[0]); // dst[0]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[1]); // dst[1]\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_dst_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 2;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 1;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[0] and src[1] should have been overwritten since they are also dst[1] and dst[2]\n assert_eq(load(contract_address, src, scope).unwrap(), values[1]); // dst[1]\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[2]); // dst[2]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[2]); // src[2] (unchanged)\n });\n }\n\n #[test(should_fail_with = \"copy empty slot\")]\n unconstrained fn cannot_copy_empty_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n copy(contract_address, SLOT, SLOT, 1, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_store_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let value = MockStruct::new(5, 6);\n store(other_contract_address, SLOT, value, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_load_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let _: Option = load(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_delete_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n delete(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_copy_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n copy(other_contract_address, SLOT, SLOT, 0, scope);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/capsules.nr","function_locations":[{"start":433,"name":"store"},{"start":886,"name":"load"},{"start":1247,"name":"delete"},{"start":1866,"name":"copy"},{"start":2131,"name":"set_capsule_oracle"},{"start":2931,"name":"get_capsule_oracle"},{"start":3067,"name":"delete_oracle"},{"start":3261,"name":"copy_oracle"},{"start":3884,"name":"test::setup"},{"start":4060,"name":"test::stores_and_loads"},{"start":4450,"name":"test::store_overwrites"},{"start":4957,"name":"test::loads_empty_slot"},{"start":5311,"name":"test::deletes_stored_value"},{"start":5819,"name":"test::deletes_empty_slot"},{"start":6233,"name":"test::copies_non_overlapping_values"},{"start":7106,"name":"test::copies_overlapping_values_with_src_ahead"},{"start":8366,"name":"test::copies_overlapping_values_with_dst_ahead"},{"start":9648,"name":"test::cannot_copy_empty_values"},{"start":9970,"name":"test::cannot_store_other_contract"},{"start":10443,"name":"test::cannot_load_other_contract"},{"start":10891,"name":"test::cannot_delete_other_contract"},{"start":11311,"name":"test::cannot_copy_other_contract"}]},"179":{"source":"use crate::protocol::address::AztecAddress;\n\n#[oracle(aztec_utl_setContractSyncCacheInvalid)]\nunconstrained fn set_contract_sync_cache_invalid_oracle(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {}\n\n/// Forces the PXE to re-sync the given contract for a set of scopes on the next query.\n///\n/// Call this after writing data (e.g. offchain messages) that the contract's `sync_state` function needs to discover.\n/// Without invalidation, the sync cache would skip re-running `sync_state` until the next block.\npub unconstrained fn set_contract_sync_cache_invalid(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {\n set_contract_sync_cache_invalid_oracle(contract_address, scopes);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/contract_sync.nr","function_locations":[{"start":242,"name":"set_contract_sync_cache_invalid_oracle"},{"start":700,"name":"set_contract_sync_cache_invalid"}]},"181":{"source":"use crate::context::UtilityContext;\n\n#[oracle(aztec_utl_getUtilityContext)]\nunconstrained fn get_utility_context_oracle() -> UtilityContext {}\n\n/// Returns a utility context built from the global variables of anchor block and the contract address of the function\n/// being executed.\npub unconstrained fn get_utility_context() -> UtilityContext {\n get_utility_context_oracle()\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/execution.nr","function_locations":[{"start":140,"name":"get_utility_context_oracle"},{"start":344,"name":"get_utility_context"}]},"191":{"source":"use crate::ephemeral::EphemeralArray;\nuse crate::messages::processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse, MessageContext,\n pending_tagged_log::PendingTaggedLog,\n};\nuse crate::protocol::address::AztecAddress;\n\n/// Finds new private logs that may have been sent to all registered accounts in PXE in the current contract and\n/// returns them in an ephemeral array with an oracle-allocated base slot.\npub(crate) unconstrained fn get_pending_tagged_logs(scope: AztecAddress) -> EphemeralArray {\n let result_slot = get_pending_tagged_logs_oracle(scope);\n EphemeralArray::at(result_slot)\n}\n\n#[oracle(aztec_utl_getPendingTaggedLogs_v2)]\nunconstrained fn get_pending_tagged_logs_oracle(scope: AztecAddress) -> Field {}\n\n/// Validates note/event requests stored in ephemeral arrays.\npub(crate) unconstrained fn validate_and_store_enqueued_notes_and_events(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {\n validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot,\n event_validation_requests_array_slot,\n max_note_packed_len,\n max_event_serialized_len,\n scope,\n );\n}\n\n#[oracle(aztec_utl_validateAndStoreEnqueuedNotesAndEvents_v2)]\nunconstrained fn validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {}\n\n/// Fetches logs by tag from an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_logs_by_tag(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_logs_by_tag_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getLogsByTag_v2)]\nunconstrained fn get_logs_by_tag_v2_oracle(request_array_slot: Field) -> Field {}\n\n/// Resolves message contexts for tx hashes in an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_message_contexts_by_tx_hash(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_message_contexts_by_tx_hash_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getMessageContextsByTxHash_v2)]\nunconstrained fn get_message_contexts_by_tx_hash_v2_oracle(request_array_slot: Field) -> Field {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/message_processing.nr","function_locations":[{"start":570,"name":"get_pending_tagged_logs"},{"start":795,"name":"get_pending_tagged_logs_oracle"},{"start":1128,"name":"validate_and_store_enqueued_notes_and_events"},{"start":1692,"name":"validate_and_store_enqueued_notes_and_events_oracle"},{"start":1938,"name":"get_logs_by_tag"},{"start":2163,"name":"get_logs_by_tag_v2_oracle"},{"start":2423,"name":"get_message_contexts_by_tx_hash"},{"start":2694,"name":"get_message_contexts_by_tx_hash_v2_oracle"}]},"198":{"source":"use crate::protocol::address::aztec_address::AztecAddress;\nuse crate::protocol::point::Point;\n\n#[oracle(aztec_utl_getSharedSecret)]\nunconstrained fn get_shared_secret_oracle(\n address: AztecAddress,\n ephPk: Point,\n contract_address: AztecAddress,\n) -> Field {}\n\n/// Returns an app-siloed shared secret between `address` and someone who knows the secret key behind an ephemeral\n/// public key `ephPk`.\n///\n/// The returned value is a Field `s_app`, computed as:\n///\n/// ```text\n/// S = address_secret * ephPk (raw ECDH point)\n/// s_app = h(DOM_SEP, S.x, S.y, contract) (app-siloed scalar)\n/// ```\n///\n/// where `contract` is the address of the calling contract. The oracle host validates this matches its execution\n/// context.\n///\n/// Without app-siloing, a malicious contract could call this oracle with public information (address, ephPk) and\n/// obtain the same raw secret as the legitimate contract, enabling cross-contract decryption. By including the\n/// contract address in the hash, each contract receives a different `s_app`, preventing this attack.\n///\n/// Callers derive indexed subkeys from `s_app` via\n/// [`derive_shared_secret_subkey`](crate::keys::ecdh_shared_secret::derive_shared_secret_subkey).\npub unconstrained fn get_shared_secret(address: AztecAddress, ephPk: Point, contract_address: AztecAddress) -> Field {\n get_shared_secret_oracle(address, ephPk, contract_address)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr","function_locations":[{"start":267,"name":"get_shared_secret_oracle"},{"start":1354,"name":"get_shared_secret"}]},"247":{"source":"/// Appends the elements of the second `BoundedVec` to the end of the first one. The resulting `BoundedVec` can have\n/// any arbitrary maximum length, but it must be large enough to fit all of the elements of both the first and second\n/// vectors.\npub fn append(\n a: BoundedVec,\n b: BoundedVec,\n) -> BoundedVec {\n let mut dst = BoundedVec::new();\n\n dst.extend_from_bounded_vec(a);\n dst.extend_from_bounded_vec(b);\n\n dst\n}\n\nmod test {\n use super::append;\n\n #[test]\n unconstrained fn append_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::new();\n let b: BoundedVec<_, 14> = BoundedVec::new();\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 0);\n assert_eq(result.storage(), std::mem::zeroed());\n }\n\n #[test]\n unconstrained fn append_non_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 6);\n assert_eq(result.storage(), [1, 2, 3, 4, 5, 6, std::mem::zeroed(), std::mem::zeroed()]);\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn append_non_empty_vecs_insufficient_max_len() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let _: BoundedVec = append(a, b);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/append.nr","function_locations":[{"start":396,"name":"append"},{"start":608,"name":"test::append_empty_vecs"},{"start":933,"name":"test::append_non_empty_vecs"},{"start":1387,"name":"test::append_non_empty_vecs_insufficient_max_len"}]},"250":{"source":"/// Returns `DstLen` elements from a source array, starting at `offset`. `DstLen` must not be larger than the number of\n/// elements past `offset`.\n///\n/// Examples:\n/// ```\n/// let foo: [Field; 2] = subarray([1, 2, 3, 4, 5], 2);\n/// assert_eq(foo, [3, 4]);\n///\n/// let bar: [Field; 5] = subarray([1, 2, 3, 4, 5], 2); // fails - we can't return 5 elements since only 3 remain\n/// ```\npub fn subarray(src: [T; SrcLen], offset: u32) -> [T; DstLen] {\n assert(offset + DstLen <= SrcLen, \"DstLen too large for offset\");\n\n let mut dst: [T; DstLen] = std::mem::zeroed();\n for i in 0..DstLen {\n dst[i] = src[i + offset];\n }\n\n dst\n}\n\nmod test {\n use super::subarray;\n\n #[test]\n unconstrained fn subarray_into_empty() {\n // In all of these cases we're setting DstLen to be 0, so we always get back an empty array.\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 2), []);\n }\n\n #[test]\n unconstrained fn subarray_complete() {\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), [1, 2, 3, 4, 5]);\n }\n\n #[test]\n unconstrained fn subarray_different_end_sizes() {\n // We implicitly select how many values to read in the size of the return array\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4, 5]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2]);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subarray_offset_too_large() {\n // With an offset of 1 we can only request up to 4 elements\n let _: [_; 5] = subarray([1, 2, 3, 4, 5], 1);\n }\n\n #[test(should_fail)]\n unconstrained fn subarray_bad_return_value() {\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [3, 3, 4, 5]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr","function_locations":[{"start":483,"name":"subarray"},{"start":776,"name":"test::subarray_into_empty"},{"start":1100,"name":"test::subarray_complete"},{"start":1294,"name":"test::subarray_different_end_sizes"},{"start":1736,"name":"test::subarray_offset_too_large"},{"start":1941,"name":"test::subarray_bad_return_value"}]},"251":{"source":"use crate::utils::array;\n\n/// Returns `DstMaxLen` elements from a source BoundedVec, starting at `offset`. `offset` must not be larger than the\n/// original length, and `DstLen` must not be larger than the total number of elements past `offset` (including the\n/// zeroed elements past `len()`).\n///\n/// Only elements at the beginning of the vector can be removed: it is not possible to also remove elements at the end\n/// of the vector by passing a value for `DstLen` that is smaller than `len() - offset`.\n///\n/// Examples:\n/// ```\n/// let foo = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n/// assert_eq(subbvec(foo, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n///\n/// let bar: BoundedVec<_, 1> = subbvec(foo, 2); // fails - we can't return just 1 element since 3 remain\n/// let baz: BoundedVec<_, 10> = subbvec(foo, 3); // fails - we can't return 10 elements since only 7 remain\n/// ```\npub fn subbvec(\n bvec: BoundedVec,\n offset: u32,\n) -> BoundedVec {\n // from_parts_unchecked does not verify that the elements past len are zeroed, but that is not an issue in our case\n // because we're constructing the new storage array as a subarray of the original one (which should have zeroed\n // storage past len), guaranteeing correctness. This is because `subarray` does not allow extending arrays past\n // their original length.\n BoundedVec::from_parts_unchecked(array::subarray(bvec.storage(), offset), bvec.len() - offset)\n}\n\nmod test {\n use super::subbvec;\n\n #[test]\n unconstrained fn subbvec_empty() {\n let bvec = BoundedVec::::from_array([]);\n assert_eq(subbvec(bvec, 0), bvec);\n }\n\n #[test]\n unconstrained fn subbvec_complete() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), bvec);\n\n let smaller_capacity = BoundedVec::<_, 5>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), smaller_capacity);\n }\n\n #[test]\n unconstrained fn subbvec_partial() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 3>::from_array([3, 4, 5]));\n }\n\n #[test]\n unconstrained fn subbvec_into_empty() {\n let bvec: BoundedVec<_, 10> = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 5), BoundedVec::<_, 5>::from_array([]));\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_offset_past_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n let _: BoundedVec<_, 1> = subbvec(bvec, 6);\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_insufficient_dst_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // We're not providing enough space to hold all of the items inside the original BoundedVec. subbvec can cause\n // for the capacity to reduce, but not the length (other than by len - offset).\n let _: BoundedVec<_, 1> = subbvec(bvec, 2);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_causes_enlarge() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // subbvec does not support capacity increases\n let _: BoundedVec<_, 11> = subbvec(bvec, 0);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_too_large_for_offset() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // This effectively requests a capacity increase, since there'd be just one element plus the 5 empty slots,\n // which is less than 7.\n let _: BoundedVec<_, 7> = subbvec(bvec, 4);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr","function_locations":[{"start":1041,"name":"subbvec"},{"start":1612,"name":"test::subbvec_empty"},{"start":1775,"name":"test::subbvec_complete"},{"start":2083,"name":"test::subbvec_partial"},{"start":2376,"name":"test::subbvec_into_empty"},{"start":2609,"name":"test::subbvec_offset_past_len"},{"start":2816,"name":"test::subbvec_insufficient_dst_len"},{"start":3270,"name":"test::subbvec_dst_len_causes_enlarge"},{"start":3579,"name":"test::subbvec_dst_len_too_large_for_offset"}]},"254":{"source":"use std::static_assert;\n\n/// Encodes an array of bytes as fields.\n///\n/// Use\n/// [`decode_bytes_from_fields`](crate::utils::conversion::bytes_as_fields::decode_bytes_from_fields) to recover\n/// the original bytes.\n///\n/// The `bytes` array length must be a multiple of 31. If padding is added, it will need to be manually removed\n/// after decoding.\n///\n/// ## Encoding\n///\n/// Each 31-byte chunk is interpreted as a big-endian integer and stored in a `Field`. For input `[1, 10, 3, ..., 0]`\n/// (31 bytes), the resulting `Field` is `1 * 256^30 + 10 * 256^29 + 3 * 256^28 + ... + 0`.\npub fn encode_bytes_as_fields(bytes: [u8; N]) -> [Field; N / 31] {\n static_assert(N % 31 == 0, \"N must be a multiple of 31\");\n\n let mut fields = [0; N / 31];\n for i in 0..N / 31 {\n let mut field = 0;\n for j in 0..31 {\n field = field * 256 + bytes[i * 31 + j] as Field;\n }\n fields[i] = field;\n }\n\n fields\n}\n\n/// Decodes fields back into bytes.\n///\n/// Inverse of\n/// [`encode_bytes_as_fields`](crate::utils::conversion::bytes_as_fields::encode_bytes_as_fields).\n/// Each input `Field` must fit in 248 bits; `Field::to_be_bytes::<31>()` fails the proof otherwise.\npub fn decode_bytes_from_fields(fields: BoundedVec) -> BoundedVec {\n let mut bytes = BoundedVec::new();\n for i in 0..fields.len() {\n let chunk: [u8; 31] = fields.get(i).to_be_bytes();\n for j in 0..31 {\n bytes.push(chunk[j]);\n }\n }\n bytes\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_bytes_from_fields, encode_bytes_as_fields};\n\n #[test]\n unconstrained fn round_trips_bytes(input: [u8; 93]) {\n let fields = encode_bytes_as_fields(input);\n\n // In production the fields fly through the system and arrive as a BoundedVec on the other end.\n let fields_bvec = BoundedVec::<_, 6>::from_array(fields);\n let bytes_back = decode_bytes_from_fields(fields_bvec);\n\n assert_eq(bytes_back.len(), input.len());\n assert_eq(subarray(bytes_back.storage(), 0), input);\n }\n\n #[test(should_fail_with = \"N must be a multiple of 31\")]\n unconstrained fn encode_rejects_length_not_multiple_of_31() {\n let _fields = encode_bytes_as_fields([0; 32]);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 31 limbs\")]\n unconstrained fn decode_rejects_oversized_field() {\n // `Field::to_be_bytes::<31>()` fails the proof when a field has any bit above position 247 set.\n let oversized: Field = (1 as Field) * 2.pow_32(249);\n let input = BoundedVec::<_, 1>::from_array([oversized]);\n let _bytes = decode_bytes_from_fields(input);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/bytes_as_fields.nr","function_locations":[{"start":662,"name":"encode_bytes_as_fields"},{"start":1313,"name":"decode_bytes_from_fields"},{"start":1719,"name":"tests::round_trips_bytes"},{"start":2252,"name":"tests::encode_rejects_length_not_multiple_of_31"},{"start":2454,"name":"tests::decode_rejects_oversized_field"}]},"255":{"source":"/// Encodes an array of fields as bytes.\n///\n/// Losslessly preserves any field value; use\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes) to\n/// recover the original fields.\n///\n/// ## Encoding\n///\n/// Each field is written as 32 big-endian bytes and the chunks are concatenated. The field array `[5, 42]` becomes:\n///\n/// ```text\n/// [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, // First field (32 bytes)\n/// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42] // Second field (32 bytes)\n/// ```\n///\n/// ## Privacy\n///\n/// The BN254 modulus is `< 2^254`, so every 32-byte chunk has its top bit at zero and the next bit biased. The output\n/// is therefore distinguishable from uniform random bytes; take this into account when feeding it into anything that\n/// assumes uniform randomness (e.g. ciphertexts meant to look random).\npub fn encode_fields_as_bytes(fields: [Field; N]) -> [u8; 32 * N] {\n let mut bytes = [0; 32 * N];\n for i in 0..N {\n let chunk: [u8; 32] = fields[i].to_be_bytes();\n for j in 0..32 {\n bytes[i * 32 + j] = chunk[j];\n }\n }\n bytes\n}\n\n/// Decodes bytes back into fields.\n///\n/// Panics if the input length is not a multiple of 32 or if any chunk exceeds the BN254 field modulus. See\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes)\n/// for a non-panicking variant.\npub fn decode_fields_from_bytes(bytes: BoundedVec) -> BoundedVec {\n assert(bytes.len() % 32 == 0, \"Input length must be a multiple of 32\");\n try_decode_fields_from_bytes(bytes).expect(f\"Value does not fit in field\")\n}\n\n/// Decodes bytes back into fields, returning None on failure.\n///\n/// Inverse of\n/// [`encode_fields_as_bytes`](crate::utils::conversion::fields_as_bytes::encode_fields_as_bytes).\n/// Returns `Option::none()` if the input length is not a multiple of 32, or if any 32-byte chunk is `>=` the BN254\n/// field modulus.\npub fn try_decode_fields_from_bytes(bytes: BoundedVec) -> Option> {\n if bytes.len() % 32 == 0 {\n let num_chunks = bytes.len() / 32;\n let mut fields: BoundedVec = BoundedVec::new();\n for i in 0..num_chunks {\n let maybe_field = try_decode_field_from_bytes(bytes, i * 32);\n if maybe_field.is_some() {\n fields.push(maybe_field.unwrap());\n }\n }\n if fields.len() == num_chunks {\n Option::some(fields)\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n}\n\nfn try_decode_field_from_bytes(bytes: BoundedVec, offset: u32) -> Option {\n // Field arithmetic silently wraps values >= the modulus, so we compare each chunk against the modulus\n // byte-by-byte (big-endian) while building `field`. cmp: 0 = equal so far, 1 = less than modulus, 2 = exceeds.\n let p = std::field::modulus_be_bytes();\n let mut field = 0;\n let mut cmp: u8 = 0;\n for j in 0..32 {\n let byte = bytes.get(offset + j);\n field = field * 256 + byte as Field;\n if cmp == 0 {\n if byte < p[j] {\n cmp = 1;\n } else if byte > p[j] {\n cmp = 2;\n }\n }\n }\n\n if cmp == 1 {\n Option::some(field)\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_fields_from_bytes, encode_fields_as_bytes, try_decode_fields_from_bytes};\n\n #[test]\n unconstrained fn round_trips_fields(input: [Field; 3]) {\n let bytes = encode_fields_as_bytes(input);\n\n // In production the bytes fly through the system and arrive as a BoundedVec on the other end. 113 is an\n // arbitrary max length larger than the input length of 96.\n let bytes_bvec = BoundedVec::<_, 113>::from_array(bytes);\n let fields_back = try_decode_fields_from_bytes(bytes_bvec).unwrap();\n\n assert_eq(fields_back.len(), input.len());\n assert_eq(subarray(fields_back.storage(), 0), input);\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_length_not_multiple_of_32() {\n let input = BoundedVec::<_, 64>::from_parts([0 as u8; 64], 33);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test]\n unconstrained fn try_decode_accepts_max_field() {\n // -1 in field arithmetic wraps to `modulus - 1`, the largest valid field value.\n let max_field_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let input = BoundedVec::<_, 32>::from_array(max_field_as_bytes);\n\n let fields = try_decode_fields_from_bytes(input).unwrap();\n\n assert_eq(fields.get(0), -1);\n }\n\n // Verifies the overflow check: take the max allowed value, bump a random byte, feed it in.\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n // Skip if the selected byte is already 255. Acceptable under fuzz testing.\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_equal_to_modulus() {\n // The field modulus itself is not a valid field value (it wraps to 0).\n let p: [u8; 32] = std::field::modulus_be_bytes().as_array();\n let input = BoundedVec::::from_array(p);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test(should_fail_with = \"Input length must be a multiple of 32\")]\n unconstrained fn decode_asserts_length_multiple_of_32() {\n let input = BoundedVec::<_, 143>::from_array([\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n 30, 31, 32, 33,\n ]);\n let _fields = decode_fields_from_bytes(input);\n }\n\n #[test(should_fail_with = \"Value does not fit in field\")]\n unconstrained fn decode_panics_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n let _fields = decode_fields_from_bytes(input);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/fields_as_bytes.nr","function_locations":[{"start":1007,"name":"encode_fields_as_bytes"},{"start":1603,"name":"decode_fields_from_bytes"},{"start":2190,"name":"try_decode_fields_from_bytes"},{"start":2829,"name":"try_decode_field_from_bytes"},{"start":3733,"name":"tests::round_trips_fields"},{"start":4320,"name":"tests::try_decode_returns_none_on_length_not_multiple_of_32"},{"start":4528,"name":"tests::try_decode_accepts_max_field"},{"start":5063,"name":"tests::try_decode_returns_none_on_chunk_above_modulus"},{"start":5718,"name":"tests::try_decode_returns_none_on_chunk_equal_to_modulus"},{"start":6128,"name":"tests::decode_asserts_length_multiple_of_32"},{"start":6544,"name":"tests::decode_panics_on_chunk_above_modulus"}]},"258":{"source":"use crate::protocol::{point::Point, utils::field::sqrt};\n\n// I am storing the modulus minus 1 divided by 2 here because full modulus would throw \"String literal too large\" error\n// Full modulus is 21888242871839275222246405745257275088548364400416034343698204186575808495617\nglobal BN254_FR_MODULUS_DIV_2: Field = 10944121435919637611123202872628637544274182200208017171849102093287904247808;\n\n/// Returns: true if p.y <= MOD_DIV_2, else false.\npub fn get_sign_of_point(p: Point) -> bool {\n // We store only a \"sign\" of the y coordinate because the rest can be derived from the x coordinate. To get the\n // sign we check if the y coordinate is less or equal than the field's modulus minus 1 divided by 2. Ideally we'd\n // do `y <= MOD_DIV_2`, but there's no `lte` function, so instead we do `!(y > MOD_DIV_2)`, which is equivalent,\n // and then rewrite that as `!(MOD_DIV_2 < y)`, since we also have no `gt` function.\n !BN254_FR_MODULUS_DIV_2.lt(p.y)\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\npub fn point_from_x_coord(x: Field) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n sqrt(rhs).map(|y| Point { x, y, is_infinite: false })\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate and sign for the y coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\n///\n/// @param x - The x coordinate of the point @param sign - The \"sign\" of the y coordinate - determines whether y <=\n/// (Fr.MODULUS - 1) / 2\npub fn point_from_x_coord_and_sign(x: Field, sign: bool) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n\n sqrt(rhs).map(|y| {\n // If there is a square root, we need to ensure it has the correct \"sign\"\n let y_is_positive = !BN254_FR_MODULUS_DIV_2.lt(y);\n let final_y = if y_is_positive == sign { y } else { -y };\n Point { x, y: final_y, is_infinite: false }\n })\n}\n\nmod test {\n use crate::protocol::point::Point;\n use crate::utils::point::{\n BN254_FR_MODULUS_DIV_2, get_sign_of_point, point_from_x_coord, point_from_x_coord_and_sign,\n };\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign() {\n // Test positive y coordinate\n let x = 0x1af41f5de96446dc3776a1eb2d98bb956b7acd9979a67854bec6fa7c2973bd73;\n let sign = true;\n let p = point_from_x_coord_and_sign(x, sign).unwrap();\n\n assert_eq(p.x, x);\n assert_eq(p.y, 0x07fc22c7f2c7057571f137fe46ea9c95114282bc95d37d71ec4bfb88de457d4a);\n assert_eq(p.is_infinite, false);\n\n // Test negative y coordinate\n let x2 = 0x247371652e55dd74c9af8dbe9fb44931ba29a9229994384bd7077796c14ee2b5;\n let sign2 = false;\n let p2 = point_from_x_coord_and_sign(x2, sign2).unwrap();\n\n assert_eq(p2.x, x2);\n assert_eq(p2.y, 0x26441aec112e1ae4cee374f42556932001507ad46e255ffb27369c7e3766e5c0);\n assert_eq(p2.is_infinite, false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_valid() {\n // x = 8 is a known quadratic residue - should give a valid point\n let result = point_from_x_coord(Field::from(8));\n assert(result.is_some());\n\n let point = result.unwrap();\n assert_eq(point.x, Field::from(8));\n // Check curve equation y^2 = x^3 - 17\n assert_eq(point.y * point.y, point.x * point.x * point.x - 17);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_invalid() {\n // x = 3 is a non-residue for this curve - should give None\n let x = Field::from(3);\n let maybe_point = point_from_x_coord(x);\n assert(maybe_point.is_none());\n }\n\n #[test]\n unconstrained fn test_both_roots_satisfy_curve() {\n // Derive a point from x = 8 (known to be valid from test_point_from_x_coord_valid)\n let x: Field = 8;\n let point = point_from_x_coord(x).unwrap();\n\n // Check y satisfies curve equation\n assert_eq(point.y * point.y, x * x * x - 17);\n\n // Check -y also satisfies curve equation\n let neg_y = 0 - point.y;\n assert_eq(neg_y * neg_y, x * x * x - 17);\n\n // Verify they are different (unless y = 0)\n assert(point.y != neg_y);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign_invalid() {\n // x = 3 has no valid point on the curve (from test_point_from_x_coord_invalid)\n let x = Field::from(3);\n let result_positive = point_from_x_coord_and_sign(x, true);\n let result_negative = point_from_x_coord_and_sign(x, false);\n\n assert(result_positive.is_none());\n assert(result_negative.is_none());\n }\n\n #[test]\n unconstrained fn test_get_sign_of_point() {\n // Derive a point from x = 8, then test both possible y values\n let point = point_from_x_coord(8).unwrap();\n let neg_point = Point { x: point.x, y: 0 - point.y, is_infinite: false };\n\n // One should be \"positive\" (y <= MOD_DIV_2) and one \"negative\"\n let sign1 = get_sign_of_point(point);\n let sign2 = get_sign_of_point(neg_point);\n assert(sign1 != sign2);\n\n // y = 0 should return true (0 <= MOD_DIV_2)\n let zero_y_point = Point { x: 0, y: 0, is_infinite: false };\n assert(get_sign_of_point(zero_y_point) == true);\n\n // y = MOD_DIV_2 should return true (exactly at boundary)\n let boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2, is_infinite: false };\n assert(get_sign_of_point(boundary_point) == true);\n\n // y = MOD_DIV_2 + 1 should return false (just over boundary)\n let over_boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2 + 1, is_infinite: false };\n assert(get_sign_of_point(over_boundary_point) == false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_zero() {\n // x = 0: y^2 = 0^3 - 17 = -17, which is not a quadratic residue in BN254 scalar field\n let result = point_from_x_coord(0);\n assert(result.is_none());\n }\n\n #[test]\n unconstrained fn test_bn254_fr_modulus_div_2() {\n // Verify that BN254_FR_MODULUS_DIV_2 == (p - 1) / 2 This means: 2 * BN254_FR_MODULUS_DIV_2 + 1 == p == 0 (in\n // the field)\n assert_eq(2 * BN254_FR_MODULUS_DIV_2 + 1, 0);\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/point.nr","function_locations":[{"start":488,"name":"get_sign_of_point"},{"start":1371,"name":"point_from_x_coord"},{"start":2088,"name":"point_from_x_coord_and_sign"},{"start":2697,"name":"test::test_point_from_x_coord_and_sign"},{"start":3524,"name":"test::test_point_from_x_coord_valid"},{"start":3966,"name":"test::test_point_from_x_coord_invalid"},{"start":4228,"name":"test::test_both_roots_satisfy_curve"},{"start":4803,"name":"test::test_point_from_x_coord_and_sign_invalid"},{"start":5214,"name":"test::test_get_sign_of_point"},{"start":6328,"name":"test::test_point_from_x_coord_zero"},{"start":6573,"name":"test::test_bn254_fr_modulus_div_2"}]},"268":{"source":"use std::default::Default;\nuse std::hash::Hasher;\n\nglobal RATE: u32 = 3;\n\npub struct Poseidon2 {\n cache: [Field; 3],\n state: [Field; 4],\n cache_size: u32,\n squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2 {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2::hash_internal(input, message_size)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2 {\n let mut result =\n Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n self.state[0] += self.cache[0];\n self.state[1] += self.cache[1];\n self.state[2] += self.cache[2];\n self.state = crate::poseidon2_permutation(self.state);\n }\n\n fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(input: [Field; N], in_len: u32) -> Field {\n let two_pow_64 = 18446744073709551616;\n let iv: Field = (in_len as Field) * two_pow_64;\n let mut state = [0; 4];\n state[RATE] = iv;\n\n if std::runtime::is_unconstrained() {\n for i in 0..(in_len / RATE) {\n state[0] += input[i * RATE];\n state[1] += input[i * RATE + 1];\n state[2] += input[i * RATE + 2];\n state = crate::poseidon2_permutation(state);\n }\n\n // handle remaining elements after last full RATE-sized chunk\n let num_extra_fields = in_len % RATE;\n if num_extra_fields != 0 {\n let remainder_start = in_len - num_extra_fields;\n state[0] += input[remainder_start];\n if num_extra_fields > 1 {\n state[1] += input[remainder_start + 1];\n }\n }\n } else {\n let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];\n states[0] = state;\n\n // process all full RATE-sized chunks, storing state after each permutation\n for chunk_idx in 0..(N / RATE) {\n for i in 0..RATE {\n state[i] += input[chunk_idx * RATE + i];\n }\n state = crate::poseidon2_permutation(state);\n states[chunk_idx + 1] = state;\n }\n\n // get state at the last full block before in_len\n let first_partially_filled_chunk = in_len / RATE;\n state = states[first_partially_filled_chunk];\n\n // handle remaining elements after last full RATE-sized chunk\n let remainder_start = (in_len / RATE) * RATE;\n for j in 0..RATE {\n let idx = remainder_start + j;\n if idx < in_len {\n state[j] += input[idx];\n }\n }\n }\n\n // always run final permutation unless we just completed a full chunk\n // still need to permute once if in_len is 0\n if (in_len == 0) | (in_len % RATE != 0) {\n state = crate::poseidon2_permutation(state);\n };\n\n state[0]\n }\n}\n\npub struct Poseidon2Hasher {\n _state: [Field],\n}\n\nimpl Hasher for Poseidon2Hasher {\n fn finish(self) -> Field {\n let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)\n let mut sponge = Poseidon2::new(iv);\n for i in 0..self._state.len() {\n sponge.absorb(self._state[i]);\n }\n sponge.squeeze()\n }\n\n fn write(&mut self, input: Field) {\n self._state = self._state.push_back(input);\n }\n}\n\nimpl Default for Poseidon2Hasher {\n fn default() -> Self {\n Poseidon2Hasher { _state: @[] }\n }\n}\n","path":"/Users/maximvezenov/nargo/github.com/noir-lang/poseidon/v0.3.0/src/poseidon2.nr","function_locations":[{"start":333,"name":"Poseidon2::hash"},{"start":442,"name":"Poseidon2::new"},{"start":649,"name":"Poseidon2::perform_duplex"},{"start":923,"name":"Poseidon2::absorb"},{"start":1453,"name":"Poseidon2::squeeze"},{"start":1814,"name":"Poseidon2::hash_internal"},{"start":4105,"name":"::finish"},{"start":4426,"name":"::write"},{"start":4549,"name":"::default"}]},"288":{"source":"use crate::traits::{Deserialize, Empty, FromField, Serialize, ToField};\nuse std::meta::derive;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct FunctionSelector {\n // Low 32 bits of the poseidon2 hash of the function signature.\n pub inner: u32,\n}\n\nimpl FromField for FunctionSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for FunctionSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for FunctionSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl FunctionSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = crate::hash::poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n FunctionSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n\n#[test]\nfn test_is_valid_selector() {\n let selector = FunctionSelector::from_signature(\"IS_VALID()\");\n assert_eq(selector.to_field(), 0x73cdda47);\n}\n\n#[test]\nfn test_long_selector() {\n let selector =\n FunctionSelector::from_signature(\"foo_and_bar_and_baz_and_foo_bar_baz_and_bar_foo\");\n assert_eq(selector.to_field(), 0x7590a997);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr","function_locations":[{"start":333,"name":"::from_field"},{"start":448,"name":"::to_field"},{"start":544,"name":"::empty"},{"start":652,"name":"FunctionSelector::from_u32"},{"start":756,"name":"FunctionSelector::from_signature"},{"start":1006,"name":"FunctionSelector::zero"},{"start":1079,"name":"test_is_valid_selector"},{"start":1231,"name":"test_long_selector"}]},"357":{"source":"mod poseidon2_chunks;\n\nuse crate::{\n abis::{\n contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage,\n function_selector::FunctionSelector, nullifier::Nullifier, private_log::PrivateLog,\n transaction::tx_request::TxRequest,\n },\n address::{AztecAddress, EthAddress},\n constants::{\n CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, DOM_SEP__NOTE_HASH_NONCE,\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__SILOED_NOTE_HASH, DOM_SEP__SILOED_NULLIFIER,\n DOM_SEP__UNIQUE_NOTE_HASH, FUNCTION_TREE_HEIGHT, NULL_MSG_SENDER_CONTRACT_ADDRESS,\n TWO_POW_64,\n },\n merkle_tree::root_from_sibling_path,\n messaging::l2_to_l1_message::L2ToL1Message,\n poseidon2::Poseidon2Sponge,\n side_effect::{Counted, Scoped},\n traits::{FromField, Hash, ToField},\n utils::field::{field_from_bytes, field_from_bytes_32_trunc},\n};\n\npub use poseidon2_chunks::poseidon2_absorb_in_chunks_existing_sponge;\nuse poseidon2_chunks::poseidon2_absorb_in_chunks;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\n// TODO: refactor these into their own files: sha256, poseidon2, some protocol-specific hash computations, some merkle computations.\n\npub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field {\n let sha256_hashed = sha256::digest(bytes_to_hash);\n let hash_in_a_field = field_from_bytes_32_trunc(sha256_hashed);\n\n hash_in_a_field\n}\n\npub fn private_functions_root_from_siblings(\n selector: FunctionSelector,\n vk_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT],\n) -> Field {\n let function_leaf_preimage = ContractClassFunctionLeafPreimage { selector, vk_hash };\n let function_leaf = function_leaf_preimage.hash();\n root_from_sibling_path(\n function_leaf,\n function_leaf_index,\n function_leaf_sibling_path,\n )\n}\n\n/// Siloing in the context of Aztec refers to the process of hashing a note hash with a contract address (this way\n/// the note hash is scoped to a specific contract). This is used to prevent intermingling of notes between contracts.\npub fn compute_siloed_note_hash(contract_address: AztecAddress, note_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), note_hash],\n DOM_SEP__SILOED_NOTE_HASH,\n )\n}\n\n/// Computes unique, siloed note hashes from siloed note hashes.\n///\n/// The protocol injects uniqueness into every note_hash, so that every single note_hash in the\n/// tree is unique. This prevents faerie gold attacks, where a malicious sender could create\n/// two identical note_hashes for a recipient (meaning only one would be nullifiable in future).\n///\n/// Most privacy protocols will inject the note's leaf_index (its position in the Note Hashes Tree)\n/// into the note, but this requires the creator of a note to wait until their tx is included in\n/// a block to know the note's final note hash (the unique, siloed note hash), because inserting\n/// leaves into trees is the job of a block producer.\n///\n/// We took a different approach so that the creator of a note will know each note's unique, siloed\n/// note hash before broadcasting their tx to the network.\n/// (There was also a historical requirement relating to \"chained transactions\" -- a feature that\n/// Aztec Connect had to enable notes to be spent from distinct txs earlier in the same block,\n/// and hence before an archive block root had been established for that block -- but that feature\n/// was abandoned for the Aztec Network for having too many bad tradeoffs).\n///\n/// (\n/// Edit: it is no longer true that all final note_hashes will be known by the creator of a tx\n/// before they send it to the network. If a tx makes public function calls, then _revertible_\n/// note_hashes that are created in private will not be made unique in private by the Reset circuit,\n/// but will instead be made unique by the AVM, because the `note_index_in_tx` will not be known\n/// until the AVM has executed the public functions of the tx. (See an explanation in\n/// reset_output_composer.nr for why).\n/// For some such txs, the `note_index_in_tx` might still be predictable through simulation, but\n/// for txs whose public functions create a varying number of non-revertible notes (determined at\n/// runtime), the `note_index_in_tx` will not be deterministically derivable before submitting the\n/// tx to the network.\n/// )\n///\n/// We use the `first_nullifier` of a tx as a seed of uniqueness. We have a guarantee that there will\n/// always be at least one nullifier per tx, because the init circuit will create one if one isn't\n/// created naturally by any functions of the tx. (Search \"protocol_nullifier\").\n/// We combine the `first_nullifier` with the note's index (its position within this tx's new\n/// note_hashes array) (`note_index_in_tx`) to get a truly unique value to inject into a note, which\n/// we call a `note_nonce`.\npub fn compute_unique_note_hash(note_nonce: Field, siloed_note_hash: Field) -> Field {\n let inputs = [note_nonce, siloed_note_hash];\n poseidon2_hash_with_separator(inputs, DOM_SEP__UNIQUE_NOTE_HASH)\n}\n\npub fn compute_note_hash_nonce(first_nullifier_in_tx: Field, note_index_in_tx: u32) -> Field {\n // Hashing the first nullifier with note index in tx is guaranteed to be unique (because all nullifiers are also\n // unique).\n poseidon2_hash_with_separator(\n [first_nullifier_in_tx, note_index_in_tx as Field],\n DOM_SEP__NOTE_HASH_NONCE,\n )\n}\n\npub fn compute_note_nonce_and_unique_note_hash(\n siloed_note_hash: Field,\n first_nullifier: Field,\n note_index_in_tx: u32,\n) -> Field {\n let note_nonce = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n compute_unique_note_hash(note_nonce, siloed_note_hash)\n}\n\npub fn compute_siloed_nullifier(contract_address: AztecAddress, nullifier: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), nullifier],\n DOM_SEP__SILOED_NULLIFIER,\n )\n}\n\npub fn create_protocol_nullifier(tx_request: TxRequest) -> Scoped> {\n // The protocol nullifier is ascribed a special side-effect counter of 1. No other side-effect\n // can have counter 1 (see `validate_as_first_call` for that assertion).\n Nullifier { value: tx_request.hash(), note_hash: 0 }.count(1).scope(\n NULL_MSG_SENDER_CONTRACT_ADDRESS,\n )\n}\n\npub fn compute_log_tag(raw_tag: Field, dom_sep: u32) -> Field {\n poseidon2_hash_with_separator([raw_tag], dom_sep)\n}\n\npub fn compute_siloed_private_log_first_field(\n contract_address: AztecAddress,\n field: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), field],\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD,\n )\n}\n\npub fn compute_siloed_private_log(contract_address: AztecAddress, log: PrivateLog) -> PrivateLog {\n let mut fields = log.fields;\n fields[0] = compute_siloed_private_log_first_field(contract_address, fields[0]);\n PrivateLog::new(fields, log.length)\n}\n\npub fn compute_contract_class_log_hash(log: [Field; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS]) -> Field {\n poseidon2_hash(log)\n}\n\npub fn compute_app_siloed_secret_key(\n master_secret_key: EmbeddedCurveScalar,\n app_address: AztecAddress,\n key_type_domain_separator: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [master_secret_key.hi, master_secret_key.lo, app_address.to_field()],\n key_type_domain_separator,\n )\n}\n\npub fn compute_l2_to_l1_message_hash(\n message: Scoped,\n rollup_version_id: Field,\n chain_id: Field,\n) -> Field {\n let contract_address_bytes: [u8; 32] = message.contract_address.to_field().to_be_bytes();\n let recipient_bytes: [u8; 20] = message.inner.recipient.to_be_bytes();\n let content_bytes: [u8; 32] = message.inner.content.to_be_bytes();\n let rollup_version_id_bytes: [u8; 32] = rollup_version_id.to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n\n let mut bytes: [u8; 148] = std::mem::zeroed();\n for i in 0..32 {\n bytes[i] = contract_address_bytes[i];\n bytes[i + 32] = rollup_version_id_bytes[i];\n // 64 - 84 are for recipient.\n bytes[i + 84] = chain_id_bytes[i];\n bytes[i + 116] = content_bytes[i];\n }\n\n for i in 0..20 {\n bytes[64 + i] = recipient_bytes[i];\n }\n\n sha256_to_field(bytes)\n}\n\n// TODO: consider a variant that enables domain separation with a u32 (we seem to have standardised u32s for domain separators)\n/// Computes sha256 hash of 2 input fields.\n///\n/// @returns A truncated field (i.e., the first byte is always 0).\npub fn accumulate_sha256(v0: Field, v1: Field) -> Field {\n // Concatenate two fields into 32 x 2 = 64 bytes\n let v0_as_bytes: [u8; 32] = v0.to_be_bytes();\n let v1_as_bytes: [u8; 32] = v1.to_be_bytes();\n let hash_input_flattened = v0_as_bytes.concat(v1_as_bytes);\n\n sha256_to_field(hash_input_flattened)\n}\n\npub fn poseidon2_hash(inputs: [Field; N]) -> Field {\n poseidon::poseidon2::Poseidon2::hash(inputs, N)\n}\n\n#[no_predicates]\npub fn poseidon2_hash_with_separator(inputs: [Field; N], separator: T) -> Field\nwhere\n T: ToField,\n{\n let inputs_with_separator = [separator.to_field()].concat(inputs);\n poseidon2_hash(inputs_with_separator)\n}\n\n/// Computes a Poseidon2 hash over a dynamic-length subarray of the given input.\n/// Only the first `in_len` fields of `input` are absorbed; any remaining fields are ignored.\n/// The caller is responsible for ensuring that the input is padded with zeros if required.\n#[no_predicates]\npub fn poseidon2_hash_subarray(input: [Field; N], in_len: u32) -> Field {\n let mut sponge = poseidon2_absorb_in_chunks(input, in_len);\n sponge.squeeze()\n}\n\n// This function is unconstrained because it is intended to be used in unconstrained context only as\n// in constrained contexts it would be too inefficient.\npub unconstrained fn poseidon2_hash_with_separator_bounded_vec(\n inputs: BoundedVec,\n separator: T,\n) -> Field\nwhere\n T: ToField,\n{\n let in_len = inputs.len() + 1;\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n sponge.absorb(separator.to_field());\n\n for i in 0..inputs.len() {\n sponge.absorb(inputs.get(i));\n }\n\n sponge.squeeze()\n}\n\n#[no_predicates]\npub fn poseidon2_hash_bytes(inputs: [u8; N]) -> Field {\n let mut fields = [0; (N + 30) / 31];\n let mut field_index = 0;\n let mut current_field = [0; 31];\n for i in 0..inputs.len() {\n let index = i % 31;\n current_field[index] = inputs[i];\n if index == 30 {\n fields[field_index] = field_from_bytes(current_field, false);\n current_field = [0; 31];\n field_index += 1;\n }\n }\n if field_index != fields.len() {\n fields[field_index] = field_from_bytes(current_field, false);\n }\n poseidon2_hash(fields)\n}\n\n#[test]\nfn subarray_hash_matches_fixed() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash the entire values_to_hash.\n let fixed_len_hash = poseidon::poseidon2::Poseidon2::hash(values_to_hash, values_to_hash.len());\n\n assert_eq(subarray_hash, fixed_len_hash);\n}\n\n#[test]\nfn subarray_hash_matches_variable() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash up to values_to_hash.len() fields of the padded array.\n let variable_len_hash = poseidon::poseidon2::Poseidon2::hash(padded, values_to_hash.len());\n\n assert_eq(subarray_hash, variable_len_hash);\n}\n\n#[test]\nfn smoke_sha256_to_field() {\n let full_buffer = [\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\n 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,\n 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,\n 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,\n 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,\n 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,\n 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\n ];\n let result = sha256_to_field(full_buffer);\n\n assert(result == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184c7);\n\n // to show correctness of the current ver (truncate one byte) vs old ver (mod full bytes):\n let result_bytes = sha256::digest(full_buffer);\n let truncated_field = crate::utils::field::field_from_bytes_32_trunc(result_bytes);\n assert(truncated_field == result);\n let mod_res = result + (result_bytes[31] as Field);\n assert(mod_res == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184e0);\n}\n\n#[test]\nfn unique_siloed_note_hash_matches_typescript() {\n let inner_note_hash = 1;\n let contract_address = AztecAddress::from_field(2);\n let first_nullifier = 3;\n let note_index_in_tx = 4;\n\n let siloed_note_hash = compute_siloed_note_hash(contract_address, inner_note_hash);\n let siloed_note_hash_from_ts =\n 0x1986a4bea3eddb1fff917d629a13e10f63f514f401bdd61838c6b475db949169;\n assert_eq(siloed_note_hash, siloed_note_hash_from_ts);\n\n let nonce: Field = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n let note_hash_nonce_from_ts =\n 0x28e7799791bf066a57bb51fdd0fbcaf3f0926414314c7db515ea343f44f5d58b;\n assert_eq(nonce, note_hash_nonce_from_ts);\n\n let unique_siloed_note_hash_from_nonce = compute_unique_note_hash(nonce, siloed_note_hash);\n let unique_siloed_note_hash = compute_note_nonce_and_unique_note_hash(\n siloed_note_hash,\n first_nullifier,\n note_index_in_tx,\n );\n assert_eq(unique_siloed_note_hash_from_nonce, unique_siloed_note_hash);\n\n let unique_siloed_note_hash_from_ts =\n 0x29949aef207b715303b24639737c17fbfeb375c1d965ecfa85c7e4f0febb7d16;\n assert_eq(unique_siloed_note_hash, unique_siloed_note_hash_from_ts);\n}\n\n#[test]\nfn siloed_nullifier_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let nullifier = 456;\n\n let res = compute_siloed_nullifier(contract_address, nullifier);\n\n let siloed_nullifier_from_ts =\n 0x169b50336c1f29afdb8a03d955a81e485f5ac7d5f0b8065673d1e407e5877813;\n\n assert_eq(res, siloed_nullifier_from_ts);\n}\n\n#[test]\nfn siloed_private_log_first_field_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let field = 456;\n let res = compute_siloed_private_log_first_field(contract_address, field);\n\n let siloed_private_log_first_field_from_ts =\n 0x29480984f7b9257fded523d50addbcfc8d1d33adcf2db73ef3390a8fd5cdffaa;\n\n assert_eq(res, siloed_private_log_first_field_from_ts);\n}\n\n#[test]\nfn empty_l2_to_l1_message_hash_matches_typescript() {\n // All zeroes\n let res = compute_l2_to_l1_message_hash(\n L2ToL1Message { recipient: EthAddress::zero(), content: 0 }.scope(AztecAddress::from_field(\n 0,\n )),\n 0,\n 0,\n );\n\n let empty_l2_to_l1_msg_hash_from_ts =\n 0x003b18c58c739716e76429634a61375c45b3b5cd470c22ab6d3e14cee23dd992;\n\n assert_eq(res, empty_l2_to_l1_msg_hash_from_ts);\n}\n\n#[test]\nfn l2_to_l1_message_hash_matches_typescript() {\n let message = L2ToL1Message { recipient: EthAddress::from_field(1), content: 2 }.scope(\n AztecAddress::from_field(3),\n );\n let version = 4;\n let chainId = 5;\n\n let hash = compute_l2_to_l1_message_hash(message, version, chainId);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let l2_to_l1_message_hash_from_ts =\n 0x0081edf209e087ad31b3fd24263698723d57190bd1d6e9fe056fc0c0a68ee661;\n\n assert_eq(hash, l2_to_l1_message_hash_from_ts);\n}\n\n#[test]\nunconstrained fn poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version() {\n let inputs = BoundedVec::::from_array([1, 2, 3]);\n let separator = 42;\n\n // Hash using bounded vec version\n let bounded_result = poseidon2_hash_with_separator_bounded_vec(inputs, separator);\n\n // Hash using regular version\n let regular_result = poseidon2_hash_with_separator([1, 2, 3], separator);\n\n // Results should match\n assert_eq(bounded_result, regular_result);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr","function_locations":[{"start":1253,"name":"sha256_to_field"},{"start":1605,"name":"private_functions_root_from_siblings"},{"start":2202,"name":"compute_siloed_note_hash"},{"start":5031,"name":"compute_unique_note_hash"},{"start":5247,"name":"compute_note_hash_nonce"},{"start":5663,"name":"compute_note_nonce_and_unique_note_hash"},{"start":5899,"name":"compute_siloed_nullifier"},{"start":6116,"name":"create_protocol_nullifier"},{"start":6480,"name":"compute_log_tag"},{"start":6651,"name":"compute_siloed_private_log_first_field"},{"start":6882,"name":"compute_siloed_private_log"},{"start":7142,"name":"compute_contract_class_log_hash"},{"start":7333,"name":"compute_app_siloed_secret_key"},{"start":7628,"name":"compute_l2_to_l1_message_hash"},{"start":8709,"name":"accumulate_sha256"},{"start":9037,"name":"poseidon2_hash"},{"start":9228,"name":"poseidon2_hash_with_separator"},{"start":9714,"name":"poseidon2_hash_subarray"},{"start":10126,"name":"poseidon2_hash_with_separator_bounded_vec"},{"start":10487,"name":"poseidon2_hash_bytes"},{"start":11063,"name":"subarray_hash_matches_fixed"},{"start":11462,"name":"subarray_hash_matches_variable"},{"start":11878,"name":"smoke_sha256_to_field"},{"start":13280,"name":"unique_siloed_note_hash_matches_typescript"},{"start":14502,"name":"siloed_nullifier_matches_typescript"},{"start":14882,"name":"siloed_private_log_first_field_matches_typescript"},{"start":15292,"name":"empty_l2_to_l1_message_hash_matches_typescript"},{"start":15743,"name":"l2_to_l1_message_hash_matches_typescript"},{"start":16359,"name":"poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version"}]},"359":{"source":"// Log levels matching the JS logger:\n\n// global SILENT_LOG_LEVEL: u8 = 0;\nglobal FATAL_LOG_LEVEL: u8 = 1;\nglobal ERROR_LOG_LEVEL: u8 = 2;\nglobal WARN_LOG_LEVEL: u8 = 3;\nglobal INFO_LOG_LEVEL: u8 = 4;\nglobal VERBOSE_LOG_LEVEL: u8 = 5;\nglobal DEBUG_LOG_LEVEL: u8 = 6;\nglobal TRACE_LOG_LEVEL: u8 = 7;\n\n// --- Per-level log functions (no format args) ---\n\npub fn fatal_log(msg: str) {\n fatal_log_format(msg, []);\n}\n\npub fn error_log(msg: str) {\n error_log_format(msg, []);\n}\n\npub fn warn_log(msg: str) {\n warn_log_format(msg, []);\n}\n\npub fn info_log(msg: str) {\n info_log_format(msg, []);\n}\n\npub fn verbose_log(msg: str) {\n verbose_log_format(msg, []);\n}\n\npub fn debug_log(msg: str) {\n debug_log_format(msg, []);\n}\n\npub fn trace_log(msg: str) {\n trace_log_format(msg, []);\n}\n\n// --- Per-level log functions (with format args) ---\n\npub fn fatal_log_format(msg: str, args: [Field; N]) {\n log_format(FATAL_LOG_LEVEL, msg, args);\n}\n\npub fn error_log_format(msg: str, args: [Field; N]) {\n log_format(ERROR_LOG_LEVEL, msg, args);\n}\n\npub fn warn_log_format(msg: str, args: [Field; N]) {\n log_format(WARN_LOG_LEVEL, msg, args);\n}\n\npub fn info_log_format(msg: str, args: [Field; N]) {\n log_format(INFO_LOG_LEVEL, msg, args);\n}\n\npub fn verbose_log_format(msg: str, args: [Field; N]) {\n log_format(VERBOSE_LOG_LEVEL, msg, args);\n}\n\npub fn debug_log_format(msg: str, args: [Field; N]) {\n log_format(DEBUG_LOG_LEVEL, msg, args);\n}\n\npub fn trace_log_format(msg: str, args: [Field; N]) {\n log_format(TRACE_LOG_LEVEL, msg, args);\n}\n\nfn log_format(log_level: u8, msg: str, args: [Field; N]) {\n // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe\n // to call.\n unsafe { log_oracle_wrapper(log_level, msg, args) };\n}\n\nunconstrained fn log_oracle_wrapper(\n log_level: u8,\n msg: str,\n args: [Field; N],\n) {\n log_oracle(log_level, msg, N, args);\n}\n\n// While the length parameter might seem unnecessary given that we have N, we keep it around because at the AVM\n// bytecode level we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally\n// take that route. The AVM transpiler maps this oracle to the DEBUGLOG opcode, which reads the fields size from memory.\n#[oracle(aztec_utl_log)]\nunconstrained fn log_oracle(\n log_level: u8,\n msg: str,\n length: u32,\n args: [Field; N],\n) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/logging.nr","function_locations":[{"start":395,"name":"fatal_log"},{"start":473,"name":"error_log"},{"start":550,"name":"warn_log"},{"start":626,"name":"info_log"},{"start":705,"name":"verbose_log"},{"start":785,"name":"debug_log"},{"start":863,"name":"trace_log"},{"start":1033,"name":"fatal_log_format"},{"start":1161,"name":"error_log_format"},{"start":1288,"name":"warn_log_format"},{"start":1414,"name":"info_log_format"},{"start":1543,"name":"verbose_log_format"},{"start":1673,"name":"debug_log_format"},{"start":1801,"name":"trace_log_format"},{"start":1934,"name":"log_format"},{"start":2248,"name":"log_oracle_wrapper"},{"start":2801,"name":"log_oracle"}]},"378":{"source":"use crate::constants::TWO_POW_64;\nuse crate::traits::{Deserialize, Serialize};\nuse std::meta::derive;\n// NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr\n// It exists as we sometimes need to perform custom absorption, but the stdlib version\n// has a private absorb() method (it's also designed to just be a hasher)\n// Can be removed when standalone noir poseidon lib exists: See noir#6679\n// TODO: Poseidon is stand-alone now\n\nglobal RATE: u32 = 3;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct Poseidon2Sponge {\n pub cache: [Field; 3],\n pub state: [Field; 4],\n pub cache_size: u32,\n pub squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2Sponge {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2Sponge::hash_internal(input, message_size, message_size != N)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2Sponge {\n let mut result =\n Poseidon2Sponge { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n for i in 0..RATE {\n // We effectively zero-pad the cache by only adding to the state\n // cache that is less than the specified `cache_size`\n if i < self.cache_size {\n self.state[i] += self.cache[i];\n }\n }\n self.state = std::hash::poseidon2_permutation(self.state);\n }\n\n pub fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n pub fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(\n input: [Field; N],\n in_len: u32,\n is_variable_length: bool,\n ) -> Field {\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n for i in 0..input.len() {\n if i < in_len {\n sponge.absorb(input[i]);\n }\n }\n\n sponge.squeeze()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr","function_locations":[{"start":798,"name":"Poseidon2Sponge::hash"},{"start":938,"name":"Poseidon2Sponge::new"},{"start":1151,"name":"Poseidon2Sponge::perform_duplex"},{"start":1592,"name":"Poseidon2Sponge::absorb"},{"start":2126,"name":"Poseidon2Sponge::squeeze"},{"start":2544,"name":"Poseidon2Sponge::hash_internal"}]},"397":{"source":"use crate::utils::field::field_from_bytes;\n\npub trait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n #[inline_always]\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for bool {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u8 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u16 {\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u32 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u64 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u128 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for str {\n #[inline_always]\n fn to_field(self) -> Field {\n assert(N < 32, \"String doesn't fit in a field, consider using Serialize instead\");\n field_from_bytes(self.as_bytes(), true)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/traits/to_field.nr","function_locations":[{"start":176,"name":"::to_field"},{"start":276,"name":"::to_field"},{"start":382,"name":"::to_field"},{"start":468,"name":"::to_field"},{"start":575,"name":"::to_field"},{"start":682,"name":"::to_field"},{"start":790,"name":"::to_field"},{"start":912,"name":">::to_field"}]},"405":{"source":"pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n\n// Convert a 32 byte array to a field element by truncating the final byte\npub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..15 {\n // covers bytes 16..30 (31 is truncated and ignored)\n low = low + (bytes32[15 + 15 - i] as Field) * v;\n v = v * 256;\n // covers bytes 0..14\n high = high + (bytes32[14 - i] as Field) * v;\n }\n // covers byte 15\n low = low + (bytes32[15] as Field) * v;\n\n low + high * v\n}\n\npub fn min(f1: Field, f2: Field) -> Field {\n if f1.lt(f2) {\n f1\n } else {\n f2\n }\n}\n\n// TODO: write doc-comments and tests for these magic constants.\n\nglobal KNOWN_NON_RESIDUE: Field = 5; // This is a non-residue in Noir's native Field.\nglobal C1: u32 = 28;\nglobal C3: Field = 40770029410420498293352137776570907027550720424234931066070132305055;\nglobal C5: Field = 19103219067921713944291392827692070036145651957329286315305642004821462161904;\n\n// @dev: only use this for _huge_ exponents y, when writing a constrained function.\n// If you're only exponentiating by a small value, first consider writing-out the multiplications by hand.\n// Only after you've measured the gates of that approach, consider using the native Field::pow_32 function.\n// Only if your exponent is larger than 32 bits, resort to using this function.\npub fn pow(x: Field, y: Field) -> Field {\n let mut r = 1 as Field;\n let b: [bool; 254] = y.to_le_bits();\n\n for i in 0..254 {\n r *= r;\n r *= (b[254 - 1 - i] as Field) * x + (1 - b[254 - 1 - i] as Field);\n }\n\n r\n}\n\n/// Returns Option::some(sqrt) if there is a square root, and Option::none() if there isn't.\npub fn sqrt(x: Field) -> Option {\n // Safety: if the hint returns the square root of x, then we simply square it\n // check the result equals x. If x is not square, we return a value that\n // enables us to prove that fact (see the `else` clause below).\n let (is_sq, maybe_sqrt) = unsafe { __sqrt(x) };\n\n if is_sq {\n let sqrt = maybe_sqrt;\n validate_sqrt_hint(x, sqrt);\n Option::some(sqrt)\n } else {\n let not_sqrt_hint = maybe_sqrt;\n validate_not_sqrt_hint(x, not_sqrt_hint);\n Option::none()\n }\n}\n\n// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.\nunconstrained fn is_square(x: Field) -> bool {\n let v = pow(x, -1 / 2);\n v * (v - 1) == 0\n}\n\n// Tonelli-Shanks algorithm for computing the square root of a Field element.\n// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field\n// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),\n// and C5 = ZETA^C2, where ZETA is a non-square element of Field.\n// These are pre-computed above as globals.\nunconstrained fn tonelli_shanks_sqrt(x: Field) -> Field {\n let mut z = pow(x, C3);\n let mut t = z * z * x;\n z *= x;\n let mut b = t;\n let mut c = C5;\n\n for i in 0..(C1 - 1) {\n for _j in 1..(C1 - i - 1) {\n b *= b;\n }\n\n z *= if b == 1 { 1 } else { c };\n\n c *= c;\n\n t *= if b == 1 { 1 } else { c };\n\n b = t;\n }\n\n z\n}\n\n// NB: this doesn't return an option, because in the case of there _not_ being a square root, we still want to return a field element that allows us to then assert in the _constrained_ sqrt function that there is no sqrt.\nunconstrained fn __sqrt(x: Field) -> (bool, Field) {\n let is_sq = is_square(x);\n if is_sq {\n let sqrt = tonelli_shanks_sqrt(x);\n (true, sqrt)\n } else {\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // sq * sq = sq // 1 * 1 = 1\n // non-sq * non-sq = sq // -1 * -1 = 1\n // sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n let not_sqrt = tonelli_shanks_sqrt(demo_x_not_square);\n (false, not_sqrt)\n }\n}\n\nfn validate_sqrt_hint(x: Field, hint: Field) {\n assert(hint * hint == x, f\"The claimed_sqrt {hint} is not the sqrt of x {x}\");\n}\n\nfn validate_not_sqrt_hint(x: Field, hint: Field) {\n // We need this assertion, because x = 0 would pass the other assertions in this\n // function, and we don't want people to be able to prove that 0 is not square!\n assert(x != 0, \"0 has a square root; you cannot claim it is not square\");\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n //\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // 1. sq * sq = sq // 1 * 1 = 1\n // 2. non-sq * non-sq = sq // -1 * -1 = 1\n // 3. sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n //\n // We want to demonstrate that this below multiplication falls under bullet-point (2):\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n // I.e. we want to demonstrate that `demo_x_not_square` has Legendre symbol 1\n // (i.e. that it is a square), so we prove that it is square below.\n // Why do we want to prove that it has LS 1?\n // Well, since it was computed with a known-non-residue, its squareness implies we're\n // in case 2 (something multiplied by a known-non-residue yielding a result which\n // has a LS of 1), which implies that x must be a non-square. The unconstrained\n // function gave us the sqrt of demo_x_not_square, so all we need to do is\n // assert its squareness:\n assert(\n hint * hint == demo_x_not_square,\n f\"The hint {hint} does not demonstrate that {x} is not a square\",\n );\n}\n\n#[test]\nunconstrained fn bytes_field_test() {\n // Tests correctness of field_from_bytes_32_trunc against existing methods\n // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7\n let inputs = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167,\n ];\n let field = field_from_bytes(inputs, true);\n let return_bytes: [u8; 31] = field.to_be_bytes();\n assert_eq(inputs, return_bytes);\n // 32 bytes - we remove the final byte, and check it matches the field\n let inputs2 = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158,\n ];\n let field2 = field_from_bytes_32_trunc(inputs2);\n let return_bytes2: [u8; 31] = field2.to_be_bytes();\n\n assert_eq(return_bytes2, return_bytes);\n assert_eq(field2, field);\n}\n\n#[test]\nunconstrained fn max_field_test() {\n // Tests the hardcoded value in constants.nr vs underlying modulus\n // NB: We can't use 0-1 in constants.nr as it will be transpiled incorrectly to ts and sol constants files\n let max_value = crate::constants::MAX_FIELD_VALUE;\n assert_eq(max_value, 0 - 1);\n // modulus == 0 is tested elsewhere, so below is more of a sanity check\n let max_bytes: [u8; 32] = max_value.to_be_bytes();\n let mod_bytes = std::field::modulus_be_bytes();\n for i in 0..31 {\n assert_eq(max_bytes[i], mod_bytes[i]);\n }\n assert_eq(max_bytes[31], mod_bytes[31] - 1);\n}\n\n#[test]\nunconstrained fn sqrt_valid_test() {\n let x = 16; // examples: 16, 9, 25, 81\n let result = sqrt(x);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), x);\n}\n\n#[test]\nunconstrained fn sqrt_invalid_test() {\n let x = KNOWN_NON_RESIDUE; // has no square root in the field\n let result = sqrt(x);\n assert(result.is_none());\n}\n\n#[test]\nunconstrained fn sqrt_zero_test() {\n let result = sqrt(0);\n assert(result.is_some());\n assert_eq(result.unwrap(), 0);\n}\n\n#[test]\nunconstrained fn sqrt_one_test() {\n let result = sqrt(1);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), 1);\n}\n\n#[test]\nunconstrained fn field_from_bytes_empty_test() {\n let empty: [u8; 0] = [];\n let result = field_from_bytes(empty, true);\n assert_eq(result, 0);\n\n let result_le = field_from_bytes(empty, false);\n assert_eq(result_le, 0);\n}\n\n#[test]\nunconstrained fn field_from_bytes_little_endian_test() {\n // Test little-endian conversion: [0x01, 0x02] should be 0x0201 = 513\n let bytes = [0x01, 0x02];\n let result_le = field_from_bytes(bytes, false);\n assert_eq(result_le, 0x0201);\n\n // Compare with big-endian: [0x01, 0x02] should be 0x0102 = 258\n let result_be = field_from_bytes(bytes, true);\n assert_eq(result_be, 0x0102);\n}\n\n#[test]\nunconstrained fn pow_test() {\n assert_eq(pow(2, 0), 1);\n assert_eq(pow(2, 1), 2);\n assert_eq(pow(2, 10), 1024);\n assert_eq(pow(3, 5), 243);\n assert_eq(pow(0, 5), 0);\n assert_eq(pow(1, 100), 1);\n}\n\n#[test]\nunconstrained fn min_test() {\n assert_eq(min(5, 10), 5);\n assert_eq(min(10, 5), 5);\n assert_eq(min(7, 7), 7);\n assert_eq(min(0, 1), 0);\n}\n\n#[test]\nunconstrained fn sqrt_has_two_roots_test() {\n // Every square has two roots: r and -r (i.e., p - r)\n // sqrt(16) can return 4 or -4\n let x = 16;\n let result = sqrt(x).unwrap();\n assert(result * result == x);\n // The other root is -result\n let other_root = 0 - result;\n assert(other_root * other_root == x);\n // Verify they are different (unless x = 0)\n assert(result != other_root);\n\n // Same for 9: roots are 3 and -3\n let y = 9;\n let result_y = sqrt(y).unwrap();\n assert(result_y * result_y == y);\n let other_root_y = 0 - result_y;\n assert(other_root_y * other_root_y == y);\n assert(result_y != other_root_y);\n}\n\n#[test]\nunconstrained fn sqrt_negative_one_test() {\n let x = 0 - 1;\n let result = sqrt(x);\n assert(result.unwrap() == 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636);\n}\n\n#[test]\nunconstrained fn validate_sqrt_hint_valid_test() {\n // 4 is a valid sqrt of 16\n validate_sqrt_hint(16, 4);\n // -4 is also a valid sqrt of 16\n validate_sqrt_hint(16, 0 - 4);\n // 0 is a valid sqrt of 0\n validate_sqrt_hint(0, 0);\n // 1 is a valid sqrt of 1\n validate_sqrt_hint(1, 1);\n // -1 is also a valid sqrt of 1\n validate_sqrt_hint(1, 0 - 1);\n}\n\n#[test(should_fail_with = \"is not the sqrt of x\")]\nunconstrained fn validate_sqrt_hint_invalid_test() {\n // 5 is not a valid sqrt of 16\n validate_sqrt_hint(16, 5);\n}\n\n#[test]\nunconstrained fn validate_not_sqrt_hint_valid_test() {\n // 5 (KNOWN_NON_RESIDUE) is not a square.\n let x = KNOWN_NON_RESIDUE;\n let hint = tonelli_shanks_sqrt(x * KNOWN_NON_RESIDUE);\n validate_not_sqrt_hint(x, hint);\n}\n\n#[test(should_fail_with = \"0 has a square root\")]\nunconstrained fn validate_not_sqrt_hint_zero_test() {\n // 0 has a square root, so we cannot claim it is not square\n validate_not_sqrt_hint(0, 0);\n}\n\n#[test(should_fail_with = \"does not demonstrate that\")]\nunconstrained fn validate_not_sqrt_hint_wrong_hint_test() {\n // Provide a wrong hint for a non-square\n let x = KNOWN_NON_RESIDUE;\n validate_not_sqrt_hint(x, 123);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr","function_locations":[{"start":79,"name":"field_from_bytes"},{"start":553,"name":"field_from_bytes_32_trunc"},{"start":1054,"name":"min"},{"start":1899,"name":"pow"},{"start":2233,"name":"sqrt"},{"start":2915,"name":"is_square"},{"start":3343,"name":"tonelli_shanks_sqrt"},{"start":3951,"name":"__sqrt"},{"start":4795,"name":"validate_sqrt_hint"},{"start":4932,"name":"validate_not_sqrt_hint"},{"start":6570,"name":"bytes_field_test"},{"start":7553,"name":"max_field_test"},{"start":8177,"name":"sqrt_valid_test"},{"start":8379,"name":"sqrt_invalid_test"},{"start":8548,"name":"sqrt_zero_test"},{"start":8685,"name":"sqrt_one_test"},{"start":8854,"name":"field_from_bytes_empty_test"},{"start":9107,"name":"field_from_bytes_little_endian_test"},{"start":9492,"name":"pow_test"},{"start":9715,"name":"min_test"},{"start":9889,"name":"sqrt_has_two_roots_test"},{"start":10562,"name":"sqrt_negative_one_test"},{"start":10768,"name":"validate_sqrt_hint_valid_test"},{"start":11199,"name":"validate_sqrt_hint_invalid_test"},{"start":11331,"name":"validate_not_sqrt_hint_valid_test"},{"start":11611,"name":"validate_not_sqrt_hint_zero_test"},{"start":11828,"name":"validate_not_sqrt_hint_wrong_hint_test"}]},"411":{"source":"pub struct Reader {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Reader {\n pub fn new(data: [Field; N]) -> Self {\n Self { data, offset: 0 }\n }\n\n pub fn read(&mut self) -> Field {\n let result = self.data[self.offset];\n self.offset += 1;\n result\n }\n\n pub fn read_u32(&mut self) -> u32 {\n self.read() as u32\n }\n\n pub fn read_u64(&mut self) -> u64 {\n self.read() as u64\n }\n\n pub fn read_bool(&mut self) -> bool {\n self.read() != 0\n }\n\n pub fn read_array(&mut self) -> [Field; K] {\n let mut result = [0; K];\n for i in 0..K {\n result[i] = self.data[self.offset + i];\n }\n self.offset += K;\n result\n }\n\n pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T {\n let result = deserialise(self.read_array());\n result\n }\n\n pub fn read_struct_array(\n &mut self,\n deserialise: fn([Field; K]) -> T,\n mut result: [T; C],\n ) -> [T; C] {\n for i in 0..C {\n result[i] = self.read_struct(deserialise);\n }\n result\n }\n\n pub fn peek_offset(&mut self, offset: u32) -> Field {\n self.data[self.offset + offset]\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) {\n assert_eq(self.offset, self.data.len(), \"Reader did not read all data\");\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/reader.nr","function_locations":[{"start":144,"name":"Reader::new"},{"start":222,"name":"Reader::read"},{"start":355,"name":"Reader::read_u32"},{"start":429,"name":"Reader::read_u64"},{"start":505,"name":"Reader::read_bool"},{"start":598,"name":"Reader::read_array"},{"start":855,"name":"Reader::read_struct"},{"start":1094,"name":"Reader::read_struct_array"},{"start":1263,"name":"Reader::peek_offset"},{"start":1362,"name":"Reader::advance_offset"},{"start":1426,"name":"Reader::finish"}]},"412":{"source":"use crate::{reader::Reader, writer::Writer};\n\n/// Trait for serializing Noir types into arrays of Fields.\n///\n/// An implementation of the Serialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait (and Deserialize) are\n/// typically used to communicate between Noir and TypeScript (via oracles and function arguments).\n///\n/// # On Following Noir's Intrinsic Serialization\n/// When calling a Noir function from TypeScript (TS), first the function arguments are serialized into an array\n/// of fields. This array is then included in the initial witness. Noir's intrinsic serialization is then used\n/// to deserialize the arguments from the witness. When the same Noir function is called from Noir this Serialize trait\n/// is used instead of the serialization in TS. For this reason we need to have a match between TS serialization,\n/// Noir's intrinsic serialization and the implementation of this trait. If there is a mismatch, the function calls\n/// fail with an arguments hash mismatch error message.\n///\n/// # Associated Constants\n/// * `N` - The length of the output Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Serialize for str {\n/// let N: u32 = N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// let bytes = self.as_bytes();\n/// for i in 0..bytes.len() {\n/// writer.write(bytes[i] as Field);\n/// }\n/// }\n/// }\n/// ```\n#[derive_via(derive_serialize)]\npub trait Serialize {\n let N: u32;\n\n fn serialize(self) -> [Field; Self::N];\n\n fn stream_serialize(self, writer: &mut Writer);\n}\n\n/// Generates a `Serialize` trait implementation for a struct type.\n///\n/// # Parameters\n/// - `s`: The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A quoted code block containing the trait implementation\n///\n/// # Example\n/// For a struct defined as:\n/// ```\n/// struct Log {\n/// fields: [Field; N],\n/// length: u32\n/// }\n/// ```\n///\n/// This function generates code equivalent to:\n/// ```\n/// impl Serialize for Log {\n/// let N: u32 = <[Field; N] as Serialize>::N + ::N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// #[inline_always]\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// Serialize::stream_serialize(self.fields, writer);\n/// Serialize::stream_serialize(self.length, writer);\n/// }\n/// }\n/// ```\npub comptime fn derive_serialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n\n // We care only about the name and type so we drop the last item of the tuple\n let params = nested_struct.0.fields(nested_struct.1).map(|(name, typ, _)| (name, typ));\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Serialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_serialize_clause = get_where_trait_clause(s, quote {Serialize});\n\n let params_len_quote = get_params_len_quote(params);\n\n let function_body = params\n .map(|(name, _typ): (Quoted, Type)| {\n quote {\n $crate::serialization::Serialize::stream_serialize(self.$name, writer);\n }\n })\n .join(quote {});\n\n quote {\n impl$generics_declarations $crate::serialization::Serialize for $typ\n $where_serialize_clause\n {\n let N: u32 = $params_len_quote;\n\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n $crate::serialization::Serialize::stream_serialize(self, &mut writer);\n writer.finish()\n }\n\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n $function_body\n }\n }\n }\n}\n\n/// Trait for deserializing Noir types from arrays of Fields.\n///\n/// An implementation of the Deserialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait is typically used when\n/// deserializing return values from function calls in Noir. Since the same function could be called from TypeScript\n/// (TS), in which case the TS deserialization would get used, we need to have a match between the 2.\n///\n/// # Associated Constants\n/// * `N` - The length of the input Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Deserialize for str {\n/// let N: u32 = M;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let mut bytes = [0 as u8; M];\n/// for i in 0..M {\n/// bytes[i] = reader.read() as u8;\n/// }\n/// str::::from(bytes)\n/// }\n/// }\n/// ```\n#[derive_via(derive_deserialize)]\npub trait Deserialize {\n let N: u32;\n\n fn deserialize(fields: [Field; Self::N]) -> Self;\n\n fn stream_deserialize(reader: &mut Reader) -> Self;\n}\n\n/// Generates a `Deserialize` trait implementation for a given struct `s`.\n///\n/// # Arguments\n/// * `s` - The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A `Quoted` block containing the generated trait implementation\n///\n/// # Requirements\n/// Each struct member type must implement the `Deserialize` trait (it gets used in the generated code).\n///\n/// # Example\n/// For a struct like:\n/// ```\n/// struct MyStruct {\n/// x: AztecAddress,\n/// y: Field,\n/// }\n/// ```\n///\n/// This generates:\n/// ```\n/// impl Deserialize for MyStruct {\n/// let N: u32 = ::N + ::N;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// #[inline_always]\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let x = ::stream_deserialize(reader);\n/// let y = ::stream_deserialize(reader);\n/// Self { x, y }\n/// }\n/// }\n/// ```\npub comptime fn derive_deserialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n let params = nested_struct.0.fields(nested_struct.1);\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Deserialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_deserialize_clause = get_where_trait_clause(s, quote {Deserialize});\n\n // The following will give us:\n // ::N + ::N + ...\n // (or 0 if the struct has no members)\n let right_hand_side_of_definition_of_n = if params.len() > 0 {\n params\n .map(|(_, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n <$param_type as $crate::serialization::Deserialize>::N\n }\n })\n .join(quote {+})\n } else {\n quote {0}\n };\n\n // For structs containing a single member, we can enhance performance by directly deserializing the input array,\n // bypassing the need for loop-based array construction. While this optimization yields significant benefits in\n // Brillig where the loops are expected to not be optimized, it is not relevant in ACIR where the loops are\n // expected to be optimized away.\n let function_body = if params.len() > 1 {\n // This generates deserialization code for each struct member and concatenates them together.\n let deserialization_of_struct_members = params\n .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n let $param_name = <$param_type as Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote {});\n\n // We join the struct member names with a comma to be used in the `Self { ... }` syntax\n // This will give us e.g. `a, b, c` for a struct with three fields named `a`, `b`, and `c`.\n let struct_members = params\n .map(|(param_name, _, _): (Quoted, Type, Quoted)| quote { $param_name })\n .join(quote {,});\n\n quote {\n $deserialization_of_struct_members\n\n Self { $struct_members }\n }\n } else if params.len() == 1 {\n let param_name = params[0].0;\n quote {\n Self { $param_name: $crate::serialization::Deserialize::stream_deserialize(reader) }\n }\n } else {\n quote {\n Self {}\n }\n };\n\n quote {\n impl$generics_declarations $crate::serialization::Deserialize for $typ\n $where_deserialize_clause\n {\n let N: u32 = $right_hand_side_of_definition_of_n;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $function_body\n }\n }\n }\n}\n\n/// Generates a quoted expression that computes the total serialized length of function parameters.\n///\n/// # Parameters\n/// * `params` - An array of tuples where each tuple contains a quoted parameter name and its Type. The type needs\n/// to implement the Serialize trait.\n///\n/// # Returns\n/// A quoted expression that evaluates to:\n/// * `0` if there are no parameters\n/// * `(::N + ::N + ...)` for one or more parameters\ncomptime fn get_params_len_quote(params: [(Quoted, Type)]) -> Quoted {\n if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::serialization::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n }\n}\n\ncomptime fn get_generics_declarations(s: TypeDefinition) -> Quoted {\n let generics = s.generics();\n\n if generics.len() > 0 {\n let generics_declarations_items = generics\n .map(|(name, maybe_integer_typ)| {\n // The second item in the generics tuple is an Option of an integer type that is Some only if\n // the generic is numeric.\n if maybe_integer_typ.is_some() {\n // The generic is numeric, so we return a quote defined as e.g. \"let N: u32\"\n let integer_type = maybe_integer_typ.unwrap();\n quote {let $name: $integer_type}\n } else {\n // The generic is not numeric, so we return a quote containing the name of the generic (e.g. \"T\")\n quote {$name}\n }\n })\n .join(quote {,});\n quote {<$generics_declarations_items>}\n } else {\n // The struct doesn't have any generics defined, so we just return an empty quote.\n quote {}\n }\n}\n\ncomptime fn get_where_trait_clause(s: TypeDefinition, trait_name: Quoted) -> Quoted {\n let generics = s.generics();\n\n // The second item in the generics tuple is an Option of an integer type that is Some only if the generic is\n // numeric.\n let non_numeric_generics =\n generics.filter(|(_, maybe_integer_typ)| maybe_integer_typ.is_none());\n\n if non_numeric_generics.len() > 0 {\n let non_numeric_generics_declarations =\n non_numeric_generics.map(|(name, _)| quote {$name: $trait_name}).join(quote {,});\n quote {where $non_numeric_generics_declarations}\n } else {\n // There are no non-numeric generics, so we return an empty quote.\n quote {}\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/serialization.nr","function_locations":[{"start":3018,"name":"derive_serialize"},{"start":7206,"name":"derive_deserialize"},{"start":10928,"name":"get_params_len_quote"},{"start":11387,"name":"get_generics_declarations"},{"start":12469,"name":"get_where_trait_clause"}]},"414":{"source":"use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};\nuse std::embedded_curve_ops::EmbeddedCurvePoint;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\nglobal BOOL_SERIALIZED_LEN: u32 = 1;\nglobal U8_SERIALIZED_LEN: u32 = 1;\nglobal U16_SERIALIZED_LEN: u32 = 1;\nglobal U32_SERIALIZED_LEN: u32 = 1;\nglobal U64_SERIALIZED_LEN: u32 = 1;\nglobal U128_SERIALIZED_LEN: u32 = 1;\nglobal FIELD_SERIALIZED_LEN: u32 = 1;\nglobal I8_SERIALIZED_LEN: u32 = 1;\nglobal I16_SERIALIZED_LEN: u32 = 1;\nglobal I32_SERIALIZED_LEN: u32 = 1;\nglobal I64_SERIALIZED_LEN: u32 = 1;\n\nimpl Serialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> bool {\n reader.read() != 0\n }\n}\n\nimpl Serialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8\n }\n}\n\nimpl Serialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16\n }\n}\n\nimpl Serialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32\n }\n}\n\nimpl Serialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64\n }\n}\n\nimpl Serialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u128\n }\n}\n\nimpl Serialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self);\n }\n}\n\nimpl Deserialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read()\n }\n}\n\nimpl Serialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u8 as Field);\n }\n}\n\nimpl Deserialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8 as i8\n }\n}\n\nimpl Serialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u16 as Field);\n }\n}\n\nimpl Deserialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16 as i16\n }\n}\n\nimpl Serialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u32 as Field);\n }\n}\n\nimpl Deserialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32 as i32\n }\n}\n\nimpl Serialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u64 as Field);\n }\n}\n\nimpl Deserialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64 as i64\n }\n}\n\nimpl Serialize for [T; M]\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n for i in 0..M {\n self[i].stream_serialize(writer);\n }\n }\n}\n\nimpl Deserialize for [T; M]\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut result: [T; M] = std::mem::zeroed();\n for i in 0..M {\n result[i] = T::stream_deserialize(reader);\n }\n result\n }\n}\n\nimpl Serialize for Option\nwhere\n T: Serialize,\n{\n let N: u32 = ::N + 1;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write_bool(self.is_some());\n if self.is_some() {\n self.unwrap_unchecked().stream_serialize(writer);\n } else {\n writer.advance_offset(::N);\n }\n }\n}\n\nimpl Deserialize for Option\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n if reader.read_bool() {\n Option::some(::stream_deserialize(reader))\n } else {\n reader.advance_offset(::N);\n Option::none()\n }\n }\n}\n\nglobal SCALAR_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurveScalar {\n\n let N: u32 = SCALAR_SIZE;\n\n fn serialize(self) -> [Field; SCALAR_SIZE] {\n [self.lo, self.hi]\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.lo);\n writer.write(self.hi);\n }\n}\n\nimpl Deserialize for EmbeddedCurveScalar {\n let N: u32 = SCALAR_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { lo: fields[0], hi: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { lo: reader.read(), hi: reader.read() }\n }\n}\n\nglobal POINT_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn serialize(self) -> [Field; Self::N] {\n [self.x, self.y]\n }\n\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.x);\n writer.write(self.y);\n }\n}\n\nimpl Deserialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { x: fields[0], y: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { x: reader.read(), y: reader.read() }\n }\n}\n\nimpl Deserialize for str {\n let N: u32 = M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);\n str::::from(u8_arr)\n }\n}\n\nimpl Serialize for str {\n let N: u32 = M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.as_bytes().stream_serialize(writer);\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Deserialize for BoundedVec\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut new_bounded_vec: BoundedVec = BoundedVec::new();\n let payload_len = Self::N - 1;\n\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n let len = reader.peek_offset(payload_len) as u32;\n\n for i in 0..M {\n if i < len {\n new_bounded_vec.push(::stream_deserialize(reader));\n }\n }\n\n // +1 for the length of the BoundedVec\n reader.advance_offset((M - len) * ::N + 1);\n\n new_bounded_vec\n }\n}\n\n// This may cause issues if used as program input, because noir disallows empty arrays for program input.\n// I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint\n// if someone does run into this in the future.\nimpl Deserialize for () {\n let N: u32 = 0;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(_reader: &mut Reader) -> Self {\n ()\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Serialize for BoundedVec\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M + 1; // +1 for the length of the BoundedVec\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.storage().stream_serialize(writer);\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n writer.write_u32(self.len() as u32);\n }\n}\n\n// Create a slice of the given length with each element made from `f(i)` where `i` is the current index\ncomptime fn make_slice(length: u32, f: fn[Env](u32) -> T) -> [T] {\n let mut slice = @[];\n for i in 0..length {\n slice = slice.push_back(f(i));\n }\n slice\n}\n\n// Implements Serialize and Deserialize for an arbitrary tuple type\ncomptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {\n // `T0`, `T1`, `T2`\n let type_names = make_slice(length, |i| f\"T{i}\".quoted_contents());\n\n // `result0`, `result1`, `result2`\n let result_names = make_slice(length, |i| f\"result{i}\".quoted_contents());\n\n // `T0, T1, T2`\n let field_generics = type_names.join(quote [,]);\n\n // `::N + ::N + ::N`\n let full_size_serialize = type_names\n .map(|type_name| quote {\n <$type_name as Serialize>::N\n })\n .join(quote [+]);\n\n // `::N + ::N + ::N`\n let full_size_deserialize = type_names\n .map(|type_name| quote {\n <$type_name as Deserialize>::N\n })\n .join(quote [+]);\n\n // `T0: Serialize, T1: Serialize, T2: Serialize,`\n let serialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Serialize,\n })\n .join(quote []);\n\n // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`\n let deserialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Deserialize,\n })\n .join(quote []);\n\n // Statements to serialize each field\n let serialized_fields = type_names\n .mapi(|i, _type_name| quote {\n $crate::serialization::Serialize::stream_serialize(self.$i, writer);\n })\n .join(quote []);\n\n // Statements to deserialize each field\n let deserialized_fields = type_names\n .mapi(|i, type_name| {\n let result_name = result_names[i];\n quote {\n let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote []);\n let deserialize_results = result_names.join(quote [,]);\n\n quote {\n impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {\n let N: u32 = $full_size_serialize;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n\n $serialized_fields\n }\n }\n\n impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {\n let N: u32 = $full_size_deserialize;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n \n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $deserialized_fields\n ($deserialize_results)\n }\n }\n }\n}\n\n// Keeping these manual impls. They are more efficient since they do not\n// require copying sub-arrays from any serialized arrays.\nimpl Serialize for (T1,)\nwhere\n T1: Serialize,\n{\n let N: u32 = ::N;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: crate::writer::Writer = crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.0.stream_serialize(writer);\n }\n}\n\nimpl Deserialize for (T1,)\nwhere\n T1: Deserialize,\n{\n let N: u32 = ::N;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n (::stream_deserialize(reader),)\n }\n}\n\n#[impl_serialize_for_tuple(2)]\n#[impl_serialize_for_tuple(3)]\n#[impl_serialize_for_tuple(4)]\n#[impl_serialize_for_tuple(5)]\n#[impl_serialize_for_tuple(6)]\nmod impls {\n use crate::serialization::{Deserialize, Serialize};\n}\n\n#[test]\nunconstrained fn bounded_vec_serialization() {\n // Test empty BoundedVec\n let empty_vec: BoundedVec = BoundedVec::from_array([]);\n let serialized = empty_vec.serialize();\n let deserialized = BoundedVec::::deserialize(serialized);\n assert_eq(empty_vec, deserialized);\n assert_eq(deserialized.len(), 0);\n\n // Test partially filled BoundedVec\n let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);\n let serialized = partial_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(partial_vec, deserialized);\n assert_eq(deserialized.len(), 1);\n assert_eq(deserialized.get(0), [1, 2]);\n\n // Test full BoundedVec\n let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);\n let serialized = full_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(full_vec, deserialized);\n assert_eq(deserialized.len(), 3);\n assert_eq(deserialized.get(0), [1, 2]);\n assert_eq(deserialized.get(1), [3, 4]);\n assert_eq(deserialized.get(2), [5, 6]);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/type_impls.nr","function_locations":[{"start":693,"name":"::serialize"},{"start":914,"name":"::stream_serialize"},{"start":1082,"name":"::deserialize"},{"start":1328,"name":"::stream_deserialize"},{"start":1470,"name":"::serialize"},{"start":1691,"name":"::stream_serialize"},{"start":1855,"name":"::deserialize"},{"start":2101,"name":"::stream_deserialize"},{"start":2246,"name":"::serialize"},{"start":2467,"name":"::stream_serialize"},{"start":2633,"name":"::deserialize"},{"start":2879,"name":"::stream_deserialize"},{"start":3025,"name":"::serialize"},{"start":3246,"name":"::stream_serialize"},{"start":3412,"name":"::deserialize"},{"start":3658,"name":"::stream_deserialize"},{"start":3804,"name":"::serialize"},{"start":4025,"name":"::stream_serialize"},{"start":4191,"name":"::deserialize"},{"start":4437,"name":"::stream_deserialize"},{"start":4585,"name":"::serialize"},{"start":4806,"name":"::stream_serialize"},{"start":4974,"name":"::deserialize"},{"start":5220,"name":"::stream_deserialize"},{"start":5371,"name":"::serialize"},{"start":5592,"name":"::stream_serialize"},{"start":5753,"name":"::deserialize"},{"start":5999,"name":"::stream_deserialize"},{"start":6136,"name":"::serialize"},{"start":6357,"name":"::stream_serialize"},{"start":6527,"name":"::deserialize"},{"start":6773,"name":"::stream_deserialize"},{"start":6924,"name":"::serialize"},{"start":7145,"name":"::stream_serialize"},{"start":7318,"name":"::deserialize"},{"start":7564,"name":"::stream_deserialize"},{"start":7717,"name":"::serialize"},{"start":7938,"name":"::stream_serialize"},{"start":8111,"name":"::deserialize"},{"start":8357,"name":"::stream_deserialize"},{"start":8510,"name":"::serialize"},{"start":8731,"name":"::stream_serialize"},{"start":8904,"name":"::deserialize"},{"start":9150,"name":"::stream_deserialize"},{"start":9350,"name":"::serialize"},{"start":9571,"name":"::stream_serialize"},{"start":9831,"name":"::deserialize"},{"start":10077,"name":"::stream_deserialize"},{"start":10389,"name":">::serialize"},{"start":10610,"name":">::stream_serialize"},{"start":10997,"name":">::deserialize"},{"start":11243,"name":">::stream_deserialize"},{"start":11621,"name":"::serialize"},{"start":11744,"name":"::stream_serialize"},{"start":11944,"name":"::deserialize"},{"start":12090,"name":"::stream_deserialize"},{"start":12297,"name":"::serialize"},{"start":12397,"name":"::stream_serialize"},{"start":12593,"name":"::deserialize"},{"start":12737,"name":"::stream_deserialize"},{"start":12916,"name":">::deserialize"},{"start":13162,"name":">::stream_deserialize"},{"start":13395,"name":">::serialize"},{"start":13616,"name":">::stream_serialize"},{"start":13997,"name":">::deserialize"},{"start":14243,"name":">::stream_deserialize"},{"start":15299,"name":"::deserialize"},{"start":15546,"name":"::stream_deserialize"},{"start":15911,"name":">::serialize"},{"start":16132,"name":">::stream_serialize"},{"start":16617,"name":"make_slice"},{"start":16867,"name":"impl_serialize_for_tuple"},{"start":20158,"name":"::serialize"},{"start":20409,"name":"::stream_serialize"},{"start":20616,"name":"::deserialize"},{"start":20877,"name":"::stream_deserialize"},{"start":21226,"name":"bounded_vec_serialization"}]},"415":{"source":"pub struct Writer {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Writer {\n pub fn new() -> Self {\n Self { data: [0; N], offset: 0 }\n }\n\n pub fn write(&mut self, value: Field) {\n self.data[self.offset] = value;\n self.offset += 1;\n }\n\n pub fn write_u32(&mut self, value: u32) {\n self.write(value as Field);\n }\n\n pub fn write_u64(&mut self, value: u64) {\n self.write(value as Field);\n }\n\n pub fn write_bool(&mut self, value: bool) {\n self.write(value as Field);\n }\n\n pub fn write_array(&mut self, value: [Field; K]) {\n for i in 0..K {\n self.data[i + self.offset] = value[i];\n }\n self.offset += K;\n }\n\n pub fn write_struct(&mut self, value: T, serialize: fn(T) -> [Field; K]) {\n self.write_array(serialize(value));\n }\n\n pub fn write_struct_array(\n &mut self,\n value: [T; C],\n serialize: fn(T) -> [Field; K],\n ) {\n for i in 0..C {\n self.write_struct(value[i], serialize);\n }\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) -> [Field; N] {\n assert_eq(self.offset, self.data.len(), \"Writer did not write all data\");\n self.data\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/writer.nr","function_locations":[{"start":128,"name":"Writer::new"},{"start":220,"name":"Writer::write"},{"start":339,"name":"Writer::write_u32"},{"start":428,"name":"Writer::write_u64"},{"start":519,"name":"Writer::write_bool"},{"start":629,"name":"Writer::write_array"},{"start":841,"name":"Writer::write_struct"},{"start":1040,"name":"Writer::write_struct_array"},{"start":1185,"name":"Writer::advance_offset"},{"start":1263,"name":"Writer::finish"}]}}} \ No newline at end of file diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak b/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak new file mode 100644 index 000000000000..9f3fdb1d7f9a --- /dev/null +++ b/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak @@ -0,0 +1 @@ +{"noir_version":"1.0.0-beta.19+842974fcf034b0a652631e69fc24f92f9ddd1d37","name":"AuthorizeOnceBeforeExternal","functions":[{"name":"__aztec_nr_internals__foo","hash":"4876275608018138592","is_unconstrained":true,"custom_attributes":["abi_public"],"abi":{"parameters":[{"name":"from","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"},{"name":"authwit_nonce","type":{"kind":"field"},"visibility":"private"}],"return_type":null,"error_types":{"26387131971136782":{"error_kind":"string","string":"Invalid response from registry"},"7136484461999155778":{"error_kind":"string","string":"Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"},"8502498164115016271":{"error_kind":"string","string":"semantic length returned from oracle does not match data"},"9894212961085021188":{"error_kind":"string","string":"Message not authorized by account"}}},"bytecode":"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","debug_symbols":"tZnRTmM5DIbfpddcJLbjJLzKCKECZVSpKqgDK60Q7742x05apGShZW74/7acr45jJzmnb6uHzd3r79vt/vHpz+r619vq7rDd7ba/b3dP9+uX7dNe3n1bBf0T6+oar1YgL7JIXF3HKAqi+jaakr2fTFk0iWbTYloXxWCqPOGiXA9yHcr1IDxk02zvF1O5HuQ6CqbRFEwlHiiiZJpM2TSbFtO6aAqmyquiYCo8lO9NZCo8lO9JbJpNi2ldlINpNBUeCo/RlEyTqfBIxsvZtJjWRXMwjaZgiqZkmkyNl42XjZeNV4xXlCfxFTBFUzJNpmyaTZXHonXRKrwEotEUTNGUTJMpm2bTYloXjSG4iW7ADbohN0olNewmuyluqpkY3EQ3Sk5q0I2SWU3yd9hNdlPcVDPaI4tRclEDbtANuUlu2E12o+SqpprRdmFUE92AG3RDbpIbdpPdFDfVDDmZnKytxDoK7aXFKDmrUbLGo+2Uo5rspripZrSlFhPdgBt0Q26SGycnJycnJyezk9nJ7GR2MjuZncxOZiezk9nJ2lY5qEE35EY5mh9trcVkN8VNNaNtlbW0tK8Wg24UqFnV1lqMArXYtLkWU8xoW2XNvPbVYsCNAvP7+9XK1+zbl8Nmo0v20SIuS/vz+rDZv6yu96+73dXqn/Xu9eOf/jyv9x/6sj7IpzLEzf5BVICP291G3ftVvzqMLwUMya4GhNQA0jMniDhBBNJGXhiBmBuEywkDJoxcnFCpB5Hxy+Pgwk7IpQzHQWMEEnkqkLinIsMJIf1AJvgvZiIhegwJKR9l4hRRxgiSdc0QJN09ykSdjEIua+OQ5SCOMhHDbEKqzwePUzGPoleFLC9lGMWkNAlCz0VthHRWMo/G8SmZcVKZNXphVuhjoPjVksAQe0lgHJZE5AvTMCvLoEewJQaKkxgmqYylFi8JWV7lyhbGp2T+RGnCxaUZf6I24dLa/EZGAUYZhUvLcxpFDW3pFc9xGMVs4QRqkyI+4zCheQKh2hZwaZXhzM4DSdrMFkiCOgxkPpqSOgTDCIKzKk25VWmPAgp/Z2YKtZmRs/poZhCmZwzqh4ww7jjEWb9AY8ihbbjBI10+u/M4OgNO1tJPccwmV06vjQF9iy6nLYOTQq3A0Jqu9jAwnTY/TiaXQ1sIOXAPA78eRT89ViQYRkGTIpXeR2eEGsaMOFuOHYFHZz/gT2e/WY3G3FfjQucxALFNK0/imJRoim3tSHLz1curfDkMrNl3WrF1GMb/7AvtJCt9H4d9T7PFFELpK7LcZQ4h5QdKrF5eYilcWmIpXl5iU8YXSyzhxSU2DSNB7QtpPm8oiWJjMJ7FwNqGgpXGpZ7yX03Hj3RcjRB7xx3d+31qFg4zSG3bNQQ59Q8hk9HIUyD0QhU/PkgxzPYWgra3HN1C4nfCqH66lXnJwxMQz3b8cHTITuMdfxpI6nut+DI8vvBsy+fcji9c+cxAENthLGEaP14os+cL/RFFzmcHEsNRIHkUSJ49sSncMiKnzDMDobYeip8EMtsvCdoxWZ7fjAOZDUZundqKGODoscs3ulcurC0lAceH7W9AgEeQCYOwLUWER433ca9+Iy/X99vDyc9N7wo7bNd3u429fHzd3x99+vLvs3/iP1c9H57uNw+vh42S+m9W8udXrHwlB4YbfUAvL6V15WW+eddv/w8="},{"name":"offchain_receive","hash":"6201884033566737539","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]},"visibility":"private"}],"return_type":null,"error_types":{"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"}}},"bytecode":"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","debug_symbols":"tZndbhs5DEbfxde5EKkfinmVoCjc1CkMGE7gJgssgrz7khl9sr2FBNdub6qTxnNMcShKk3lffd98e/vxdbt/ev65un94X307bHe77Y+vu+fH9ev2eW//+74K/k/hurqPdzbq6r7YGEMbqY3cxtjG1MbcxtJGaWNtY/Ol5kvNl5ov2+fExmL/rz5yG81P5JAB9g3kIRYBVIA2kAAgAAMiIAEyAGaBWWAWmCvMFeYKc4W5wlxhrjBXmCvMFWaFWWFWmBVmhVmbWYJflR0IwAD/THEoAAHYt3Nw0AYUAARgQATYt7NfThlQAAJwszhoAw4AN6uDmaMHzxGQABlQAAKoAG3gtbkAAWCOMEeYvUCjp8UrdAEBuLk6aAOv0gXs8uRzT/bhxA724ZQctEEOAAsjuTAzIAISIAMKQABu9hxmbVACgABu9hyWCEgAM2cP1RfIAgKoAG3gC2QBApg5k0MEJEAGuNmT6QtkgQpwsyfBF8gCBGBABCRABrjZk+ALZIEK0Aa+QLInwRdI9rvjC2SBCHCzZ8MXyAIFIIAK0AWqL6IFvCsFBwZEQAJ4p2OHAhCAN7vooA18WZXkQAAGRICbq4OZxb/Cl9UCAqgAbeDLagECmFnIIQLMLB6GL6sFCsDN/u2+rBbQBr6sFiAAAyLAzdkhAwpAAG4uDtrAl9UCBPCrxEEAFWBXVZ+Xr68FCGDxVJ+gr68FEiADCkAAFeBmv1++vhYgAAN8pvXj426FTfLr62Gz8T3yZNe0vfRlfdjsX1f3+7fd7m71z3r39vmhny/r/ef4uj7Yby3qzf67jSZ82u42Th93x6vD+FIKtum2y42LdgWFcwmNJcmb86ciJekCOb+ex9fHjBlEy0oPQPQ3ZqG1z8La13AWaSzJuWpz5BLKUZHjmSKPFVwYyWQ7fHRFuTiGIqXHoDyMYaKww1RsCjsnhaGijhW2pzeDnApELp6G9Biy7brDGGhyTyMTbkfkmAe5nBu011UMdWSYFGYihiFR1Cvup20nSIT17XEiJg7189anQvk4iUQXx6B9Elk1XFVTIUBRAo0VJJM1qgVVRSqpO/L5KqdJXZJQ71V2ShgqdJZMBKH1tNWUyw2aeqehPFTwpF8yJziY8/CeMs86Hh/bdqZxGHFSGLU7sm1bJ2HwuWNeGdorg8PYMeuaKfemebypKVxZGDouDJndk0j9nqQ4UvAkipJzz0XWdFUUVARRWB8fKeKk66XcN2MZ10WcbedUuHc9Pb2n53tpnNVn7jckxxNDvDwK7pWV+GSx/xLFpDqJK/YhikTjOCaOaA9u2EVqqOM4yiSOQqnno1BOw3USJ8URUw/kbLXGa+OQOI5j1gGzIqt6Wue/OKaRxGMfLYnGnSNNaiSW48ExDTMyNVyU0zTpoilEtK8UkoznMXFwxDw481VRcO09tJarauPSOk8yO76GvqNYqY1zUf9APuvN+ax/M5+X5iLz7bmYOS7LxdRwcy4s+NrnUeiqjnFxLuTvOi7Mp9ycz+neqH0ecbJWC/2BvXF21pD+xJzC+DQ9zWbFcYXtllx1ZkrUT9P55Cj8P0XJt56Zyqx7BsVqt2SO99Uy29+5HJ94K1/p6FMxXR079NYKn+bzorqYPVZwRsMoXMbPzTJpW/aiBamwNyxx8PA+NVTGadxeu+hVBunzqHLFHxDsVVl/pohh/OQ9Pa+VfpLWQuW6M9+pI47rW+rtO6Lo7R1cbq7vqWHcwb/Yj+vH7eHs9eeHqw7b9bfdpv349LZ/PPnt678v+A1en74cnh83398OGzcd36HaPw/V/kpelb/crezvyA92jr8rLPaTvwZ4qFYwGujLh8fyHw=="},{"name":"public_dispatch","hash":"15893691869641264666","is_unconstrained":true,"custom_attributes":["abi_public"],"abi":{"parameters":[{"name":"selector","type":{"kind":"field"},"visibility":"private"}],"return_type":null,"error_types":{"26387131971136782":{"error_kind":"string","string":"Invalid response from registry"},"7136484461999155778":{"error_kind":"string","string":"Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"},"8502498164115016271":{"error_kind":"string","string":"semantic length returned from oracle does not match data"},"9894212961085021188":{"error_kind":"string","string":"Message not authorized by account"},"11194752367584870169":{"error_kind":"fmtstring","length":27,"item_types":[{"kind":"field"}]}}},"bytecode":"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","debug_symbols":"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"},{"name":"sync_state","hash":"7288454187967671611","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"return_type":null,"error_types":{"361444214588792908":{"error_kind":"string","string":"attempt to multiply with overflow"},"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"1064022259863234536":{"error_kind":"fmtstring","length":101,"item_types":[{"kind":"integer","sign":"unsigned","width":32}]},"1998584279744703196":{"error_kind":"string","string":"attempt to subtract with overflow"},"5421095327929394772":{"error_kind":"string","string":"attempt to bit-shift with overflow"},"5449178635769758673":{"error_kind":"fmtstring","length":61,"item_types":[{"kind":"field"},{"kind":"field"}]},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"9791669845391776238":{"error_kind":"string","string":"0 has a square root; you cannot claim it is not square"},"9885968605480832328":{"error_kind":"string","string":"Attempted to read past the length of a CapsuleArray"},"10791800398362570014":{"error_kind":"string","string":"extend_from_bounded_vec out of bounds"},"10835969307644359280":{"error_kind":"fmtstring","length":40,"item_types":[]},"11021520179822076911":{"error_kind":"string","string":"Attempted to delete past the length of a CapsuleArray"},"12820178569648940736":{"error_kind":"fmtstring","length":48,"item_types":[{"kind":"field"},{"kind":"field"}]},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"},"17110599087403377004":{"error_kind":"fmtstring","length":98,"item_types":[]},"17655676068928457687":{"error_kind":"string","string":"Reader did not read all data"}}},"bytecode":"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","debug_symbols":"vP3NkuW8jqUJ38sZ12CTAAiibqUHZdXd2W1plpbVVj/fpKzu/dsCxbUQEe10hbufnuT74GQ4FkRpUZSELf3Pf/yf//K//4//+z/967//X//lv/3jP/5v//Mf//t//dd/+7d//b//07/9l//jP//3f/0v//7+X//nP17X/1H9x3+U//APtX/8R3v/Z6z/+PrPXP+J/I+91n/a+k9f/5H1H13/WVlsZbGVxVYWW1nGyjJWlrGyjJVlrCxjZRkry1hZxsoyVhZfWXxl8ZXFVxZfWXxl8ZXFVxZfWXxlmSvLXFnmyjJXlrmyzJVlrixzZZkry1xZYmWJlSVWllhZYmWJlSVWllhZYmWJlaW9Xvd/2/3ffv9X7v/q/V+7/zvu//r933n/987X7nztztfufO3O1+587c7X7nztztfufO3O1+98/c7X73z9ztfvfP3O1+98/c7X73z9zid3PrnzyZ1P7nxy55M7n9z55M4ndz658+mdT+98eufTO5/e+e4jvd2HeruP9XYf7O0+2tt9uLf7eG/3Ad/uI77dh3y7j/l2HfR+/dfv/877v7H+ex34rV3QNvQN75RNLnjnbOOCd9I+LxgbfMPcEDdcZljQNvQNskE37My+M/vO7Duz78xzZ54789yZ5848d+a5M8+dee7Mc2eeO3PszLEzx84cO3PszLEzx84cO3PszHFn7q/Xhrahb5ANusE2jA2+YW7YmdvO3HbmtjO3nbntzG1nbjtz25nbztx25r4z952578x9Z+47c9+Z+87cd+a+M/edWXZm2ZllZ5adWXZm2ZllZ5adWXZm2Zl1Z9adWXdm3Zl1Z9adWXdm3Zl1Z9ad2XZm25ltZ7ad2XZm25ltZ7ad2XZm25nHzjx25rEzj5157Mzbg317sG8P9u3Bvj3Ytwf79mDfHuzbg317sG8P9u3Bvj3Ytwf79mDfHuzbg317sG8P9u3Bvj3Ytwf79mDfHuzbg317sG8P9u3Bvj3Ytwf79mDfHuzbg317sG8PyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD8r2oGwPyvagbA/K9qBsD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/q9qBuD+r2oG4P6vagbg/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0P2vagbQ/a9qBtD9r2oG0Pju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPju3BsT04tgfH9uDYHhzbg2N7cGwPjsuD0i9oG/oG2aAbbMPY4BvmhrghdubYmWNnjp05dubYmWNnjp05dua4M/vrtaFt6Btkg26wDWODb5gbdua2M7edue3MbWduO3PbmdvO3HbmtjO3nbnvzH1n7jtz35n7ztx35r4z952578x9Z5adWXZm2ZllZ5adWXZm2ZllZ5adWXZm3Zl1Z9adWXdm3Zl1Z9adWXdm3Zl1Z7ad2XZm25ltZ7ad2XZm25ltZ7ad2XbmsTOPnXnszGNnHjvz2JnHzjx25rEzj53Zd2bfmX1n9p3Zd2bfmX1n9p3Zd2bfmbcHfXvQtwd9e9C3B3170LcHfXvQtwd9e9C3B3170LcHfXvQtwd9e9C3B3170LcHfXtwbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B+f24NwenNuDc3twbg/O7cG5PTi3B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgdjezC2B2N7MLYHY3swtgffz9lfoAbqIAEpyEAD5KAJgkaDRoNGg0aDRoNGg0aDRoNGg0aDRodGh0aHRodGh0aHRodGh0aHRoeGQEOgIdAQaAg0BBoCDYGGQEOgodBQaCg0FBoKDYWGQkOhodBQaBg0DBoGDYOGQcOgYdAwaBg0DBoDGgMaAxoDGgMaAxoDGgMaAxoDGg4Nh4ZDw6Hh0HBoODQcGg4Nh8aExoTGhMaExoTGhMaExoTGhMaERkAjoBHQCGgENAIaAY2ARkADPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafZ6ePaJKCDDRADpqguCkbfm5qoA4SkIIMNEAOmiBoNGg0aDRoNGg0aDRoNGg0aDRoNGh0aHRodGh0aHRodGh0aHRodGh0aAg0BBoCDYGGQEOgIdAQaAg0BBoKDYWGQkOhodBQaCg0FBoKDYWGQcOgYdAwaBg0DBoGDYOGQcOgMaAxoDGgMaAxoDGgMaAxoDGgMaDh0HBoODQcGg4Nh4ZDw6Hh0HBoTGhMaExoTGhMaExoTGhMaExoTGgENAIaAQ34vMPnHT7v8HmHzzt83uFzgc8FPhf4XOBzgc8FPhf4XOBzgc8FPhf4XOBzgc8FPhf4XOBzgc8FPhf4XOBzgc8FPhf4XOBzgc8FPhf4PPuNZCRNUGxKny9qoA4SkIIMNEDQEGgINBQaCg2FhkJDoaHQUGgoNBQaCg2DhkHDoGHQMGgYNAwaBg2DhkFjQGNAY0BjQGNAY0BjQGNAY0BjQMOh4dBwaDg0HBoODYeGQ8Oh4dCY0JjQmNCY0JjQmNCY0JjQmNCY0AhoBDQCGgGNgEZAI6AR0AhoxNbIxqWbGqiDBKQgAw2QgyYIGg0aDRoNGg0aDRoNGg0aDRoNGg0aHRodGh0aHRodGh0aHRrwucLnCp9nW5PMpAbqIAEpyEAD5KAJik0KDYWGQkOhodBQaCg0FBoKDYWGQcOgYdAwaBg0DBoGDYOGQcOgMaAxoDGgMaAxoDGgMaAxoDGgMaDh0HBoODQcGg4Nh4ZDw6Hh0HBoTGhMaExoTGhMaExoTGhMaExoTGgENAIaAY2ARkAjoBHQCGgENGJrZHPUTQ3UQQJSkIEGyEETBI0GjQaNBo0GjQaNBo0GjQaNBo0GjQ6NDo0OjQ6NDo0OjQ6NDo0OjQ4N+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPDT43+Nzgc4PPs9NKJWmCYtPl85saqIMEpCADDRA0JjQmNAIal881f8d0+fwmASnIQAPkoAmKm7IB66YG6iABKchAA+SgCYJGg0aDRoNGg0aDRoNGg0aDRoNGg0aHRodGh0aHRodGh0aHRodGh0aHhkBDoCHQEGgINAQaAg2BhkBDoKHQUGgoNBQaCg2FhkJDoaHQUGgYNAwaBg2DhkHDoGHQMGgYNAwaAxoDGgMaAxoDGgMaAxoDGgMaAxoODYeGQ8Oh4dBwaDg0HBoODYfGhMaExoTGhMaExoTGhMaExoTGhEZAAz4f8PmAzwd8PuDzAZ8P+HzA5wM+d/jc4XOHzx0+d/jc4XOHzx0+d/jc4XOHzx0+d/jc4XOHzx0+d/jc4XOHzx0+d/jc4XOHzx0+d/jc4XOHzx0+d/jc4fNsAVNPaqAOEpCCDDRADpqg2KTQUGgoNBQaCg2FhkJDoaHQUGgYNAwaBg2DhkHDoGHQMGgYNAwaAxoDGgMaAxoDGgMaAxoDGgMaAxoODYeGQ8Oh4dBwaDg0HBoODYfGhMaExoTGhMaExoTGhMaExoTGhEZAI6AR0AhoBDQCGgGNgEZAI7ZGNpLd1EAdJCAFGWiAHDRB0GjQaNBo0GjQaNBo0GjQaNBo0GjQ6NDo0OjQ6NDo0OjQ6NDo0OjQ6NCAzyd8PuHzCZ9P+HzC5xM+n/D5hM8nfD7h8wmfT/h8wucTPp/w+YTPJ3w+4fMJn0/4fMLnEz6f8PmEzyd8PuHzCZ9P+HzC5xM+n/D5hM8nfD7h8wmfT/h8wucTPp/w+YTPJ3w+4fMJn0/4fMLnEz6f8PmEzyd8PuHzCZ9P+HzC5xM+n/D5hM8nfD7h8wmfT/h8wucTPp/w+YTPJ3w+4fMJn0/4fMLnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7wecDnAZ8HfB7weWyf99f2eX9tn/fX9nl/bZ/31/Z5f22f99f2ec9+OI2kCYpN6fNFDdRBAlKQgQYIGg0aDRodGh0aHRodGh0aHRodGh0aHRodGgINgYZAQ6Ah0BBoCDQEGgINgYZCQ6Gh0FBoKDQUGgoNhYZCQ6Fh0DBoGDQMGgYNg4ZBw6Bh0DBoDGgMaAxoDGgMaAxoDGgMaAxoDGg4NBwaDg2HhkPDoeHQcGg4NBwaExoTGhMaExoTGhMaExoTGhMaExoBjYBGQCOgEdAIaAQ0AhoBjdga2Q93UwN1kIAUZKABctAEQQM+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmHzzt83uHzDp93+LzD5x0+7/B5h887fN7h8w6fd/i8w+cdPu/weYfPO3ze4fMOn3f4vMPnHT7v8HmHzzt83uHzDp93+LzD5x0+7/B5h887fN7h8w6fd/i8w+cdPu/weYfPO3ze4fMOn3f4vMPnHT7v8HmHzzt83uHzDp93+LzD5x0+7/B5h887fN7h8w6fd/i8w+cdPu/weYfPO3ze4fMOn3f4vMPnHT7v8Hn2w9krSUAKMtAAOWiCYlO+9XFRA0FjQmNCY0JjQmNCY0JjQiOgEdAIaAQ0AhoBjYBGQCOgEVsj++FuaqAOEpCCDDRADpogaDRoNGg0aDRoNGg0aDRoNGg0aDRodGh0aHRodGh0aHRodGh0aHRodGgINAQaAg2BhkBDoCHQEGgINAQaCg2FhkJDoaHQUGgoNBQaCg2FhkHDoGHQMGgYNPL1lJo0QA6aoNiUb2hd1EAdJCAFQWNAY0BjQGNAw6Hh0HBoODQcGg4Nh4ZDw6Hh0Eifj6QG6iABKchAA+SgCYpNAY2ARkAjoBHQCGgENAIaAY3YGtkPd1MDdZCAFGSgAXLQBEGjQaNBo0GjQaNBo0GjQaNBo0GjQaNDo0OjQ6NDo0OjQ6NDo0OjQ6NDQ6Ah0BBoCDQEGgINgYZAQ6Ah0FBoKDQUGgoNhYZCQ6Gh0FBoKDQMGgYNg4ZBw6Bh0DBoGDQMGgaNAY0BjQGNAY0BjQGNAY0BjQGNAQ2HhkPDoeHQcGg4NBwaDg2HhkMDPlf4XOFzhc8VPlf4XOFzhc8VPlf4XOFzhc8VPlf4XOFzhc8VPlf4XOFzhc8NPjf43OBzg88NPjf43OBzg88NPjf43OBzg88NPjf43OBzg88NPjf43OBzg88NPjf43OBzg88NPjf43ODz7IczT5qg2JQ+X9RAHSQgBRlogKAh0BBoKDQUGgoNhYZCQ6Gh0FBoKDQUGgYNg4ZBw6Bh0DBoGDQMGgYNg8aAxoDGgMaAxoDGgMaAxoDGgMaAhkPDoeHQcGg4NBwaDg2HhkPDoTGhMaExoTGhMaExoTGhMaExoTGhEdAIaAQ0AhoBjYBGQCOgEdCIrZH9cDc1UAcJSEEGGiAHTRA0GjQaNBo0GjQaNBo0GjQaNBo0GjQ6NDo0OjQ6NC6fj1eSgQbIQRMUmy6f39RAHSQgaAg0BBoCDYGGQEOhodBQaCg0FBoKDYWGQkOhodAwaBg0DBoGDYOGQcOgYdAwaBg0BjQGNAY0BjQGNAY0BjQGNAY0BjQcGg4Nh4ZDw6Hh0HBoODQcGg6NCY0JjQmNCY0JjQmNCY0JjQmNCY2ARkAjoBHQCGgENAIaAY2ARmyN7Ie7qYE6SEAKMtAAOWiCoNGg0aDRoNGg0aDRoNGg0aDRoNGg0aHRodGh0aEBnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOnzt87vC5w+cOn2c/3GhJA+SgCYpN6fNFDdRBAlIQNAIaAY2ARmyN7Ie7qYE6SEAKMtAAOWiCoNGg0aDRoNGg0aDRoNGg0aDRoNGg0aHRodGh0aHRodGh0aHRodGh0aEh0BBoCDQEGgINgYZAQ6Ah0BBoKDQUGgoNhYZCQ6Gh0FBoKDQUGgYNg4ZBw6Bh0DBoGDQMGgYNg8aAxoDGgMaAxoDGgEb6XJMcNEGxKX2+qIE6SEAKMhA0HBoODYfGhMaExoTGhMaExoTGhMaExoTGhEZAI6AR0AhoBDQCGgGNgEZAI7ZG9sPd1EAdJCAFGWiAHDRB0GjQaNBo0GjQaNBo0GjQaNBo0GjQ6NDo0OjQ6NDo0OjQ6NDo0OjQ6NAQaAg0BBoCDYGGQEOgIdAQaAg0FBoKDYWGQkOhodBQaCg0FBoKDYOGQcOgYdAwaBg0DBoGDYOGQWNAY0BjQGNAY0BjQAM+D/g84POAzwM+D/g84POAzwM+D/g84POAzwM+D/g84POAzwM+D/g84POAzwM+D/g84POAzwM+D/g84POAzwM+D/g84POAzwM+j+1zeW2fy2v7XF7b5/LaPpfX9rm8ts/ltX0ur+1zeW2fy+sFjQaN9PlM6iABKchAA+SgCYpN6fNF0OjQ6NDo0OjQ6NDo0OjQ6NAQaAg0BBoCDYGGQEOgIdAQaAg0FBoKDYWGQkOhodBQaCg0FBoKDYOGQcOgYdAwaBg0DBoGDYOGQWNAY0BjQGNAY0BjQGNAY0BjQGNAw6Hh0HBoODQcGg4Nh4ZDw6Hh0JjQmNCY0JjQmNCY0JjQmNCY0JjQCGgENAIaAY2ARkAjoBHQCGjE1sh+uJsaqIMEpCADDZCDJggaDRrweYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5g88bfN7g8wafN/i8wecNPm/weYPPG3ze4PMGnzf4vMHnDT5v8HmDzxt83uDzBp83+LzB5w0+b/B5h887fN7h8w6fd/i8w+cdPu/weYfPO3ze4fMOn2c/nL+SBKQgAw2QgyYoNl0+v6mBoNGh0aHRodGh0aHRodGhIdAQaAg0BBoCDYGGQEOgIdAQaCg0FBoKDYWGQkOhodBQaCg0FBoGDYOGQcOgYdAwaBg0DBoGDYPGgMaAxoDGgMaAxoDGgMaAxoDGgIZDw6Hh0HBoODQcGg4Nh4ZDw6ExoTGhMaExoTGhMaExoTGhMaExoRHQCGgENAIaAY2ARkDj8rl70gTFTdkPd1MDdZCAFGSgAXLQBEGjQaNBo0GjQaNBo0GjQaNBo0GjQaNDo0OjQ6NDo0OjQ6NDo0OjQ6NDQ6Ah0BBoCDQEGgINgYZAQ6Ah0FBoKDQUGgoNhYZCQ6Gh0FBoKDQMGgYNg4ZBw6Bh0DBoGDQMGgaNAY0BjQGNAY0BjQGNAY0BjQGNAQ2HhkPDoeHQcGg4NBwaDg2HhkNjQmNCY0JjQmNCY0JjQmNCY0JjQiOgEVsj+5v8OiNmL9NsSW/dKUlv3TmSFGSgAXLQBL11o1907aObGqiD3hqRatc+usk2XWMfmnT9u8x8jXNkzdc4RyQNkIMm6F3L+/LhwmvY3tcPifPCTHkN0nudf+E1ShsbsV+Y//aaEDcqcVyYY3rNeu/l/n+4PtT6IjZiJwpRiVeR3RMH0YmTmGrXcGQD0cZUi8ROFKISjTiITrzUJCu7ZsIbr6lwYyN2ohCVaMRBdCLVOtWEakI1oZpQTagmVBOqCdWEakI1pZpSTammVFOqKdWUako1pZpSzahmVDOqGdWMakY1o5pRzahmVBtUG1QbVBtUG1QbVBtUG1QbVBtUc6o51ZxqTjWnmlPNqeZUc6o51SbVJtUm1SbVJtUm1SbVJtUm1SbVgmpBtaBaThViiUo0YqqlycKJkxgbszVpYyNeatd7ayS7kzYq0YiXmo5EJ05gzg/XT4YlG42apkTOBNYSr39rknhVZvlnORPc2IidKEQlXpWNnjiITpzES22kcM4ENzbipZZ3bbPzaKMSjZhquZnp+bwkzLai9xV7ohCVeGXwVEt3ew5qWtpzg9LSC9PSNzZiSqRaWvpGJRpxEJ14qeXJOZuLbkxLz9y2NO/Mf5vmvdGIg+jESQxgmvfGRuxEqjnVnGpp3nglOvFSixzUNO/CNO+NV4ZcH2SHUMvFQLYI3ZjWu7ERr8pyuZBtQhuVaMSsLHdLWu/GSYyN2S3UcsmR7UIbOzHVIlGJRhxEjHp2DW3EqGff0MZG7EQhKtGIg0i1RrVGtfyc6euV2IidKETduzDbiDYOohMnMYCCfZzNRBs7cew9n91Ba8dme9DGRuxE7O5sEdpoxEHE7s42oY3c3WneG7m7jbs7zXsjd7dxdxt3d5p3YX6t9JWbmZ8gfWU5+RHSGztRiEo04rjQEp04iQHMTwO/PLEROzHVcoPyE8E3GnEQnTiJAczPBb9yi/ODwTd2ohBT4hrqbNBZo5P9Nmszs+FmYwDbi9iInSh747PtZqMRB9H3OGTrzcYALovMxEbsRCEq0YiD6HvjswlnYwDlRewYnfymb8vRya/6Lszv+t7YiJ0oRCUacRCdSDWlmlHNqGZUM6oZ1YxqRjWjmlHNqDaoNqg2qDaolp/2bddMkF0zGxsx/yx3QDrrRiUacRCdeBXZ8+BKZy1MZ93YiJdaz4MrnXWjEi+1njs2nXWjE1MthdNZeSGWnTQ9l5bZSrOxE4WoRCNeeSWLzI9wJ2b3zMZG7EQhKtGIg+jESaRao1qjWqNao1qjWqNao1qjWqNaGlJfiUq8MmhPHEQnTmIA05A3NmInClGJVBOqCdWEakI1pZpSTammVFOqKdXS0prjkJa+MdUsMYBp6RtTbSTmn0XiJF5/ltcB2RazsRE7UYhKNOIgOnESqeZUc6o51ZxqTjWnmlPNqeZUc6qlY9c4pPXWxqf1bmzEThSiErOG3C0xiE6cxKzhPV1ptrlsbMS9xZqdLhuVaMRBdOIkpppemIa8sRE7Ue8h0WxcyW3T7FzZ2IlCVKIR9zho9q9snMQACsdBOA5pvRs5DsJxEI6DcByE4yAcBwmgchyU46Ach7TejYYhMY6DcRyM42AcB+M45LnwRo6DcRyM47D8tpDjMDgOy28LOQ6D4zA4DoPjMDgOg+MAv+nLOQ7OcXCOw/LbwoEhmRyHyXGYHIfJcZgch+lEjsPkOATHIV14I8chOA7pwhs5DsFxCI5DcBwC49BeL2IjYhzaS4hKNKLvIcl+krVtrSnRiIPoxEnEOGRbycZG7ESMQ7aWbDQixqF1J04ix0E4DsJxkE7kOAjHQTgOy4ULJ4ZEOQ7KcVCOg3IclOOgATSOg3EcjOOQLryR42Ach3ThjRwH4zgYx2FwHAbHYXAccNbTNjgOg+MwOA7LhQsDQ+IcB+c4OMfBOQ7OcZgvIsdhchwmxyFdeCPHYXIc0oU3chwmxyE4DsFxCI5DcBxCiRyH4DgEx2G58MK+rGeJjdiJQkyJkWjEQXRiSszEAK4T4MJGvNSuH7doNolsVGC68Lo/qdn1sbET888kUYlGHEQnTmIA0283Mq8wb/pt5JCk32504iQGMM96NzZiJwpRiVRTqinVlGpKNaOaUc2oZlQzqhnVjGpGNaOaUW1QbVBtUG1QbVBtUG1QbVBtUG1QzanmVHOqOdWcak41p5pTzanmVJtUm1SbVJtUm1SbVJtUm1SbVJtUC6oF1YJqQbWgWlAtqBZUC6oF1LJdZGMjdqIQlWjEQXTiJFKtUa1RrVGtUa1RrVGtUa1RrVGtUa1TrVOtU61TrVOtU61TrVOtU61TTagmVBOqCdWEapxLhHOJcC4RziXCuUQ4lwjnEuFcIpxLhHOJcC4RziXCuUQ4lwjnEuFcIpxLhHOJcC4RziXCuUQ4lwjnEuFcIpxLhHOJcC4RziXCuUQ4lwjnEuFcIpxLZM0lMzGAay5ZmMk00YiDeCW7urA0e0s2BjCnihsbsROFqEQjDiLVJtUm1YJqQbWgWlAtqBZUC6oF1YJqAbV8A9PGRuxEISrRiIPoxEmkWqNao1qjWqNao1qjWqNao1qjWqNap1qnWqdap1qnWqdap1qnWqdap5pQTagmVBOqCdWEakI1oZpQTaimVFOqKdWUako1pZpSTammVFOqGdWMakY1o5pRzahmVDOqGdWMaoNqg2qDaoNqg2qDaoNqg2qDaoNqTjWnmlPNqeZUc6o51TiXKOcS5VyinEuUc4lyLlHOJcq5RDmXKOcS5VyinEuUc4lyLlHOJcq5RDmXKOcS5VyinEuUc4lyLlHOJca5xDiX2JpLNFGISky1kTiITky1mRjANZcsvNRmquVccmOqeaISjXipXS0Amu1aGyfxUpvXaSbbtTY2YicKUYlGHEQnTiLVhGpCtZw1Zg5Jzg8ztyLnhxsDmPPDjZkhEjtRiEo0YtbbEp04iZfa9axZswVrYyN2ohCVaMRBdOIkUm1QbVBtUG1QbVBtUG1QbVBtUG1QLeeHyCM154cbO1GImTd3Vno+cgek529sxE7MDHkop+dvNOIApqUj91CaN/JYT/PeaMRBdOIkvouU66GxZn+UXE2emv1RGztRiEo04iA6cRID2KiWXy+9HjtrvsZpoxBTbSYacRBTTRInMYD5GdP2SmzETrzUWpaTnzK90YiD6MRJDGB+0PTGRuxEqgnVhGpCNaGaUE2oplRTqinV8uumLcchP296oxEHMdUscRIDmB85vbEROzHVcr/lh05vNGKqjUQnTmIA83OnNzZiJwoxk+XxkF81vTGA+V3TGxuxEzNZJCrRiIPoxEkMYH7J+MYrWc/jLL9W3NNv+bniG504iQHMTxbfeJXec8fmR4tvFKISjTiIvjG7seR6Yq7ZjbVRiEo04iBeyWQlm8QAptFvvNREEjtRiJfa9QRasxtr4yCmWgqn0cUTU+0a6uzG2tiInShEBaZj8w5ytlVtvP5MZ6IQrz/T9WdGHMSryOsFxZoNVDemcfKucDZFbezESyLv3mZT1EYjDmJKZJFpnBsDmMaxHJ00zo2dKEQW6SzSWaSzSGeRziKdRTqLdBbpLNJZ5GSRk0VOFjlZ5GSRwSKDRQaLDBYZLDJYZLDIYJHBIgNF5huQVg3ZYbWxE4WIIrPDapWTHVYbOxFFZofVRiMOIorMDquNLLKzyM4iO4vsLLKzSGGRwiKFRQqLFBYpLFJYpLBIYZHCIpVFKotUFqksksaZNM6kcSaNM2mcSeNMGmfSOJPGmTTOpHEmjTNpnEnjTBpn0jjZQHWXQw9NemguD2UN9NCkhyY9NJeHshx6aNJDc3koa6CHJj006aHsmpJ8IDOXhxYOohNTIhIDuPy2sBEvieuFTJpdUxuVaMRLLR+y5GuINs6N2SoleTsvW6U2KvFKdrWRa7ZKbXTiJAYwXXhjI3aiEJVItUa1RrV0oWfp6cKF6cIbG7EThajEVNPEQbzU8jo226o2BjDNe2MjdqIQlWjESy0v5bKtamOq9cQApnlvbMTMm1uRjr1xEJ2YeXNv5npyYbr7xkbsRCFeanndkm8i2jiITpzEAKa7b2zEThQi1QbVBtVywZmXiNl3tTHVcotzJrixETND7uP0cV4t5guGNjZiJ2ZlI1GJRhzErGwmTmIA09I3vtU0rwDXx/duFKISjTiIfmFufH6y58a40dZH+G5MNU3sRCEq0YiD6MRJDGB+vudGqjWqNarlJ3yuBmFb3+S7cRCdmGqeGMD8kM+NjdiJQky1mWjEAcwv9lyty7Y+t3ddm9r63t6NRhzEq8irkdfWN/duDGB+pefGq8jrWs/Wd/duFKIS9+629e29G504sWOVu9u4u/ODPTemmiUKUYm5bTnU+dWeG52Y25YDlR/p6bnx+ZWeG4WoRCMOohMnMYD5tZ4bqeZUc6o5K8tPbi3Mb27dmBlyUPOrWzcKMevNccgPb904iE6cxADm17dubMROFCLVgmpBtTTvdYFn6yt6109lbX1G70YlGjEzRKITJzGAadMbr3qv/mpb39O78VK7rgttfVFvYfpNsrL0242dKEQlGnEQnTiJARSqCdWEaulCya1IF16N0ra+iKe5FelCzdFJF97YiFdl15WlrY/caSZLO1kmSztZJks7XU07tj50d6MQry22zJvGGevPJjGA6Zarz8bWl+pGjm/64nosautbdSPzpi9GbnH64sZG7EQhKtGIg+jESaTapNqk2qTapNqk2qTapNqk2qTapFpQLagWVAuqBdXSQyNHPT2UuD5Qdz2BtvU1uhGJqGx9j+5GJ04iKlvfpLuxETtRiEqkWqNao1qjWqNap1qnWqdap1qnWqdap1qnWqdap1qabI1ZmuzGgeFLD63hU1amrExZmbIyZWXKypSVKStTVqaszKhmVDOqGdWMakY1o5pRzahmVBtUG1QbVBtUy/PbGqiBo68vb+aYLRfmmNGFnS7sdGGnCztd2OnCThd2urDThZ0u7HRhpws7Xdjpwk4Xdrqw04WdLux0YacLO13Yg2pBtVycrtHJxWlitj+tgZLlwkhEZUIXCl0odKHQhUIXCl0odKHQhUIXCl0odKHQhUIXCl0odKHQhUIXCl0odKHQhUIXynJhDgldmM1L9+jkmWyNjrAyulDoQqELhS4UulDoQqELhS4UulDoQqELhS4UulDoQqELhS4UulDoQqELhS6UwXEYjYjZSAZmI+G5UHguFJ4LhedCoQuFLhS6UOhCoQuFLhS6UOhCoQuFLhS6UOhCoQuFLhS6UOhCCY5DcByC4xAYh+whWn+mr0bsRCEq0YiD6MRJRGVKFypdqHSh0oVKFypdqHSh0oVKF2qDL7S/iPCFdvhCeSZTYWXCyoSVCSsTViasTFiZsDJhZXSh0oVKFypdqHSh0oVKFypdqIp5UhXzpBrmSTXMk0oPKT2k9JDyTKY8kynPZMozmQ5WNljZYGWDaoNqXJEqXah0odKFSheq47ypjvOmTpw3deK8qfSQ0kNKDyk9pPSQ0kPKM5nyTKY8kynPZMozmfJMpjyTaVAtqBZQsxeOVHs1IhxrLzjW6CGjh4weMnrI6CGjh4weMnrI6CHjmcx4JjOeyYxnMuOZzHgms449ZB3rahOsq02wrjZ6yOgho4eMHjJ6yOgho4eMHjJ6yOgho4eMHjKeyYxnMlPMJWbcQ4a5xAxzidFDRg8ZPWT0kNFDRg8ZPWT0kNFDRg8ZPWT0kNFDtjyU9S4PLZwofZ2HsnSeh4znIaOHjB4yesjoIaOHjB4yesjoIaOHjB6ygLuN12TjBXePF9w9eB4aPA8NnocGz0OD56HB89CghwY9NOihQQ8Nemg0VtZwVI+Oo3p0HNWDa7nBtdzgWm5wLTd4Hho8Dw2ehwbPQ4PnocHz0BBWJqxMWZmyMjpg0AGDDhh0wOBabnAtN7iWG1zLDa7lhmFvDmNlg3tzcG/SAYMOGHTAoAMGHTDogEEHDDpg0AGDDhh0wKADBh0w6IBBBww6YNABgw4YdMCYmDUGV2IjMGuMwKwxeA5wrsScKzHnSsy5EnM6wF8YX39hz3vDnveGPe88BzjPAc5zgPMc4DwHONdR3hsRZyfvODs5j1/n8es8fp3HrwuOEufx64qjxBVHiXMGdx6/zuPXuQpyroKcqyDnKsi5CnKugtyw35xXEj6w33xgvzmPPnf+W+foOEfHOTqT/3by307+2zx2rt5by14JvZ5ZWvZKbOxEIV6j4z3RiIPoxEmMjdkroddDTcteCb2eZFr2Suj1si/LXgm9enotvxi10YhXXlv/NoA5096Yf+aJWc5MzHIi8fqz6/mmZVeEXg81LbsiNnaiEJVoxEF04iQGUKgmVBOqCdWEakI1oZpQTagmVFOqKdWUako1pZpSLQ/7mfstD/uFORXP3IU56c7chcbKjJUZKzNWNljZYGWDlQ1WNljZYGWDaoNqg2qDak41p5pTzanmVHOqOdWcak41p9qkWlpvjVlO/Dc6hi+tt4YvWFmwsmBlwcqClQUrC1YWrCxQWb6CZmMjdqIQlWjEQXTiJFKtUa1RrVGtUa1RLU8dOVDZV3Hj8qYk6h6zoAuDLgy6MOjCoAuDLgy6MOjCoAuDLgy6MOjCoAuDLgy6MOjCoAuDLgy6MOjCoAtDqaZUy5PPGp1cPC3MBdEaqOXCHCi6MOjCoAuDLgy6MOjCoAuDLgy6MOjCoAuDLgy6MOjCoAuDLgy6MOjCoAuDLgy6MOjCWC7MIaELs//hHp08Aa7RCVZGFwZdGHRh0IVBFwZdGHRh0IUBF44XXDhecOF4wYXjBReOF1w4XnDheMGF4wUXjhdcOF4vqjWqtT0OY3U63Lhno7H6FK4hGa/Oyjor66yss7LOyjor66yss7LOyoSVCdWEakI1oZpQTagmVBOqCdWUaspxUI6DchyM42CszFiZsTJjZcbKjJUZKzNWZqxssLJBtUG1QbVBtUG1QbVBtUG1QTV/YYud4+ADG++BjZ+sbLKyycomK5usbLKyycomK5usbLKyoFpQLagWVAuqBdWCakG1mNjM2PPkWM0JucWrDSG3uNFDjR5q9FDDmWw0nMlGw5lsNJzJRmtGHEQnUq1RrVONLmx0YaMLG124uhfWtvUBlIbNFMVm0kONHmr0UKOHGj3U6KGmrExZmbIyZWVKNaWaUk2pplQzqhmO1NXTcCMc2wYc2+ihRg81eqjRQ40eavRQo4caPdTooeaszKnmVHOqOdWcas495A6cHRs0DRtEDzV6qNFDjR5q9FCjhxo91OihRg81eqjRQ40eakE1nsn6C3PJamS4EXPJak7Irej0UKeHOj3U6aFOD3V6qNNDnR7q9FCnhzo91OmhTg+t5oRV7/LQwkDp6zyUpfM81Hke6vRQp4c6PdTpoU4PdXqo00OdHur0UKeHVnPCKhLXZGM1HKx6De7uPA91noc6z0Od56HO81DneajTQ50e6vRQp4c6PdQHKxs4qrvjqF6tBatIZ2XOypyVOSvjeajzPNR5Huo8D3WehzrPQ6u1YJUzWVmwsmBldECnAzod0OkA4VpOuJYTruWEaznhWk5e2JurtWBhw95cjQFZjtABQgcIHSB0gNABQgcIHSB0gNABQgcIHSB0gNABQgcIHSB0gNABQgcIHbAaA5YaV2LrYf8SVswawnOAcCUmXIkJV2LClZjQAeux/pIw7HkZ2PMysOeF5wDhOUB4DhCeA4TnAOE6aj3WvxFnp/VQfknw+BUev8LjV3j8rofyKxmP3/WgfeUNHiWcwYXHr/D4Fa6ChKsg5SpIuQpSroKUq6D1SH39Ga8k1mPylaFhvymPPu38t70TMTrrgfj6M+G/Ff5b4b9dx85IzDHzRCUacRAzw0ycxACu42xhI3aiEJVoxEGkmlHNqDaoNqg2qDaoNqg2qDaoNqg2qDao5lRzqjnVnGrroI3ESQzgOpQXNmInClGJRhxEqk2qTaoF1YJqQbWgWlAtqBZUC6oF1QJq69n4jY3YiVBbj76vH1KM9ej7+l3HWI++r1/rj/Xo+0YnTmIA0y03vv/Mrg8BjHz/w8ZJDOBlnI2N2IlCVKIRqSZUE6ppJpPETJZbrEo04iA6cRIDaC9iI3Yi1YxqRjXLvDlml4esZb2XhzYKUYlGHEQnTmIALw9tpJpTzanmmeya+/KdDtbygJmN2IlCVKIRB9GJkxjAoFpQLah2ucV6Vna5ZaMRB9GJkxgb84m5Xb8QH/kqiI2X2vVO9ZHP0Tcq0YiD6MRJDGB7ERuRao1qjWqXId8+SRxEJ05iAC9DbmzES01y46/F08ZL7frl+cgn8RsH0YmTGMD08Y2NmGqeKEQlGnEQnTiJAdRUy9HRRuxEISrRiIPoxEkMoFHNqGZUS0tfP44Y+XqHdaTm6x1uHC9iI3aiEJVoxEF0ItUG1ZxqafR1rKfRbxSiEo04iE6csIgHcPKonjyqJ4/qyaN68qie9NCkhyY9NOmhSQ8F1YJqQbWcH9axnvPDjfRQ0ENBDwU9FPBQdhksi2SXwca+D/DsMtioRCMOohMnER7KN0isAzw7EjZ2ohCVaMRBdCKOam84qr2/iI3YiUJUohEH0YlU61QTqq2ZIBKvDJqDmp6/cRKvDNfXCkZ2OmxsxE4UohKNOIhOnESqGdWMaul5lUQhKtGIg+jESQxgzg83NiLVBtUG1XIm0Dx20vNrzNLzN3YiR8c5Os7RcY6Oc3Sco+McncnRmRydyX0xqTapNqk2OTqTozM5OpOjExyd4OgERyc4OsHRCe6LoFpQLaCWXRxrJLNfw64vXYzs19g4iE6cxACmj29sxE7MekeiEo2YajPRiZN4qV0/mxvZ/LGxETtRiEo04iA6cRKpJlQTquUZ/frp3siGDrMcyfTxjQFMH9/YiJ0oRCUacRCpplRTqqVjLQc1vWk5fOnNG504iQFMb97YiJ0oxOvPrp8ajuzMsJE1pPVuVOJVzsjK0no3XuVcjU4jOzNsZN603sK03o2N2ImXmuduSevdaMRLzbPItN6Nl5qnGdJ6V0vTyGYKu7qQRjZT3JhH9dV6NLIVYqMQlWjEQXTiJAYwj+obqdap1qmWB23eW8leiY0BzIP2erXCyF6JjZ0oRCUacRCdOIkBVKop1ZRqeSjnDaDsf7C8bZH9DzfmyefGRuzELOc6hWYjg+WVezYybHTiJAYwzxc3NmInClGJVHOqOdXymIzczDwmbxSiEo04iE6cxADmbB85Djnb32jEQXTiJMaNno0MGxuxE4WoRCO+k43rNQGefQobG7ET5cKeOC7URCdOYgD7i9iInShEJRqRap1qnWqSySwxk3miEo04iE6cxADqi9iInUg1pZpSTTNZDrXln0Xi9Q9aDuplho1OnMQAXpP5xkbsRCEqkWqDaoNqkclyx0YnClGJRhxE35ifk2m5mfk5mY2dmHk1UYlGzLwz0YkTmEfq9U4Hz26AjZ14SfQs55rMNxrxkrheouD53H9cL0bwfO6/sREzb5aeR+rCPKIk/0EeD5KV5fFwoxLz3+afXWf/oVnkdfYf1/LW8/H7xgDmQaA5JHkQLMyD4MbMkBJjEgN4zZPDUu2aJzd2ohCVaMRBdOIkBnBSbVJtUm1SbVJtUm1SbVJtUm1SLagWVMvj13L48vi9UYlGHEQnTmJszAftGxuxE4WoRCMOohMnkWqNao1qjWqNao1qjWqNao1qjWp52F/fx/F8VL+xETsx1TRRiUYcRAcKZo18VL9xEPPfjsRJDGDOv9dXaDwf1W/sxEtiZLI02Y2DeElc78zwfHnAuF6U4fnygHGtUz1fHjCujn3PZ/kbLwnPgboulYdnhutSeeOl5pksZ3BfyZx4qc0sMs27MM17YyN2ohCVaMRBdCLVBtWcak41p5pTLY0+c4vT0jOHL807c4vTvDN3bJr3RiMOohMnMYBp3hszb45k2vRGI2bePB7SpjdOYua99lt2A2xsRJSeLQAbjXhJXF9m9ny7wMZJvCSuBZzn2wU2NqLsMcvOgY1GTAlPdOIkviU8F1rZObCxEfXCVLust3EAr6WP57IjewQ2GjH/bQ7JZb2N7xo8DZk9Ajde1tt41ZCn5nx5wEYhKtGIg+jESQygvYhUM6oZ1YxqRjWjmlHNqGZUG1QbVBtUG1QbVBtUG6mWoz6cOIkB9FTLHeCN2IlCVODMP5uJjdiJ15/leidbFjYa8SqyZ72XITdO4OVCv94f5dnTsLETUyK3IpRoxJTIci5vuuQBc3lzY2zM1w9sbMROFKISjTiITpxEqjWqNao1qjWqNao1qjWqNao1qjWqdap1qnWqdap1qnWqpY+vO+menRkbJzGAkmqW2IidKMTMOxIzw7WzsotjYyN2YmaIxKveXLJmb4dr1pvuvtGJkxjAdPeNjdiJQlQi1YxqRrV0dy6Fs7fjxnT3jY3YiUJUohEH0YlUS/Nqjq/nn+WYedaQY5bmvfGqIRen2aSxUYjKf2vEQXTiJFItzbtqCGYIZkhvLrX05o2xMRsv1r/NxouNnShEJRrRdw35qoL7f23M0LDF2a+x0YiD/9aJk4gtzn6NjVTrLLKzyM4i02S5ps3ejo2TGMA02Y2N2Im5QZKoxNwgTxxEJ6ZalpOGXJiGvPFSu17+5tn8sVGISjTiIDpxEgOYhryRakY1o5pRzahmVDOqGdWMaoNqachcjmejiOdyPBtFNirRiIPoxEkMYJ5ub2xEqjnVnGpONaeaU82p5lSbVJtUm1SbVJtUm1SbVJtUm1SbVAuqBdWCakG1oFpQLagWVAuq5aRw3c337C/ZmBIzUYiXxHVb3rOpZOMgOnESA5hn6esWvmf7iOfFVbaPbDRi5tVEJ05iAHN+uLEROzHVLFGJRhzEzHuZN/tA3HPj0/M35p9F4iA6cfLfBjA9f2MjdiLV0uirBmUGY4b08VJLH98oRNabPr5xEJ3Ieo1qad5Vw2CGwQyDW5zevDGAznqdW+zcYucWO+t1qjmLdBbpLDINmdex2dCxsROFqEQjDuKlltdv2dCxMYBpyBsbsROz9CtZ9mB4XktnD8ZGISoxy7HEQXTiJAYw7XRjqmliJwox1UaiEQfRiZMYwDTZjY1o+0ZCtlhsdCKuebPF4kZ5EXHNmy+T2CjELD0SryJj/a+TeBUZOZJpshuvvHm5no0XG6+8+TAkGy82GvG9FfNqxvRsvNg4iQG8DLmxETtRiEo0ItWMakY1o9qg2qDaoNqg2qDaoNqg2ki1HL4xiQH0FzHVclC9E4WoRAPO/Lc56lOISjTiIDpxEgMYL2IjUi2oFlQLqgXVgmpBtYBavj5jYyNCLXsl5tUj69krsVGJKTwTB9GJl3DefMleiRsvv228JPJWRDZIbFTiJZE3ErJBYqMTJzGA8iJe23a99trz7RgbhajESy3vKeTbMTY68VLLewrZTDHzmjebKTY24qWWF7rZTLFRiUYcRCdOYgDTmzc2ItWMakY1o5pRzaiW3swr7Gy8mHkBnY0XGxuxE4WoRCMOohMnkWpONaeaU82p5lRzqjnVnGpONafapNqk2qTapNqk2qTapNqk2qTapFq6O29F5Bs6Nl5qeVci39CxUYlGvNTyyj3f0DE1d1a6+8bYmG/o2NiInSjEVPNEI+KRQ76WY2MAG051se4gL+xEnOqyF2WjEfNmctawbiYvnMTcoGv4sutk5hV2dp1sVKIRB9GJkxjAnCpubESqCdWEakI1oZpQTagmVFOqKdWUauuZTw7feuazcO7nONmhcmM+88m1fXaobMxkPVGISszScxfmTHCjEycxgDkT3NiInShEJVJtUG1QbVBtUM2p5lRzqjnVnGpOtZwJ8gletsZsnMQA5kyQz+qyd2ZjJwpRgZelW/Ye5Os+NnZi/lkev2npG414FZmP+LJLZuO8cWYTzLx61WY2wWxU4pXsuuad+TaPjU7MZCPx2uLriJrZJbOxETtRiEo04iA6cRKp1nOgst7eiJ14qV1H9czemY1GHNe/lUQnTmJcmJspL2IjXtvm+W/T0jcq0YiD6MRJDGBa+sZGpJpSTammVFOqKdWUako1o5pRbfXkzEQhKjHVcqjT8zc6cRIDmJ73HL70/I2dmBlyH6djPdXSb9fz2JkfK9kYwPTbjVfemcd6+u1GIV5jNnMz88x74yA6cRIDmGfeG1Mtty3PvDcKUYkpcR192QE0rwvSmR1AG4WoxCzSEwfRiVlkJAYwDXljI3aiEC+167NQM5uBZmSRacirAXDmq0HmdbU4swNoXh+AmtkBtFGISsxkuRV5srxOwjNf1jEjS19Nk1mDDmKqzcRJDGAetDc2YicKUYmZLCWuYzJeucXXMbmxETtRiEq0C3OgrvPQRidOYgD9RWzETsxkOeruxEnMZLkv5ovYiJ0oRCUacQAjk+V+i0bsxEyWezOUaMRBdOIkxsZsHNqYyUaiEQcxk3niJAawvYiN2IlCTLWZmGqROIhOnMQA9hfxUrt+XDmzL2ijEJVoxEF04gSKYOOFoyMcHRnYIOHoCEdHODrK0VGOjnJ0VDAkqtg25egoR0c5OsrRUY7O5c17K4yjYxwd4+gYR8c4OsbRMY5OGvJaBc1sBorrgn9mM9BGIw5iZpDESQxgGvLGRuzEVNNEJRpxEJ04iQFMx7Y87NOxuZTIdqKNQlSiEQcx1XIXzkkMYFr6xkbsRCEq0THUad41kmnexGwn2tiIGLPsLNqoRCMOohMxZtlZdGO6+8ZG7EQhKtH2UGeT0RqzbDLaOIkBTHff2IgYM+lCVKIRB9GJk4g9lK8yietXnTPblDZeea+fZ85sU9o4iE6cxACm53uOQ3r+xk4UohKNOIgOTB/3HNR0bM/RyVNozw3KU+iNnZhqM1GJRky13Ph07I2TGMB07I2N2ImX2vVbz5mNQxuNOIiOrUgXSh7K6cIblWjEQXTiVa+sZAFMF97YiKmW9aYLNR2QLrzRiIPoxEmMjdlOtLERO1GISjRiqlmiEycxgOnNGxuxE1NtJCox1TzxUrtuJMxsJ9r/6yReapaVpTdvbMROFKISjTiAksk0MZNlvWnIG4WoxEyWW5GGvNGJkxjANOSNqZbbloa8rtxndhbF1ekws7MorkbemZ1FGwfxynt1DszsIYq8tM8eoo2dKMTMmxuf5r1xEJ04iQFMo+d9guwhirwjkD1EkXcEsoco8ho9e4g2GjHz5hanpUducVr6xkbsRCEq8crrOSRp6RudOIkBzJPwjY2YyXJQ06Z5xZqvdNkoRCUacRCzhhydtOmNsTE7izammid2ohBTbSYacRCdOIkBTJvemGqR2IlCVGJKXDs2P3cSeYWdfUGRl7/ZF3Rj2unGRuxEIV4SeVGcfUEbB9GJqZY1pJ0Wpp1uTLUcqLTTjUJUohEH0YmplgOVJluYJruxEVMid2FaJC9es6tnYyN24vVneYWdXT0bjTiITpzESy2vpbOrZ+OllpfV2b/TXnk9mQ084JGc++ByCXgWDvJ8FW6Fe2EprIWtcNGdRXcW3bl0czjjVXjp5iZGLyyFV55r28f6cVVezYz166qbpbAWXnVG8ijshWfhrDNXx9mmA26Fe2HB+GcDD9gKj8JeeBZeutdEnm084Fa4F86/zXV19uS8eSRb4VHYC8/CQdalm+OsrXAvLIWXbo6bWuFROHWvzuyZb2oBB9lehVvhXlgKp26uhLOpBzwKe+G1jXk8jPXvc9zGKOyFZ+Eg+6twK9wLS2EtXHS96HrRXf7K5fdY/rp5FF7/Psd2+evmIC9/3dwK98JZp2TO0MJWeBRO3VzbjuXHmwPs6zeQ168Dpy+f3twLL91ITt3rYeX05dOrwXn68unNXngWDvLy6c2ZPxenvvx4sxUehb3wLBzk5cebW+FeuOj2otuLbj5oeF0/RJvZ7QPuhaWwFrbCo7AXnoWDrEVXi64W3eXrXDr78vXNS1eTR2EnL5/m+tmXH3Ml7MuPN3vhWXjVmcfGeBVuhXvhVWceP0MLW+FROHVzgezL1zcHefk6l8C+fH1zLyyFUzcXx758ffMovHRzG9f59+Ygr/PvzUt3JvfCUlgLW+FReOnmtq/54eYgr/nh5tTNJbKv+eFmKZy6nmO15oebB3guv+fqeC6/3yyFVx5LtsKjsBfO+nOBOtf5N1eoc51/b5bCWtgKj8KZf66cs3CQl99vXrqe3AtL4aU7k63wKLx0I3kWDvKaH25O3XxoM9c8kIvDueaBm0dhL5z583nOXPNAPq+Zax7IBzZzzQM398JSeOnmOKx54OZR2Asv3dzePKe3fJaSfUdvztpyrmi5JszOozevf6+FrfAo7IVn4SCPpZtjOFrh/Ntcs2UzETjIvp7P57Z7K9wLS2EtbIVHYS88Cwd5Ft1ZdGfRnUs3j7epha1w6uYaKfuLwJO8ug16eja93PLOXzYLvTn3Y3jhWThrzlt+2TAEboV7YSmsha3w0p3JXngWDnKe69v1TreZbUTgXjh1855ddhKBrfAo7IVn4SCvlgSR5Fa4F5bCa3sj2QqPwkvXkmfhIMvKn2Mlq/782/R+09ze9P7mWTjz5LooO4nArXAvLIW1sBVeurmN6oVn4SBb2V9W9peV/WVlf1nZX1b2l5X9ZWV/WdlfVvbXKPtrlP01yv4aZX+Ntb055sMKj8Jre0fyJK+5Im9nxporbpbCmf9q2pqx5oqbR+HMn+uxWHPFzUFec8XNrXAvLIWXbo7JmituHoW98Nqu9FqsPDk+oYWt8MqT47DmjZtn4VX/exziteaNm1vhXlgKa2ErvHRnsheehYO85o1rvRqvNQ9c68O4+4uudWDcDUY3S2EtbIVH4azhWh/G3WZ0c5DvRqPFS9eSe2EpvHRHshUehb3wLBzk5f2bl26O4fL+zVJYCy+tHLfl2esearyWZ2/WwlZ4FPbCWadn/uXZxcuzN7fCSzf34/LszVp46eY+XZ692Qun7swa1nl/5r5b5/2Z27i8fHMvLIW1sJGXHyPzLz/eLIW1sBUehb3wLBzk1Ut4c9GNohtFd/k38thb/r156Wb9y783T3BbfrzWhNGW7671XrTlu5tn4SAv3133LaOt8/XNvbAUXnVGshUehb3wpduv1pnIdxptzvP15pYsyb2wFNbClpzbmx7f7IVn4SDLq/DSzXGQXlgKa+GlO5NHYS+8dHPbJcj6KtwKp+61vo18TRNYC2f+ltue5/HNQc7zeG9ZQ57HN/fCUlgLW+FReOlmnTYLp+61Xo1s3wK3wr1w5u+5Lb7+TR633gtLYS1shUfhrK3nfsxz8eYgz1fhpZvH8OyFpfDSzW2fVngU9sKzcJDjVXjp5rhFLyyFtfDSuo63fI/T2wSvZCmsha1w/u21vops2gLPwkFO729uhZeuJ0thLWyFR2EvPAsHeXn/5la46Pai24vu8v61xo6+vH9z6mqOw/L+zUFeXr7W3tGXZzW3d3n25iAvz96cdV5r5ujLszdLYS2cdV7r0sj+LbAXnoWX7nXM9OXlm1vhXlgKa+Glm2OyvHyzF56FU9dyTJaXb26Fe2EprIWt8CjshWfhoutF14vumh8sx3PNDzdrYSu8dDXZC8/CQV7zw82t8NLN/bLmh5u18MqZPl0ez3VvXx6/WQpr4VVz7q/l95u98CycNV+9B5G9X+BWuBfmsSEvLWyFeWzIywvPwkFec0WupWXNFTf3wqmb62dZc8XNVngU9sKzcJDXXHHzym/JWtgKr/ye7IVXfk0O8loP3NwK98JSWAsv3RyftR642QvPwkFec8vNrXAvLIW1cNHVoqtFV4uuFl0rulZ0reha0bWia0XXiq4VXSu6VnRH0R1FdxTdUXRH0R1FdxTdUXRH0R1F14uuF10vul50veh60fWi60XXi64X3Vl0Z9GdRXcW3Vl0Z9GdRXcW3Vl0Z9GNohtFN4puFN0oulF0o+hG0Y2iG9TV16twK9wLS2EtbIVHYS88CxfdVnRb0W1FtxXdVnRb0V3z0vXzm9A1L908Cy/da/7Ue15a3Aqn7vVMJHTNVzdr4dT19e9HYS88Cwd5zVc3t8K9sBTWwkVXiq4U3TUv5fW4rvnnei4Tuuafm63wKJx58ppd1/xzc5DX/HNzK5z1zxznNc9crT2ha5652QvPwkFe88zNrXAvLIW1cNEdRXcUXS91rnnjZi288uR4rnnjZi+c9UeO25o3Fq954+ZWuBeWwlrYCo/CXrjozqIbRXfND3lfQtc8ELmP1jxw8ywcYFvzQN6XsDUP3NwLS2EtvOofyaPw0p3Jk5xelusZVuQbu8CjsBeehYOcXt7cCvfCUrjo9qLbi66snC155czxkZVTkt858yoxO/JuMtCqMEdG119Z8qokR0ZXJZ68Ksm/vdyX13LZRrfoct5N668iOcenZc3pKcl7DtlS9+b89+kpyfsM2VQH7oWlsBa2wqOwF56Fg+xF14uuF10vul50veh60fWi60XXi+4surPozqI7i+4surPozqWbe3A6OVae3Jux/n3uzSh1RqkzSp3BOvNNWOBWuBeWwlrYCo/CXngWLrqt6Lai24puK7qt6Lai24puK7qt6Lai24vu8mmO5+q72+wY27E8mGM7pNQppU4pdUqpU0qdUuqUUqeUOqXUqaVOLbpadLXoatHVoqtFV4uuFl0tulZ0reha0bWia0XXjGNoPG7H7fccz9vXOZ7F16P4ehRfj+LrUXw9iq9H8fUovh7F16P4ehRfj+LrUXw9iq9H8fUovh7F16P4ehRfj+LrUXw9ZtGdRXdOjtsMcijH8PZ1jmHx9Si+9uJrL7724msvvvbiay++9uJrL7724msvvvbiay++9uJrL7724msvvvbiay++9uJrL77229ea3AoPjFu+k+seN5dSZ/G1F1978bUXX3vxtRdfe/G1F1978bUXX3vxtRdfe/G1F1978bUXX3vxtRdfe/G1F1+7lfGxXpjzng/Oe17O117O117O117O11587cXXXnztxddefO3F11587cXXXnztxddefO3F11587cXXXnztxdc+y/jMMj6zjE+U8YlSZ5Q6o9QZpc4odZbztZfztRdfe/H1LL6exdez+HoWX8/i61l8PYuvZ/H1LL6exdez0V+ztcL012z01yzn2dlLnb3U2UudvdTZS5291NlLnb3U2Uudxdez+HoWX8/i61l8PYuvZ/H1LL6ewvl5CufnqZyfp3J+nsWPs/hxFj/Ocp6d5Tw7y3l2lvPstFKnlTqt1GlF14puWYfP4utZfD2Lr2fx9Rw8v8/B8/t0nt+n8/w+ix9n8eMsfpzFj7P4cRY/znKeneU8O8t5dpbz7Czn2VnOs7OcZ+csurPoRtGNcpxHL8x5IF6cB6L4MYofo/gxih+j+DGKH6P4MYofo/gxynk2ynk2ynk2ynk2ynk2ynk2GvdjNF5fROf1RXReX0TxYxQ/RvFjFD9G8WMUP0bxYxQ/RvFjFD9G8WMUP0Y5z0Y5z4ZyvgpthTlfhXK+iuLHKH6M4scofozixyh+jOLHKH6M4scofozixyh+jOLHuP2Y9d9+XBzclvv8mNtSzo9Rzo9R/BjFj1H8GMWPUfwYxY9R/BjFj1H8GMWPMTlvRLmejeC8EcF5I8r5Mcr5Mcr5Mcr5MXh+bK8XT5BX0GrQayA10BpYDVDuFXgJGgxyBXDIFYySgGvXK5g1qFX3WnWvVfdada9V91p1r1X3WnWvVUutWmrVUquWWrXUqqVWrbVqrVVrrVpr1VqrViu1aa3aWinUtBRqdUutVm21aqtVW6161KpHrXrUqum6K9AaRKmNxruCuqVet9Rr1V6r9lq116q9Vj1fpQKuUK9glHJmlHKibmnULY26pVGrjlp11Kqj7p8oR1V7laOqvcpR1V5lS9vLazBrULa0tVcNypa21mvgRbS/imj1T6v+adU/rfqn9XIktuqfJuVIbFKOxCZldFr1T6v+aVwyXkGUgIvGK/CSWuvoaB0dK8dBszo6Vo6DZuU4aPWIb6P+zagjOuqIeh1Rr3/j9W+8/s19jPoK1t/MFfQaSA20BmtEYwWjBl6DWYMowX3E30FWcPWPXUFWcDWQXUFWcP1C4gqygr5GZx3xOxg1SJ2eG9fXWWYHrQYrwVxBFtpjBZlAspzVNyXSVpAJpK+g10BqoDWwGowaeA1mDaIEyzI7qBX0WkGvFfRaQa8V9FpBrxX0WkGvFUitQGoFUiuQWoHUCqRWILWCZUCRFcwSrJOR6ArW39gKatVaq9ZatdWqrVZttWqrVVut2mrVVqu2WoHVCqxWMGoFo1YwagWjVjBqBaNWMGoFo1YwagWjVuC1Aq8VrMnhHut1OtzBLAO/Jod74GetetaqZ6161qpnrXrWqmetetaqo1YdteqoFUStIGoFUSuIWkHUCqJWEKWC1XmFoNWg10BqoDWwGgwO72rA2sE9h+gKjGMtdaaQOlNInSmkzhRSZwqpM4XUmULqTCF1ppA6U0idKaTOFFJnCqkzhdSZQupMIXWmkDpTSJ0ppM4UUmcKkVqB1ArWqfoe0bXU3YGV4b1nijW8daaQOlNInSmkzhRSZwqpM4XUmULqTCF1ppA6U0idKaTOFFJnCqkzhdSZQupMIXWmkDpTSJ0ppM4UUmcKqTOF3DPFGsQ6U6x2qD2iaxlxj+isVdeZQupMIXWmkDpTSJ0ppM4UUmcKqTOF1JlC6kwhdaaQOlNInSmkzhRSZwqpM4XUmULqTKF1ptA6U+irjJu+pAZlhtVWZlitawqtawqtawqtawqtM4XWmULrTKF1ptA6U2idKbTOFFpnCq0zhdaZQutMoXWm0DpTaJ0ptM4UWmcKlTpuUsdN6rhpHTetVWutWmvVWqvWWnVdU2hdU2idKbTOFFpnCq0zhdaZQutMoXWm0DpTaJ0ptM4UWmcKrTOFjuJTHXXcRvGpevGp1lWAeq3aa9Veq/ZatdeqvVbttWqvVc9adZ0ptM4UWmcKrTOF1plC60yhdabQOlPoLOcFjVcNynlBo5wXtHrbqretetvqKsDqKsDqKsDqKsBeowZeg1mDWkGrFdSrD6szhdWZwupMYXWmuHul1hjczVJ30Ms65G5zWgNi1dtWvW3V21a9bdXbVr1tdRVgdRVgdRVgdRVgdRVgdRVgdRVwt1DdgdYKtFagxSV3e9UOyuxiVmYXq9626m2r3rbqbavetuptq9626m2r3ra6CrC6CrC6CrC6CrC6CrC6CrhbsO4tHeU6626qujfby3WWVW9b9bZVb1v1tlVvW/W2VW9b9bZVb1v1tlVvW/W21VWA1VWARZkT7+6rHZQ58e6nWls6qrdH9fao3h7V26N6e1Rvj+rtUb09qrdH9fao3h7V26N6++6uWttzt1fdwX1GXxt3n7fXxtXz9qjn7VG9Paq3R/X2qN4e1dujentUb4/q7VG9Paq3726rexPqvYC7f+reHi0z0qjn7VHP26Oet0c9b4963h71vD2qt0f19qjeHtXbo3p7WK3airPGKM66+6buTahr8lHX5KOuyUddk4963h71vD3qeXvU8/ao5+1Rz9t3C9VdqNeqZ6161qqrG0d146huHNWNo67JR12Tj7omH3VNPuqafEQ9QqJUfXdIrULvVqhVqFc3enWjVzd6daNXN3p1o1c3enWjVzd6daNXN3p1o1c3enWjVzd6daNXN3p1o1c33u1RdwV1FX03PN3laJn5vJ4bva6iva6iva6iva6ivbrxbnC6RbUcVW7lqHIrR5XXc6PXc6PXc6PXc6PXc6PXde/d6rSDcka/m5Ru0eofr/7x6h+v/rk7le7U1T9379GtM+uRWM9mXv3j1T9eV6peV6peV6peV6peV6qzrlTvdqOVYNar0LuBaGW7O4VWtlmP+Nnq3zSpQRnRu13oTtDr3/T6N73+zX2MjhWssfYVWA1GDbwGV7f7nSuA1zG9sRE7UYhKNOIgOpFqSjWjmlHNqGZUM6oZ1YxqRjWjmlFtUG1QbVBtUG1Q7Tr473G+Tio3XqeUjY3YiUJUohEH0YlUc6pNqk2qTapNqk2qTapNqk2qTapNqgXVgmpBtaBaQO3u9FFdQR6F+lpBHoVqK/AazBpECZardtBqsBL4CmYNogTr1LGDVoNeA6mB1sBqMGpQK+i1gl4rWGs3jRVkausrsBqMGngNZg2iBOvcs4NWg14DqUGtQGsFWitY6z3LOefuBrK1g9e5ZwdaA6vBqIHXYNYgSrDOSjtoNagVjFrBqBWsU5StgV+nqLEOl3WK2oHUQGtgNRg18BrMGkQJ1uXbDmoFs1YwawXr8m2sqtcJbwejBl6DWYMowTrh7WBVMFfQa5AV+PLpWjDuwGowauA1mDUIBO3uRdpBq0GvgdRAa2A1WBWMFXgNZg2iBGva2EGrQa/BqsBXoDXICq7fZl7BqIHXYNYgSrDmnR20GvQaZAXXbx+vQGtgNRg18BrMGkQJ1mJ2B6uCNaJrMbsDqYHWwGowauA1mDWIEqzpaQe1Aq0VaK1gTULXD0avgM5qL3vVoNWg10BqoDWwGowaeA1mDWoFo1YwagVrehrr2FnT0w60BlaDUQOvwaxBwLRtvc4LQXWWV2d5dZZXZ3l1lo8aeA1mDaq3Z/X2rBXMWsGsFaz57fbcmt92UL09q7dn9fas3o7q7TW/3aZd89sOpNhszW87qN6O6u2o3o7q7Sjebq9XDRptdneE7UBqoDWwGowaeA1mDYqz7l6xHbQa9BpIDbQGVoNRA6/BrEGtoNcKeq3gnsVsBSubr2DWIEpwz1VzBa0GvQZSA62B1WDUwGswaxAl0FqB1gq0VnDPVbECrYHVYNTAazBrECVY89sOWg16DWoFViuwWsGaxWIdo2uuusd6zVU7kBrUER11REcd0VFHdNQRHXVEvY6o1xH1OqJe96nXCrxW4LUCryPqdUS9juisIzrriM46orOO6KwjOuuIzrpPZ61g1gpmrWDNSPdeWPPO9W6AKxg18BrMGgSDu/tuB60GvQZSg9ye6wUDV2A1GDVYFegKZg2iBGveibGCVoNeA6mB1sBqMGrgNZg1iBL0WkGvFfRawVo9ha/gyqav1wqiBDnvIGg16DWQGmgNrAajBl6DWoHUCrRWoEtn7RJd2dbAq9dg1iBKYK8atBr0GkgNtARjJZgryH/WVm05OSCwGmShbVWdkwOCLDQbcNvqpNO2dHJyQNBq0GsgNVgVrB3sVoNRg1XB2gSfNVgVpDXXG8y0r03I9YH2VWj69A5Wg5r2sQKpgdbAajBq4DWYNYgStFcNWg1qBa1W0GoFbaWOFUQJ+qsGmTobcNvqY0MgNdAaWA1GDbwGswZRgmWzHdQKpFYgtYJlpryF2lZPmuatuLZ60hC0GvQaSA1WobkoWS1lKnMFXoNZgyjBMsYOWg16DaQGWgOrQa1g1ApGrWB5QdeALC/sQGtgNRg18BrMGkQJlhd2sFKvw39aDUYNvAazBlGCeNWg1aDXQGpQK4haQZQKVq+Y5p3GtnrFEPQaSA1WalvB2gRfwaxBlGBZcwetBr0GUgOtgdVg1KBW0GoFrVawrKlzBZnaXiuwGowaeA1mDaIEy5o7aDXoNZAa1AqkViC1guVTaytYCfoK1j9bu2RZcwezBlGCdWrbQatBr4HUQGtgNagVWK3AagXXOlHHQiEq8bqLHgsnMYB5F33tuLyLfmMnroLvQGtgNcgaxxrZXCIiCAarx0pHW0GrQa9Big5dQY7FGCvwGswaLJ0sZ3VS7WCdRtYV+Wpd0nURvlqXELQarL9ZCdbR5bGCHIN1db1alxCMElzXW2siyA8ibnTg2vnronQ1EyEYNcgNnqv4tfN3ECVY8/8OWg16DaQGWgOrwahBrWDUCkatwGsFXivwWoHXCrxW4LUCrxV4rcBrBes0sa4PV2sSglaDXgOpgdbAajBq4DWYNagVRK0gagVRK4haQdQKolYQtYKoFUStIEoFq9EJQatBr4HUQGtgNVgVzBV4DWYNogTLeuuacjU6Ieg1kBpoCa4l4Jq+8vVPG4V4zW+20IiDmJWua8LV3IQgSrAMv67IVj8TAqnBW27NS6ubSWNtaNrd1qXR6maydWm03h6FIDJYknnOsddKnGtDBD2DlTrPRrauX9Y7pBBYBrKCUQOvwaxBlCDPUwhaDXoNpAZag1qB1QqsVmC1AqsVjFrBNSHZOtiuSWedmldflK3rqtUXZW3tWm816DWQGmgNrAajBl6CuXTW7pitBr0G14G4Ks4T7Y1GXAqxAq/BLEHUzYq6WVE365or9P4LJRox5dbl4GqZQjAZ5Jun1ujmi6c2dmKOX7cVaA2sBksuVuA1mCW4jL8WKdlRtVGAedVn62JqvRoKQa9BViVrG3JpiSCryqf6bXVTIfAaZFVrMbO6qXYgrxq0GvQaSA20BlaDUQOvQa1AagVaK9BagdYKtFagtQKtFWitQGsFWivQWoHVCqxWYLWCNRusJaOv2WAHVoNRg6xgXbStTi8EUYI1G+yg1WAl6CuYNYgSXNODrX19TQ4bOzGL1zvQGlgNltzaYJ81iBKsWWJZfb2SCkGvQYre1spFht0Hfi4yEIwaeA1mDaIEa+LYQatBr4HUoFYQtYKoFUStIGoFUSpY/WcIWg16DaQGWgOrwaiB12DWoFbQagWtVtBqBW1VMFagNbAajBqsCnwFswZRgjV/7WDpzBVktnXBs16OhWDWIEqw5qK1ylhdczb6CnJ71qXQekUWAq2B1WDUwGswaxAlWHPRDloNagVaK9BawZqL1sXY+k4lAq/BrEGUYM1FO2g16DWQGmgNagVrklkPqddrtMzXWOfFjfka6zXJ7CBr8zXwa5K5g7UG2UErf7PWIDuQGmgNrAa1gjXV3LXNmm3WbGsOuStYc8gORg3q9qw5ZAdRgjWH7KBuT9QK1rRx1xY1W5Rs621bdwXrdVsIeg2k/o3WwGowauA1KBWs1jsErQa9BktUV6A1sBqMGngNZg2iBGsKcFtBq8GqIFYgNdAaZAVzFbqmjR14DbKC9Zx99e7tYE0bO2g16DWQGmgNrAajBl6DWoHUCrRWoLUCrRVorUBrBVor0FqB1grWtLGe2q/mP1vXqOsVYQhaDXoNpAZaA6vBqIHXYNagVjBqBaNWMGoFo1YwagWjVjBqBaNWMGoFo1bgtQKvFXitwGsFXivwWoHXCrxW4LUCrxXMWsGsFcxawawVzFrBrBWsKW3dUFh9hQhSdN0pWK2ECFJ0PS9erYQIpAZaA6vBqEGK5o2CvhoG7foK3xW0GvQaLJ2xAq2B1WDUwGswaxAlWJNdPi/uq2EQQa+B1GDpRAY5V428WdFXvx+CnkFbgdRAa2D1b0YNvAazBlECqRWs6emuTWo2qdlklgokSqCvGtTt0V4DqYHWoG6P1grWVHPXZjWb1WxWR8esBqMGdXusjo7V0Rl1dEbdnlErGHUTRt2EUTdhLFFZwaxBlMBfNWg16DWQGqwKljHcajBq4DWYNYgSrMkhVuq5/tky04wSxKsGrQar0HXEh9RAa2A1GDXwGqwKluciGKyeOgSrgrmCXgOpgdbAajBq4DWYJcg7J75QiErknZm+2uQQeA14Z6avNrkdrCXMDnKz8kZjX21yIxsl+noNG4IsPm/O9dVAhyCLb2uQlvnvYJm/LR1pNeg1yOHLt4H11UCHwGowauA1mDWIEqwJYwetBr0GtQKtFWitQGsFWivQWoHWCqxWYLUCqxVYrWBNMn0N/JpkdjBq4DVYFaxdsiaZO1iTzA5aDXoN1t+sPbfmiB20GvQaSA20BlaDUQOvwaxBrWDWCmatYNYKZq1g1gpmrWDWCmatYNYKZq1gzQT5Jrm+utwQtBq8y8nr+Z49bhuVmIXknc2++tsQeA1SLm9z9tXShqDVILc+b3P21dKGQGtgNRg18Brk1uc9tb5a2nawlg47aDXICnSVs5YOO9AaZAX5bKavN9INW1u6Zo8dzBpkBbYSrNljB60GvQZSA62B1WDUwGswa1Ar0FqB1gq0VqC1Aq0VrNnD1his2WPN4at1DsGsQZRgzR47aDXoNZAaaA2sBrUCqxVYrcBqBaNWMGoFo1YwagWjVjBqBaNWMGoFo1YwagVeK/BagdcKvFbgtQKvFXitYM1FeQevr648BKuCPEGtrjwErQa9BlnBWLt+zUVj7fo1F+1g1MBrMGsQJVhLoR1kBWM5eC2FdrAfWvbsF9w4iGWB0O8nRXcQDNar8e4Fwno1HoJeg/XwSFegNbAarA32FazNWgnWNLeDVoNeA6mB1sBqMGrgNZg1qBX0WkGvFfRaQa8V9FpBrxX0WkGvFfRaQa8VrNs0awm/3pOHIAdxrZnlfu58B+u581zBrEGmzrtgffUkImg1yI3LO3R99SQi0BpYDUYNvAazBlGCNX/toNWgVmC1AqsVWK3AagVWK7BagdUKRq1g1ApGrWDNXy4r0BpYDUYNVgXLMmv+2kGUYM1fO2g1eCcYN05iAK+JZ6xdfk07Gztxlb2OpDXl7MBqkJXOte/XLLODKMGaZeYakTXL7KDXIEXnGoR1wTVXOeuCawejBl6DWYNgsLonEbQa9BpIDbQG17Q3Fw6iE5f2HUQJ1mS0g2u4fWEnCvGtmrfIe3ZSbhzE3OK4g1mDKMGagHbQatBrIDXQGlgNRg1qBb1W0GsFUiuQWoHUCqRWILUCqRVIrWD93GAt7tab/RBECdY8FXfQatBrIDXQGlx7YO2Xa5ba6MA12+Rdvr56Lse6/bDeqDfWvbz1IVEEWgOrwdrGlXrNAjuYNVijvA6oNQvsoNWg10BqoDWwGqwKYgVeg1mDKMFauKxbi+v1er5ONOv1eghmDaIEOT34aw1iTg8Ieg0kg+XHnB4QWA1GDbwGswarghz41Ujq637MaiT1dQ9nNZL6Ogmu3lF/xQq8BrMGUYJ0v6/bIOtde97y4FqvyvN1G+TuHZVVzv2jgTvICrLBqa/eUQRaA6vBqIHXYNYgSqArta5gpV4VqNVg1MBrMGsQJbA1Bmt482yNoNdAaqA1sBqMGngJxkq99tzoNZAarNRrnw6rwaiB12DWIErgrxq0GqzU6zjwUQOvQabu6whJZ+0grw8QtBr0GkgNtAZWg5V6HXzLcztoNVip12G5PLcDrYHVYNTAazBrsCrI4231lvpayq/eUgS9BlIDrYHVYFVgK/AazBpECZY1d9Bq0GsgNZgcqvXN0R30Vw0aN3t9dhSB1EBrYDUYNfAazDKIPcoYSB1RqSMqdUSljqjUEV1zyL2lUkdU6ohKHVGpI6p1RLWOqNYRXdPGuh22mkt93fRazaU7WNPGDloNVra5AqmB1sBqMGrgNVgVxAqiBONVg1aDXgOpgdYgK8jPQfT1Gj9ft+XWa/wQzBpECdbssoNWg6xA1kGRp3cEWgOrwaiB12DWIEpwTzVrZ91TzdoL91RzB1aDUYM61msVsIMowT0j3UGrQd3bUcc66ljfM9IdjBp4DerejrK31+dU7521vqd6j/V6XSACqYHWwGowalDGerW2IihjvV4kiKDVoNdAaqA1WDq6glmDpZO7cbXLImg16DWQGmgN1paucVtz1Q68BrMGUYI1V+2g1aDXILPp2iVrdtE1omtRsm4dr2ZVBF6DrGDdOl7NqjtYs8sOsgJdQ7Vmlx1IDbQGVoNRA6/BqsBWECVYs8sOWg162dI1U2QnaF+dqwiiBGum2EGrQa9Bbs+6QFr9qwisBqMGWYGt7VkzxbqduZpZd7CWKztoNeg1kBpoDawGowZeg1rBrBVErWDNIethyWpmRSA10BpYDUYNvAZZwbr3uZpZ72A1s3p2W/bVzOrrwn41s+L/IzVYFcwVWA1GDbwGswZRgjWH7KDVYKWOFWTqdU9hdakimDWIEqxpY93qW29wRNBrIDXQGlgNVgVrDNa0sW6Arc5Wz764vjpbfd3ZWp2tCFoNls5YwdJZA78WMjvwGswaLJ01VGuq2UGrQa+B1EBrsCpYY72mp7kGcU1P687Y6l/1df9r9a/uYE1PO0iddWdsdan6ui+1ulQRjBp4DWYNogRrEpprENcktINeA6mB1sBqMEqwZqS5dsmakeYa6zUj7UBqoDWwGowarI1bY71mpB1ECdaMtINWg14DqcGVuq+nLavnFUGUYE01637U6nlF0GsgNdAaWA1GDbwGswbBYPXJImg16DWQGmgNrAajBl6DWYNaQasVtFpBqxW0WkGrFbRaQasVtFpBqxW0WkGvFfRaQa8V9FpBrxX0WkGvFfRaQa8V9FqB1AqkViC1AqkVSK1AagVSK5BagdQKpFagtQKtFWitQGsFWivQWoHWCrRWoLUCrRVYrcBqBVYrsFqB1QqsVmC1AqsVWK3AagWjVjBqBaNWMGoFo1YwagWjVjBqBaNWMGoFXivwWoHXCrxW4LUCrxV4rWBNdqt7dDXNIogSrFls3Upena2+7urGPVfdQatBr4HUQGuwaosVjBp4DWYNrgpm9i3K6nlF0GrQM+grkBpoDawGowZeg1mDVYFk0F41aDXoNViirwz6+htdwRL1FXgNZg2iBPKqQavBEp0rkBpoDawGWUFbteXkgGDWICtoa3hzckDQatBrIDXQGlgNVgVreNVrMGsQJbC12fG//td/+Me//Zf/4z//93/9L//+n/77f/2Xf/nHf/yf+B/+2z/+4//2P//x//zn//ov//7f//Ef//1//Nu//Yd//P/+87/9j/xH/+3/+c//nv/97//5v77/v++t/Jd//z/f/30n/L/+9d/+5aL/9R/416+P//R9pvf7r9/neUWC9vo1Rfs4Rb6BKDO8nwMhgf/69/3jvxfb9b+fzbIAj8fbENehmhneZ0n/cBv0UINcVx6riPdjSKSIeJrh+snBneH6wQEz+C8ZxscZBvbE++4XN2LG0wR+PaNbu7INJHg/vv8lwTxsQz7FXtvwvnHyYYr4OEV/zb03r+7XD1O0w/68Gqt2jvcK78Mch73xvmW4U7xv/pXDuo9fyzgcl8YU0j7cH6ciHEf2+z6jfFzE6cAc1xOjdWC+75TTXvZrCjvs1Xxz0NqrOl8fpjhWMRuqiPlhCj8cnD22Sd+3I8bHgzFPB1fbLr3a4ZnjvX9+yXE4QK8ryD2i189Uy3Qh8uuUdThEJd/gsQbk/XgUOfTXQvph2rx+kIkZ430JeyjkcJBenc7w2+DOfT+S+zWHHHLYCzneT2e5Ma/f6jgdITH21CEx28c5DgfqdR2x63gvzj/OMU7TsJVpeHyc43CoXk/jd45ecjR/PByajUfrpPi+Of1xGXE8J8F04h8Pqby+PxzSvj8cpyNszL1GuG6Of1zGIcfI11Ku2VT1cJQej3Qcpdcj2o/rOBylOlGHvu/lfZjjOJFpx0RmYh9OZOLfz3GsowmcLxEf13E6TLthKnzfDfkwhx4OU8sfVu1zbS85+q852mnVMLFv30v+j6ZkPUymitFQ+3BOP43F+3n+ruH9+PwwFvr9HMc68ulX5rBq+z/qOMyk13Xk3q+vspL7bUF7KkPDtu2tTf+4jMMhGlj/vG85fWWfvC9PcH0ir/Gl8VTB/KU2Pt4n1k7HOJb3vRzh/dflpJ0ulKbuJZTMXxYu89cc8s1D/LQZ12vpcTYw+XhD7Ps5jtNOYPUkUTblr3brSzCVd/340LDTFDoaptBfF/m/7ZT4fo7jeOgLFwpar3j+ZirPl1ndB9j8OMfop6sNwYrD6vW8/HoxPuQHcpzqeMFv11tbP85xWpD2hgtR/eX0+FuO44K0I0ezcpruv90Y8G9Pxacyrp/s4ewo+nEZp8NUcGlvZf3Vv3rJY+PDSx5v37728tNV06uXy6Zfd+1vhcj3C9Hz5dvk4VG9/3shp+NUsXy6GrnLReBvOY6ne5wm5VWWxr/nON8mUN4mKPPpb7cJDhk8f3m17hJ4mx/eJfDDYToCQzqi3tL8bUvm6fr+hQXUNTAfbcmpDH9hXeytTkC/l9H/uWV0LKC898NonO5tOu67XM0ByGG/nq6nnZZx++iKWW/yjucZcDvu+jzXxylOl0xdeWPRPlxNztMt0heuuq6vUH1cxml1PpHDpkUp49epNA4H6PuCCVcJ9ZTwR47TFZPuI6MPL9ex8bUDIz48MM7HJ9Zg3u1jmxxzGB5B+Ogf54jjHKq8NfCyD+/3HusY3JZRduwfdfi379Y+LsP714Y0f1i0J+KPh7S9Xt98MtRe7bvPho4b4gP3nb0+V/ltQ04npey0vVNo+/jW9esHbuS/fuBO/usHbuW/TvfyHXPx+2bY4enK6wfuPbXXD1yxtNPzpqeXCq21718rtNMjp6cXC63Jt68WjoU8vVxopwdPj64XPjlYv7ugfN+h3QfI/GXf/n6onm6TiuDW4vvpsH54fd7OD54eLaLa6bHTs1XUOcWzZVQ7PnR6to5qp1vxTxdS7fSY5elKqp0eOz1dSrXTc6dna6nnB8jHi6nnR2q3w5F6TILbL+8k/nGS45Onh1tzyiHZ8bxP//7hTCb9+z0N7fTs6XFXg+j32xrO+8bRJSKzxWHfHBtFsAaYr3pL3H4z8On509P5TOa357Njiofzmb6+P5+dHj89ns9OD6Aez2cqPzCfnZ5CPZzPHh8gpxngcKTOV3/hSP3l6rD9RZJ86ehKMk5JTs+hSn/X9fLRD68Pz5XkzxdWJbM+2/u9Evv+vanjNKIN4/pe0BzOE9a/fzlyLgSX3dr8sLSy79+favbtG1TnFA+nIvv+LapmP3CPqtkP3KRq4wfuUrXx7dtUzw+QLy6tfrFMbT77m6WV8rpK++lK4vRY6umthONjqYfePdfx7auzYZgP/XXokBzHIxW3qt4DMz+eVP20XG185Pge34+n91MlQ3HlPTROlXz/nv+5EMPNiDFefihEf6CQ4yHCp0qjuPfvckzmCP0whx+nVbSIX6+U/GIOHKzXCwQ/zhHHzgcMyPt20i9tSr9NifN4tHZjml7u8f6Z5tSSgnnEfmlk++2QPz2hejg5P6xC2iHF2b0vTPBvJ8/DeByOtDl9j+oMqYP62z28eZxZe/B2opRJ/s9aTkfbYHvfKEfs+JtKzFmJhR0qOR2z3QVT4+t0nDyuZbRTLcc0fLZxcXw1zaR/dA75ehpjmuhfTiPCNHY4Yk5PsK5vMmM/hXxtPz1esYV/e1I4psAlWz9uyvG4neW4la8et8PKcTv0q7vY2fmibh8PbH/17++dPNt9b++cUzzcO+eB5e5RP5wJ++t0vDqm7PeNPvlgmjynmB2rtqnxtRSOlpPp8eFkfTyFKe7s5ReuPx6P07OsR/2dnyxR8unSXqLUbv0/CjnfHOAM64ezxidLvycPK/upKamcjlV+6bydvyU5PcpynAOvF7l8dAHZ2/j2XYp++hXVs7sU5xTP7lL006OKh3cpen99/y5FP3UUPr1L0ftPzKr9+7Pq4wMkDgfI8UBFA931XqGv5ZgTPYnxen2Y4/QbqmF4YjKsXLT9XQ6LJznO24IOkuvdGB/mkG8/dT2neGg6OT51ffQDly7fbf//pIpn1j/9hOqx9U/30tvrNZmltfjwcq2fnlI8vebrp4dQj2eQU/f9wxnkVMfza89+/CnVo2vPTyp5eu3ZT8+ynl57/kUtp2vPT9I8vRT4JM3jSwH1HzjkdP6TD7nH6/jTQ62Hi/Djxjy6KDlX8exq4rwhTy4FPhnSp3cnPk3z7O7EZ2ke3p3opwdbT+9OfDLnN14kvU+kr4+n69OzrafXJn+xsvh4tXZ6tPXox43nqxsRPD8VG4erm2MSzLJq8vFTqT5OjwueNev00/Xe02adfvyp08NmnT7ON/sfNeucx3ViAWuvdtg5p2c5z46RU4ane+b0o6vHe+b8s6uHe+b0q6sf2TP20hf2zMk2bv9M91rH1Grvp0uHMk6/DsxL9bV7e3kRwPibFHiEKvKaH6aIh4/H5cPz3nE0OJfZe0b6eDROT5PeEzofEJTXEXT9bV6ex6ZB4QXb0HZYXp1rwVulWv2B4J+1HHtcsTAqP0t5r4Sepxhokh89DilOm2J4gNqs3EX7c1Pa+fKESeSQ5PgSIGdv+qveJ/mbQ23gJQs25fXxoXb6DZY2vligbsxvNyfj+1daxyowk2lZw/9ZxbEX23mB9B5S/bCOY5IZWG6+4mVf2hisv+11GtLjGtExjby5vK1h/FWShyMyfmBEjkfqHLiekPrbtt/fDXD6Idb1LWuceF8f/5zjnKS98BKfVt+I9jdJnv7CRV7f/4XLOcezRZG8fmC5Kq8fWK7K6weWq5/s4Gc/+pHXd18ScMzw8F2Mcvw1Fm6O1C67319VcDZvlEvN+PiWxCdJTJjEP5qL5HgV8Wxl9UkdnTegw15fm+Cfbox/f2PkBzbmuCTCpowhX1xVoXO53gv8yxR4SFL6J39P8UmHPJ4KzFY7Sn9r9ZPjw6tnjzelf78JW/q3m7DPKZ49aZH+/SZs6T/QhC39B5qwRX6gCVvk203Yzw+QOBwg8u3Hm+cczx5vyukJ1sPHm5/kePR485NtefR4U77/Iyz5gR9hyQ/8CEt+4kdYov0nHizK6dHV0weLcvoZ1mPvqn3bu6c6nj/OE/XvP877i1pOj/M+SfP0cd4naZ4+zpPTa/Ue72j7djP2OcWjh2ifDezDJ4Jy+jXVs2dx5xSPnsV9sjFPn8V9mubZs7jP0jx8Fienn2U9fRb3yTT59FmcjB/oE/yL0+DHS4vT86tHd/PPS3FBiqn1R5W/L8VPT6+G4tcuo77W932g/5bk1OMneBlkSLmt+GeS00n9hVdnxCtehyTH11KW97PwCmf8ZsHTT7Our71iWisj8ldJJBpfF1ou5v9Mcvp5dkMSa3V5Mf+mEEdLa/jHhZyPNDUeabN/fKT58e4VThdtjA9/AiintwYqb7RoLxd9f0wBx6dPvGEr8zUPSebpjj5+AWTj0Pgk/vDmVZ2i5W9GFVcG19d9PxrVT36wjjtg85d3Qv7+873zu3Oe/fTuk5dFPfnpnczjay8e/fTukxyPfnon80f6BWX+QL+gzB/p05MZ33169Ekljxf20X5gYT9/pE/vkzRPfyP2SZrHK7/5I11Yn6V5uvKLH+jCOtby2AIR37/g0eMTi0cXPOcUzy54In7CzXr8UdUzN58reepmPT7XevjLuU+SPJwSnm/QcUo4p3k8JZzTPJ4SPkvzcEr4JM3DKUGPP9R6PCX8SGOmNv3+xeDx7ZRP3xr2+oEvTWk7vgBp4sWh19eF64vs5S/SzIbPA1zfELRDmuM3LB789OOT7Qn0Ilxfq/z4renaf6BDS/uPdGh9UsuzDi3t3+7QOqZ41qF13pSHHVqfjMezDi3tP9Ch9clR/1LnwVZfyfL7wXZ8heCj5shPUjxpjtTTj6aePfX+dDJ59t06Pb2EUAzTgJjah/PA8QtYj2aSYxXPvpygx9fLPf5+nsr5NcRsv6l3l2x8NUn8QJLyBZe/TPLse4B6urX79IOAenr+9fSLgHp8DeHDTwLq6fnX04/g6elzWA+/gvdJIVxqRby+OiRs9YraE/B3Sfi2+xivn0hiXztM9NXw8/yXHDbn+GWsh59K1NOnsR4fJsc3zT09TE72e/i1RLXD8WqO763abPrFnfPwM5Zq8yd2TvzAzjk+93q4c86FPPSwPXxNs4T+RJL5xST6Kq82/+rmGN8UZ/LVw4Q3vd/41c1hT43YtC8mGfiA0PuJoX7tgO0vdku/Xv7VJFjzve+ijy8nESbxH0iiX6+EV9XWvprEOCbl2dfXK5ny1RPG06mg/8RU0H9iKug/MRX0n5gK+k9MBf0npoL+A1PBeTn97KvDOp9+drjFFxcF9QF2f30tydMPMT/fnMNXlP/iYudwxRTf7zvUOH97GNOJlMn+z0IOh4lb7K3x+gT799VJHD9JiFuFbyw36H6v4/jeV9xIklf9YtzvOc5feMVN2Hb9WODjrTkNa3Zj3MPqpyvi5/cJDh+d1Jjfv3ES374Fe6zi2Y0Tex2/wsmvbb/Z9MMBsdfxucFAFq2faozxV7Xgh5ht1t9Q/VmLHu8Gs+vifWf4ozuOdnpg9ez52yd1sHvrzWWu/5sxiYburTfrOIzJ6YlxNp/fz3WsfhS0/5Ykvj8mxzocu0bmqY7jmPTOtVb9hdsfY3J61mU8TN4efh2SHO9Y4PH3e7Y9HLHHJ12TzSj1J0zx26Cc3kDytMvPTi+de9rlZ6eb08+6/Kwdv6P9rMvvmORpl5+dXkz4sMvvk0KedfmdD7SmPNDi4wcgdvzO1sMD7fR06vGBdvxh1tMD7fSZrYcHWvcfONBOSZ4faPH9A+1cyE8caOx7fD+lPMxop2dc7zL3iv691R8uX+30esLheE42XD+8QffJxky+7/V1WNycHnE93pjxT94YwcXJG+2LJywuo7Uuo//u1Kn4tYyZHiaj02+83tcdONDi8LHzT5KgZeuNX0xivAH0xi8nsfIWoX5Ypx2XNoLPqFwcX02jZdWoTb6aZki90X6oRo+TbHCSjfm1ZTDvvbx5HpbBGt9tzjimeNaccdyY/mp49HDde/y4FciOX9ySVpq1+uuj15KYfbvP8JM6+LXbduirsPMXt/CUOVrrXzlGrvvjjfe2+2FFf3w34cvYGV6/2+Ptq7XUNwL9WUt8/wp/HF/3olbu1sfBOscPb/UX77+8b5PHV9M0/C7qzYf+NRunW1uPOnk+SfGkk8dObyh81snzN+Mh9vVh5Y3Ldjolf5IGVxlvttOxEt/fO/HtvXN6S+HP7J06HmN8fe9ISeNfOx3/OqlYP1jw9KMk5Y+S1F/9w0nFx/m5G/qTXuPVf2KLhhzSnH7u9fBl6ObfvR37SRWPnh3YPL+qaPC9Wq/XwcfHD3E9W3F9Ugn38PUqhUMl326Hte+/sPC8MeWk/vZiO6y4Tj/3et93kXoz9uOBPSbpfHPSm+Pba53W9XAdd3rc9fA5hp2eyzwzzrGKh6uc07OuaymBNfV7ZXwwzulx188v/tr7svRQy/iBnePf3jnjB3ZOnB/NcufY4Vp/nF9Jh8dD1+KkPDz4apL++mISf5WmvFOS735+41wGW9h6/+WR999si3DfiJxGdXz3MvKTOnBPqUt9eelfbcwv3RVfPUQGHmb24Ydh/f63t06P28zRPWMxPv7Z0fm3S8odY79cXfx2nDX5Jyd5+J7O0Y4/I+TvfKS8dfT3N1uO9gPv2BztB96xed45wl/D//KOzT/G9buvhD8eaNLhvOuy6+My+ne/XnDMYOxEsPqrzPc9pd+SyLdPV+P4+6sX7sGO1y+3GvtfJGnOD1HPdkgyvnsh/UmKJxfSoz/92PmHF9JP9+349Ybnb6Mh318njtOrCwcX3++riVMhp+ashicX3vSU5HCkPuzwGuefTj3q8Bqnp1sPO7zG8VMsTzu8PhlWPMvx/svDur/ZN12Y5JeV5t8lwb7p07+cBEdJDzvMAA+NI61/nES//7G4od9erer3PxY3Tj+aGoLfoLy1DucIPX9/99Fvjsfx7YUPfxz7SSXPfnE8jk+kHr16+JMUT149fN6Uh784/mQ8Hg7q8ZHWw18cnxffgcvE0dphTXR6qPUjSZ6um4/PtJ6um23+wLr5+FuLx+vm40vhMQtcP3b4eFy//bmtcxl8yC6qHy/f2+k6ceKjxvHLldXrty05rgIwpqJekujfJAm8nkLqj2v/TPL99er4/np1fH+9ehoNfeGBjb7qevX30fBvv27gkxSPRsP7P3c0Gl6n92uT6x+jod8fDf3+aIx/8mgEG+TGwW4+f+DM798+85/nsHixd7G2HcpfTITaBz9+9BpfTMK3qOtoX0xi/BGQNf/i5rwfNOBGRNjhtH1qkXt62j6+SOnpafv0vOnxafv4na2fOG1r4IVZ7+cB/vG4xuu795mOj5se7pnTz7Me75njM6uneyb0n7xnWozS52cfD8n47gXiKYPjhsgs/v9zNE7T6sOPMI3j46qH+8XPz2Z+wjGCXxCpjY9nIj/9NsuG89YbU/T4LcXpruosrfa/vG1o/pZEv3mAfFJG8C0yeirjtMDkCyjKZyX9L0ZDxfmZ3doP/kcZ87vLoXMdWr7U+0ur8G91nK4/nt4M8fYDbwr7pJJnSyI/PWV6difjXMfDOxmfbMzTERnfv5NxtP+c/BzLtIP/+/H+Lt+VYvJxktODqh9J8vDk7cf32j08eXv/gc8Xe/+Bzxcfdw6/pFTfD/THqPbvfrz4fJShE2H661DEqVcFr2h4T0kfT8ynkcBDiOmH4+v0M6w2+aLBKG3b/tsOkeMXNZ41xLscb0/hl2nvvfPRF0/O2xL89mmUH9v+sS3nr8E++oDqZ0kefUD1kyTPPqB6HJLO6eNqtfx4SI4/EGj8VsKrjTqB2F+lKTNzi/h6Gn6IsZef+vxlmi6DacbHP8n08ze38AvEVn8jID7+qpZRavHDyOjxjTzs9HqVmfEvaxHcMHqz9K8Or5SdXd/K8+cmjeP5gu3o5U7vH5uk59e+Yx9p+eTd3yVRLF+b1lH5uyQ85lTjq0kCSUwPm3P64tbDX9+ed47w7fH6Ouyc02/FjW62Xtf0v33tw+385oknH3Px02Onpx9z8dPbgZ5+zMWPD69GU1wYjHZ4tbkfH19N/M6m9PT8/jmXv6nEP37lu59+kRUDQxv1Tuefm3Os5ek7r30c32mFO+r1Fet/MypPP7bjp5vqzz6288lR/+hjO5/N0/wO4Ku2of4xT58+ufXw4v6c4smzDj/9hurZs47PxkO5uhAbH4/H6adY1wHKCUk/nhqPSfilkTf6F5M8XRT4scF/cBVZXkn3d5X4LO/PP23O+IFz+THJ03P5OcnDc/k5ycNz+fz+K1s+Odbwo6P3Cfm0djx/m/zRV+M/S/LoQ+s+9fszwQ98aP18P/uFL69o14+f8fn85GMA2De1L77/toNPD7TevuHKpL434vebHqck6i++Ebn+3vz3JPHtLoFzHRM/R9HZ26GO/s+tgy/C0ajdeX/Uof/UOuyFacR6ba39o44f6BL0+IEuwU8qeXhjPL7d4neu4+mN8fiBFr/56j9wY/w4BdTWh/qT0N+Okvn9h1rH5/PKX+5budfx53R2fMUKGsG7167n35LM1z87ycMb9PP4OPrhDfrZXt+/QT9b+4Eb9Med05y/6a6/r/l9XE8Pth7dop+nB5+NPy1vUS72fvsu8jz+AIsPG5q7f5zj9JLBtsuIWX9hO/4iRZQ7p3bI8f2f68/jIy2+OKrVd5j/UcjxFYOTb5+a9vHX6Gb/gU/Gz/7tT8Y/P0Di4wPk+GNS/vrivZPkwxynJ1qDL/weFvq1Ohov86Qd6jg+1MLKzE/Hx/z+nbh5evDx9E7cPD7Yenwnbp4ebT27E/c3lRzuxM3TRc3TO3Gf1PL0Ttw8/g7r0Z24cwrlS+7jkMK/ex/ufMijO6Zewv9xyB+dx76n9630L7q3rqvK3Px7jtPjrIfu1WMfKJ4KSGuH4/T4+azOz2f12b+aBFvzzjcPSezbx8dxUB8dH+cfK0jnV4TmoT3/nCTKJy4+/sXD1O++NuiTTvBn15nTfqAB65N28ke/AjtuzNNfgfn8gUvE0/Orx78CO3dx8f2X5vWHvr8dIub/5CRPL6vsJy6rxk9cVo0fuKw675yX8sn8Lx8u+G1cx3cvq9rpEvHhnmnteD9jYEnU6i+f+98kaXwpTSu7988kp5PEs+8lz/EDTdhz/EAT9vSfaMI+XdKI8ANEWn6CHb/NRn7cwXjqVJ+Q/vaj5fPX7fHqsfeFa7kJ+FdvtlH8mvydpH+YZPrxB6m4jyC1h+rvkjQOaju8uuichCeK92PKL78yiHe96jsV/6zkuy9h+WTX8MFk/czqH2Wc3nM3HHea3h78qGnwnGKi73DMDx9ZfZICK5o3fpjifHgE16qvLx9juIp457PDkH77J62fpHjyKH/Ob/+k9TwaHZ8PfG/IV4e08zZCt69OILWSrycZTFKu//8ySUzumS9XEu37SQQvHnyfb766OTK5OfPjqeyz91PygiTqHZrfX3J5evsR37JTN+avXvv56Metn6R4ckHzyXvJcdEc9Tz1V682f9LJbd9/xYd9/xUfn3zhgB9M+uXlmH/3mQTcVLWX+xeTNOEvSbV/NQnm1HeSr371oeF+t52//3T+IRd+X68+fyDJ7F9MYriYUevtq5UEf7V4+ujKuRLlnRX96sCaMcn46hdTDCvvdyWHvXP88Jlihfg+YOta5NdrgGjf/s3gJymerEXi9Lzq4XvVH4+Gvj4ejf79bwxF/4FvDJ03hj+e1jE+3JhPkpRGvmhfTRKlUeQ0rOO71xDnFI+uIT5J8eQa4pPvLxrb797PAz/0i3z/IwKf1dFLHR+Ox7H9bjq/nPgekI/fKR1yfFvAcL4y2A/fOorTg6bOy4B3Fh6tv31H7pMcvBfxruTjHIe16vsQEl53f/xDrDh9ONjwONLq73LC/qKOh9/Ei9NS4uk38eL0cOXZN/Hi+J6+h9/EOyZ5+k28UD0urp508n5SyLNv4n1mmxEPbXNMw1c6v/mw5gw9HLAP3xwaenx32aM3h+Y3IA53vp+8OTSOD66evjn0symWC4pR7+L99m3o83sDef/89ar9L/I3SXBvo79kfDkJv9gk/gNJ9OuV4ICtDU5/mcQ4JvXp9ZcrmfJxkuPT66e7+Jzk4S7+JMmzXfw4iX69kme7+Jzk4S5+XMlpF/dv33k6p3h0t+WTFE/utsipYft9LcGfommt5PeGjU/SOH8uoW4fdyfF6QHW0/7C8ON3BJ70F55T8De2IR+m+Gxg+Yv59+jIYWO+f53k379O8m9fJ8mcP3KgndM8PtDmDzSyxvx2I+s5xbMD7ZOBfXqgTfv2gXZM8exAO6d4cqAdn5H24EPS+hnK355OHHMIThHvlbZ8mCPi2BXAz270crX22w+FP8nBD4r1cqX1R47zW5XYkf8ODsfH6TWC7zvQxjT1UvrPNMeLLVwGl7X8H54J+7btHlYh7ZDiOB6CH6S/WedhPA7unfy58Qypg/r6LUl8fzZrr3NvwLNxPZ70enCSl8PP9N+lnG8OPPjQ0yelGN8GpPUrTf8vpZwu+jpef9fqt93/clxqMaPZ4WA5rymEXZz16zV/mWbSyjqHfD0N76/P6F9OIzx/TTsdM8dGPSnfqT6cTD8xwaMTcvzMkjp+Zkl9vSrqJyaH9u1J95McPzK2Dxc71xurvrva+STHo+XOZzmerHc+OREpH0C0X/vDfx+S04OuRz3mn6w0+AHiN/ZxquQ05apyevKPp9zzEg6Lnvc9dftwCXe9BexwxDom//djwA9/3XG9PuywOc9+zfhOMk/tHU9+zvhJjme/Z3wvEc9fg3zyg8Z3kuML3J79ovF6L9rpkcqznzReb1T7ifnxeNP94fz4+ECJ04FyPGTZ5O1TvphkosXr/ST/9XGS0xOvwVftn34c+VmSR7+w/Gxz+JHp6IfN0fZ9Bx5zPHWgHl/n+ug7W+8k332jwGd1PJwJjt9iejwTHN/O93pNpmktPryOeuf5gauxd5Yfugqy13evgj6r5fllkPXvXwb9TTWn66DP8jy9EPosz9Mroc/zPLsU+jTP42uh01sIn18LnaoJ7qx4j/fBDaefcj0/vx5/y/Xw/HrM8ej64zwmf7E1P7BaOOb4ga1RxXuo38/M5mlr/Ae2xv8/3JpayZ8ePL/quLxPrf1y3f37cX98udvDq5i/Wboc1oT+3Z8fHq+mDJ9tCys/6v6rm+pD+BaEYV/MgSVljDLL/nlV56dfubLhR1r5+fCfYzp/4Kru/IOuZ2vKY46na8rZfmAtd3qY9XwtN+Unrurmj9z1mj9w1+vxgXK6qjsfsuhTlzbki0nM8MMd8/HVJOX1H19O4uU1JCO+mgTT/fsOzyHJ6Z7V44vUc5KHF6nHzZn8vdpU/4Ek1r6YZOAqSOZxTI7vz8QPRVroaTI4laJ8UbnWH1f+WUr8xD6Of/I+1tb4ZlL7+EZEO34mhx+Xb/2XVsa/GtkOC2p9j/yfpZzuIjx6c807x/GH3s9eXdPa8XtbD187c3WCHub7R++d+WRMHr14xo/ve7POL1OYHtY5x1dXfHvZ9xY3Li7sdBv9+M6Ih18KaMd3Rih/y6/1/YZ/rMrb6WlYM/52RQ57+FjJw1elvbMcP7vJJ1nvA/9Uyw98+6C1dnyXxtNXrr3znA6Yxy8p+6t6/DQrnN5XGBb4sUOdtP+2mudbdfoZ2LN3r32S49HL165mnX9ujqcz5THHozf0nffN8+P/9N7Cpx+XuJp+vj+ux8drD8f1mOPhuB6/6vUXM8LxudjP13KcDWT8xGzQf2iOOz3ZejobHHM8POL09c/N8fSo1R84as9nZjR/qhxnA9UfOTMfFz2PPhTzySH78NWhf5FFTvY5PRx7PkmefxL28HCLHzjc4gcmpvYTe+dxluPeOX2X6PnesR9YGtgPLA3s+0uDzx4SPuzD+yzP40a89iMPwtoPPAhr/+wHYX/RiddOj7EeduKdczzrxPskx3d/eeDd+Ync0iz257Xy6bWGT1vO2um1hk8fTjR/ffvhxDnHw4cT7fhaw4cPJ5rLDzycaK4/8HCind6g9Xwm8PEDM8HTA+XwcOKTQ/ZZy9k5ycOWs3b6KNfTO72fJHl2p/eTzXnWctamfN+BxxxPHXh8DvbUgfMnWr3a/JlWrzZ/otWrzZ9p9Wrx/VavT2p53OrV4idavf6immOr1yd5Hrd6fZLncavXp3ketnp9ludpq1eLn2j1OlbzuNWrv35ihdtf31/hnnM8W+Eex+QvtkZ/YGv0n7s1j1u9+st/YGv8B7bmZ5q0+vnV+w+btP7iZP/xKqqf7hd9+2md88X7Lv3jXz6/y/j+V73fSQ7rBVPM2aanZXI/Pdt6fEujt+8/0/1kUJ599Pm0d8S4d+z0JHX+zD2NT/I8vqfRe/+JObLL92eVLv/cOfIv7mn077/c8JMcz+5p9O+/3vB04MvgW/hH2Te/zwbHFHw/+iiXU39MKMePeT17mcJnSR69TeGdRH7k+qOfHow9vv7op9cb/sX1Rz89IXh4/fFJLY+vP/rpodbj64+/qOZ4/fFJnsfXH5/keXz98Wmeh9cfn+V5ev3Rjw/Lnl5/HKt57obTj8men430B9a4+v017nFr/sbbP/Azsk9qee7t88/IyqPV12lkfuTHaH+xTecZ4pzn+QxxzvN8hvgsz9MZ4pM8j2eI4wfBns8Q8jNXfOMnfpbjx7UZbjNPq5+wHo9z+AtdvP765YPcv/tyfPsz9p/lePKy9neOw7Hy7AXWxzENtG74a+ppPL79BZtzjocfJ3tPQsfPtT77Otk7y2nF+vDzZK2fn589/D7Z6XDtcN/7Oec87B4/vtnj2Vco31k+WfTuLKcvN35WyyivsW+nLH56IIirtNJE//srOM85Bt6vOuqXwf7McexrfvZJzM/G5OnIHn9M9vSjmMcHkxM/OXzz4YMYxyyz4QXUb+4ff5vjvUXfflvCcXNiYHPmq8WpkPETBjrePX3ewvhJNU8tdLrr8tRCx3v1Dy103JrHFprjJywU8k+20Hzhlv+bRzscc2HfX2OcczxbY4R/99x++qaMGHz8vhtrHxq5n34I9mgu6McvqPKOdKtfPrDxxRzx/RyqH+c4He3BtX3UH+X89jLt488AgsuTqA8L/ioHGhd7jNcP5LAPc5yuUszRYm6zXrH/nuP1A2N66rIVvCNIJPQHcsyv5VDckZFfzjN/k4MftnmjfDEHPwRbX2DwdzmMzbHTvpZj4AegMvRrx8fTzwucczz7usAnOR59XOBxDv1yHY8+LXDO8ezLAo/rOHxY4PTqQ301PKV/ycdzYZNTFpHBb4V6O2U5XWZxXm4xxinL8WeOihVrHx9+++yzUp5NiZ8Ny7NJ8W+yzK9meTgxfpLl4dT4WZZnk+NnWZ5Nj59keTpBHo4WnS/8yn62+NqJvH4Uqh9OXMcFFr4L2X/9+vhvy145PQ572nspcvq1S8dDyy4vP5Ry+onWw09CvZMcvx326JtQ7ySn7209+yhUEz2+OffhV6E+GVtxjq1/vJtPN/qeXpnI6Yb9oyuT043CNseLn/8b9vFHVa8X3p/u+OO3jU1buXUT429qwafq2/TDR2/f11DHG7HC3p33fY8Pr6Tl9AGxh8/QPqlE0Qnx5vjok9fHUYmGbwC+uX5L9M9ROT61xddm3/+wfk28/57FfmBUjpXwi5MyP67kPCq9c31Qb3H/v4zK6ReOPFTeJnydspxuELzwLFvb8bg9/VqsTbaZRKklft9Bp4ddT78Y+c5y6kx8+MnId5bjmwuefDPynUOPB9yjj0aeszz9amST0yOvh5+N/KyUZ9+N/OSIa8ojLtrpiIsfOOKOP/h6fMSdTofPj7jTtPD0iDt+CezxEXfK8vyIOz33enzEnUv5kSOOXbXa9TTHnV6N9/Db2u8kp1v/zz6u/dn24AJT5XVa95wefD3entNbFH9mewQXDW+0r57JuLLVurL9y7OqomXZTE+z0+m5igY+dvheOsmXs6Ax641fzWK80/PGr2fBrwbe2D/Mcl75CF4MeXF8MYuWVaU2+WKWIfWG0WkVdnz2NYJTbswvrZJ5F+HN87RKPj21evhk8pjj2ZPJY/vGq+EW2nWPcZ625nhV1kojVi+z3O8z/+nx19M1/7mSjjNZOz1T1NfxgwyvfehHa/0Lx8l1F7zxFnY/rPj1dexN41vlXlF/qdu+WIuKnGo5vsEDO1nqM/nf7yTo6W2K7wKs3JePcSrm1Ab7fnbNlvvX6cLskzwNv45686mPI++rfvNR9ic5Hj3Kzrtc33uU/VdjIvaNseUNxnY6QX+WB1chb7bTMdO+327wSY6H+8j/6fuojskY39hHUvL4l07Qv04x9fv1f1ZzemGR8tdw6q/+8RRzvDn+fuKG9oPXePUf2KQh/bRJerw/Hrw/LodNsm/ef/3/13YtO3LcSPBffN4Dn0nyWxaCIWu1xgCCZYztgw/+d7PHMjO7Wh2MKnIuwugVSCZZZD4jZ3Jwwf6E5kgF10bXVvDOoS8azQvjDLGpLLrNNwYIIAtKrpKmGMQgi8TwesxbH27UlGg9EQZyow3kPtcuRjFc0P3ntmoE3Xp90IpkPYXxNq1w8ROCcrAGEMzpdBtj2Nx3JICPSkEZM9oyjBsUm1anO6LgU3+Vm3ndTZw+XsMw1vYpjKLVLwVg/NPn8X7q0LKGEO5yuyeWEoeXGmLMaCnLDhmWYwRoQpRybS1Zxtba9rBTGDLShkFKAvrIcXFr0R3Uc8tFc8smDl6OUqCKFSVj6DeGNxHsBxToh5H9H28htudnlez/QLZA1AbsGO0bcbyFMpx3Q3BcJPeOAFkz3Nm26vUwxGEdEja8MQIHj47Qnbi7GFU4g+JH/rQHvTxC2eB0yQanS5adLnKD5T5W9qCPtmGDC7Q3szE4kSgoF1b8CHwXnyAKOLFs6U6ClghZupNQjxFbupNgCxhdujPRbVPKzru0z6kdClFR7lITJ1HGDoVarqOM0xJafoqSNgwDSygXJm+pzH8OfwroooUjxdh+p4Q4EOmenIksZLdTQlSKMpoMLHvPoxOKMcYVZxKE38FAq2G7nSY6oTWLTFiy2ymlDVZb8zusthZ2WG0wDUZabRG2cIyP8Fa2DKw2lMKijC5kLtU6EjV3YWp3FAJZ5WmoIyY7iSidQmmjqzS2FBHKhjRCW08jZLchjQC76tyILCdn7aWjRjLKgJEamWCQGsnvrBHvdNCUrd971EjZoJGyQSPtvTXStNpHwLeXvd/wfmZEk8i9n+hSTEoSnezUhuOliDCylvZnb0ffncFow1TL7a7a9ODOlg0PVoYUieyDlWGIgHywUOU4+4pn1ObLKyXs4N7IIbzvK+6bmLqaDJSyTGEAIcpwIav5bL6jD9QOxvKi5LDlwIYNBxZRUXWrqqlBYb22gzGe4eQw7dcz061Ko8VIcag12da274gRVt8sKEcazFzdXmtIjh00MXnGjUj5JhNZ2FcLxZRJjw1Lwnpsk/WwWoHDukiPDfXU1KqTCUy/YL+97yHyhucCtoHRzwXyP/krKeUNVxIMaplo1FO1djnKossHN3ekx2pxSAhoqI07zTBOHW9FpIkRI6wlAiEQhq9KotJMVV45biskLGQLHnOG40BGL0Kz02vlzHLamJfpm2m3elwOulmdTt3sPxu+DTmHovyL/Q5JF1HqII7rgWCXL6kl6EVyq54BakF2mvPKne682Kskn8MxV2PPmS/gjBfDBVPWfRbnjTv4XxwB/ThZYJnsaD3xthY0FjknjRhpCtKOQE4BLUZw5qI8K00c/nX/OYbLOo5mzy2vwHdWhW1aLTg0YbLHVQmm7Bw7lcwwppMoaZiTPlnNnETRw5dSu4zSBoqdy/6IUlhWANCBhbcoKjlwcmiLUEFP1m87B2tp56NLV6A7xk17yIi/kJ6HnsuOSc4Zjqzn5xbnuj6N9owsaG5xRkkWeszoRBqa9C9XyNBBzS2GstCTPTJqoCIne0w+AG5K7+zy1qkczpZQPV7edT2vMMHgYsZtPa8w00lS4yNmATpBabDbUdUbKoHbEqIov3z/sVxFoU0GzO0oamsaup2TspRqCEXhiuqOhx6i0A89RmEfeoxCPvRvV9DyQ48P3Sg47481tDChg9MM8XlL7aKb1LRS3LXy1GUTJxsuBixJUEvXJj4OoSO0yVWnF1XbVRPqcTXoqqx63VbbDHyMikOUVEbvbLIFyY8oKDlGXv1YkjpKo1MNHkkS31kS5TtIzRb/PEqS31eSnhuVYSbburdHScqGgLT4uiH0OpGFDEgLypGRAWksCRuQnqyH1UrYQZiMb4TmlKfD9vY8nJblPjB0vYWkHZn5bjbE/fYg+4sNjUuoG0LjEtqG0LhAek02NI4U64s2xjUH3o24OqnRC0pgeu3Q8608nzEtMJVDTnmXCIu7qBnTGIOcMS0RdilwVacCZ4exM6YFVmawU94l7ZiGK2l9Gi5/UMCUd3hkg9Yn9616PuVdUJaMna2OJfHqQEWPJEGm7IiTpoLOSdoR+JK0I/AlaU/gS/J64OuMLCjwJXlH4GsiDR34krwe+MIYSTlyG8JYD3vh0z/KRayP/Hj64WcYB51lj2Nf/ZatqWMu7AcQxJXIfsuIKjG6EZWP3qMTCxvDgqjLUsNllLGgDlgRSlo/J1Cz3DnBNdcxKBt5BRXGE5RmCLNB5bbA+WBcFRwuY2V9QTgfjC7DwcWwXFkRXA9dVoS1wnpxJa17cZBnlHV8YFqAdnzKjjJFKRvKFNGN4l3SLPUdr/Px66mr3beyXq8lsCVahoHibcteOIHhlUPAm919wED3ETklUFAjF10NK3VHl7jUDV3isG026iSBZCjZ2vESwN1gI8liU4MHOmhURJcGtUr3KU2E7MhFgFhEvK7EI34HyEQS9MmKV3kVRsttsIxND5wI0tLih4tVqpmv7B0SA81nLiP80g/+0wI2jFFHEZzU58mQCcZ4wvuPT0lz4PFoaqE5uXjEhv3c4QD9R3HriYMJBpUzLqh7i0sNQX2EMZOor+SiToP60uGO1z5ek+MyhiiG8X/PYbSqu3JVjuaXMeLgMOr3+8W1xKprqeAam9Fdqe3dbHzigTQLxeWUlcGu5hyVGNnFHddTMBMO1OEpNvtMneNRpcqKMcstp48JBqWPCaeyTnC449s6ycw8AozZlXIVxY96huxTuIwy7tWOcplr2o8IcMYzKSAfeFI+cFuSv4BSw1WUPFyJlIO/LMt4xztguixL0rBCuqzdnBVFLnO252H8dlngHsEuoWEx3jgvzX19iECVuF5KMMHgbJO43hXOayQ5pBE0LpycEFBQkoufEID72kaEI4k8X88ExdSPNX8ZpZmSBqRblCkjvQuMwXkXEwzGu5jNispa9NWTZs+/nSQbzv1EkmAkATqBBVtFxzx1pQDq4QLJDoMU5V0saPZCgVku9RM6jJ7b46ybCcigGrvJAkBQjitIVN8ctAwV1BqWR9Yu29aRls9Iwo7uKai8jx7dUzIMnVCjewqkPWRH90AUenRPyZAvgqsnnYhCju6ZfULSyE8I45So3P4FmaYFxetZZroC52iRzHRlEp2mmOkKii2fGCo5uXbV3hAb+Tte3nCkOTkqeobCDYueolDjok+gpAVZqJHRMxRuaPQJWdDYaFnfZ4zB7fIEg9pjGiNdloPaX4zB7S4tB9hbH1BChAxYYQwuQDPBoAI0AaVE2bVADHItZZ2QAyFUGWZ+E5uIPD4XsF2LTCNiEDLlXbZwH5Yt3IdlB/ehD8j9udEVF+PjgpK4CU7RdpNUMiggKzDtxBaElgYrpqiCUIyhHcgtPseYaVfZBbqGQMlUdW7ZbccYnNs+waDc9oAph/gTh3HoE1cRHSJ94iqcBsadOIxBnriJdvkT1zacuLbhxLVLJ+5D/83HTy+vP375+unj7y9ff/mt/7+/blCvLx9/+vL522///8cvn8zf/v7nr//+zU+vL1++vPz846+vXz99/t8fr59vSLe/+8F9++W/PrruCPZfa/nwnx/i25/4/oXcxp24/ifef/tHcvtHUj/8dZPrbw=="}],"outputs":{"structs":{"functions":[{"kind":"struct","path":"AuthorizeOnceBeforeExternal::foo_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::foo_parameters","fields":[{"name":"from","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"authwit_nonce","type":{"kind":"field"}}]}}]},{"kind":"struct","path":"AuthorizeOnceBeforeExternal::offchain_receive_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::offchain_receive_parameters","fields":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]},{"kind":"struct","path":"AuthorizeOnceBeforeExternal::sync_state_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::sync_state_parameters","fields":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}]},"globals":{}},"file_map":{"3":{"source":"use crate::cmp::{Eq, Ord};\nuse crate::convert::From;\nuse crate::runtime::is_unconstrained;\n\nmod check_shuffle;\nmod quicksort;\n\nimpl [T; N] {\n /// Returns the length of this array.\n ///\n /// ```noir\n /// fn len(self) -> Field\n /// ```\n ///\n /// example\n ///\n /// ```noir\n /// fn main() {\n /// let array = [42, 42];\n /// assert(array.len() == 2);\n /// }\n /// ```\n #[builtin(array_len)]\n pub fn len(self) -> u32 {}\n\n /// Returns this array as a vector.\n ///\n /// ```noir\n /// let array = [1, 2];\n /// let vector = array.as_vector();\n /// assert_eq(vector, [1, 2].as_vector());\n /// ```\n #[builtin(as_vector)]\n pub fn as_vector(self) -> [T] {}\n\n /// Returns this array as a vector.\n /// This method is deprecated in favor of `as_vector`.\n ///\n /// ```noir\n /// let array = [1, 2];\n /// let vector = array.as_slice();\n /// assert_eq(vector, [1, 2].as_vector());\n /// ```\n #[builtin(as_vector)]\n #[deprecated(\"This method has been renamed to `as_vector`\")]\n pub fn as_slice(self) -> [T] {}\n\n /// Applies a function to each element of this array, returning a new array containing the mapped elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let b = a.map(|a| a * 2);\n /// assert_eq(b, [2, 4, 6]);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> [U; N] {\n let uninitialized = crate::mem::zeroed();\n let mut ret = [uninitialized; N];\n\n for i in 0..self.len() {\n ret[i] = f(self[i]);\n }\n\n ret\n }\n\n /// Applies a function to each element of this array along with its index,\n /// returning a new array containing the mapped elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let b = a.mapi(|i, a| i + a * 2);\n /// assert_eq(b, [2, 5, 8]);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> [U; N] {\n let uninitialized = crate::mem::zeroed();\n let mut ret = [uninitialized; N];\n\n for i in 0..self.len() {\n ret[i] = f(i, self[i]);\n }\n\n ret\n }\n\n /// Applies a function to each element of this array.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let mut b = [0; 3];\n /// let mut i = 0;\n /// a.for_each(|x| {\n /// b[i] = x;\n /// i += 1;\n /// });\n /// assert_eq(a, b);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n for i in 0..self.len() {\n f(self[i]);\n }\n }\n\n /// Applies a function to each element of this array along with its index.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let mut b = [0; 3];\n /// a.for_eachi(|i, x| {\n /// b[i] = x;\n /// });\n /// assert_eq(a, b);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n for i in 0..self.len() {\n f(i, self[i]);\n }\n }\n\n /// Applies a function to each element of the array, returning the final accumulated value. The first\n /// parameter is the initial value.\n ///\n /// This is a left fold, so the given function will be applied to the accumulator and first element of\n /// the array, then the second, and so on. For a given call the expected result would be equivalent to:\n ///\n /// ```rust\n /// let a1 = [1];\n /// let a2 = [1, 2];\n /// let a3 = [1, 2, 3];\n ///\n /// let f = |a, b| a - b;\n /// a1.fold(10, f); //=> f(10, 1)\n /// a2.fold(10, f); //=> f(f(10, 1), 2)\n /// a3.fold(10, f); //=> f(f(f(10, 1), 2), 3)\n ///\n /// assert_eq(a3.fold(10, f), 10 - 1 - 2 - 3);\n /// ```\n pub fn fold(&self, mut accumulator: U, f: fn[Env](U, T) -> U) -> U {\n for elem in self {\n accumulator = f(accumulator, elem);\n }\n accumulator\n }\n\n /// Same as fold, but uses the first element as the starting element.\n ///\n /// Requires the input array to be non-empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [1, 2, 3, 4];\n /// let reduced = arr.reduce(|a, b| a + b);\n /// assert(reduced == 10);\n /// }\n /// ```\n pub fn reduce(&self, f: fn[Env](T, T) -> T) -> T {\n let mut accumulator = self[0];\n for i in 1..self.len() {\n accumulator = f(accumulator, self[i]);\n }\n accumulator\n }\n\n /// Returns true if all the elements in this array satisfy the given predicate.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [2, 2, 2, 2, 2];\n /// let all = arr.all(|a| a == 2);\n /// assert(all);\n /// }\n /// ```\n pub fn all(&self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = true;\n for elem in self {\n ret &= predicate(elem);\n }\n ret\n }\n\n /// Returns true if any of the elements in this array satisfy the given predicate.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [2, 2, 2, 2, 5];\n /// let any = arr.any(|a| a == 5);\n /// assert(any);\n /// }\n /// ```\n pub fn any(&self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n for elem in self {\n ret |= predicate(elem);\n }\n ret\n }\n\n /// Concatenates this array with another array.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr1 = [1, 2, 3, 4];\n /// let arr2 = [6, 7, 8, 9, 10, 11];\n /// let concatenated_arr = arr1.concat(arr2);\n /// assert(concatenated_arr == [1, 2, 3, 4, 6, 7, 8, 9, 10, 11]);\n /// }\n /// ```\n pub fn concat(&self, array2: [T; M]) -> [T; N + M] {\n let mut result = [crate::mem::zeroed(); N + M];\n for i in 0..N {\n result[i] = self[i];\n }\n for i in 0..M {\n result[i + N] = array2[i];\n }\n result\n }\n}\n\nimpl [T; N]\nwhere\n T: Ord + Eq,\n{\n /// Returns a new sorted array. The original array remains untouched. Notice that this function will\n /// only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting\n /// logic it uses internally is optimized specifically for these values. If you need a sort function to\n /// sort any type, you should use the [`Self::sort_via`] function.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let arr = [42, 32];\n /// let sorted = arr.sort();\n /// assert(sorted == [32, 42]);\n /// }\n /// ```\n pub fn sort(&self) -> Self {\n self.sort_via(|a, b| a <= b)\n }\n}\n\nimpl [T; N]\nwhere\n T: Eq,\n{\n /// Returns a new sorted array by sorting it with a custom comparison function.\n /// The original array remains untouched.\n /// The ordering function must return true if the first argument should be sorted to be before the second argument or is equal to the second argument.\n ///\n /// Using this method with an operator like `<` that does not return `true` for equal values will result in an assertion failure for arrays with equal elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let arr = [42, 32]\n /// let sorted_ascending = arr.sort_via(|a, b| a <= b);\n /// assert(sorted_ascending == [32, 42]); // verifies\n ///\n /// let sorted_descending = arr.sort_via(|a, b| a >= b);\n /// assert(sorted_descending == [32, 42]); // does not verify\n /// }\n /// ```\n pub fn sort_via(&self, ordering: fn[Env](T, T) -> bool) -> Self {\n // Safety: `sorted` array is checked to be:\n // a. a permutation of `input`'s elements\n // b. satisfying the predicate `ordering`\n let sorted = unsafe { quicksort::quicksort(self, ordering) };\n\n if !is_unconstrained() {\n for i in 0..N - 1 {\n assert(\n ordering(sorted[i], sorted[i + 1]),\n \"Array has not been sorted correctly according to `ordering`.\",\n );\n }\n check_shuffle::check_shuffle(self, &sorted);\n }\n sorted\n }\n}\n\nimpl [u8; N] {\n /// Converts a byte array of type `[u8; N]` to a string. Note that this performs no UTF-8 validation -\n /// the given array is interpreted as-is as a string.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let hi = [104, 105].as_str_unchecked();\n /// assert_eq(hi, \"hi\");\n /// }\n /// ```\n #[builtin(array_as_str_unchecked)]\n pub fn as_str_unchecked(self) -> str {}\n}\n\nimpl From> for [u8; N] {\n /// Returns an array of the string bytes.\n fn from(s: str) -> Self {\n s.as_bytes()\n }\n}\n\nmod test {\n #[test]\n fn map_empty() {\n assert_eq([].map(|x| x + 1), []);\n }\n\n global arr_with_100_values: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2, 54,\n 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41, 19, 98,\n 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21, 43, 86, 35,\n 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15, 127, 81, 30, 8,\n 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n global expected_with_100_values: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30, 32,\n 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58, 61, 62,\n 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82, 84, 84, 86,\n 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114, 114, 116, 118,\n 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n fn sort_u32(a: u32, b: u32) -> bool {\n a <= b\n }\n\n #[test]\n fn test_sort() {\n let arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = arr.sort();\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_100_values() {\n let arr: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2,\n 54, 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41,\n 19, 98, 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21,\n 43, 86, 35, 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15,\n 127, 81, 30, 8, 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n\n let sorted = arr.sort();\n\n let expected: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30,\n 32, 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58,\n 61, 62, 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82,\n 84, 84, 86, 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114,\n 114, 116, 118, 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_100_values_comptime() {\n let sorted = arr_with_100_values.sort();\n assert(sorted == expected_with_100_values);\n }\n\n #[test]\n fn test_sort_via() {\n let arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = arr.sort_via(sort_u32);\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_via_100_values() {\n let arr: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2,\n 54, 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41,\n 19, 98, 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21,\n 43, 86, 35, 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15,\n 127, 81, 30, 8, 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n\n let sorted = arr.sort_via(sort_u32);\n\n let expected: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30,\n 32, 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58,\n 61, 62, 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82,\n 84, 84, 86, 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114,\n 114, 116, 118, 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n assert(sorted == expected);\n }\n\n #[test]\n fn mapi_empty() {\n assert_eq([].mapi(|i, x| i * x + 1), []);\n }\n\n #[test]\n fn for_each_empty() {\n let empty_array: [Field; 0] = [];\n empty_array.for_each(|_x| assert(false));\n }\n\n #[test]\n fn for_eachi_empty() {\n let empty_array: [Field; 0] = [];\n empty_array.for_eachi(|_i, _x| assert(false));\n }\n\n #[test]\n fn map_example() {\n let a = [1, 2, 3];\n let b = a.map(|a| a * 2);\n assert_eq(b, [2, 4, 6]);\n }\n\n #[test]\n fn mapi_example() {\n let a = [1, 2, 3];\n let b = a.mapi(|i, a| i + a * 2);\n assert_eq(b, [2, 5, 8]);\n }\n\n #[test]\n fn for_each_example() {\n let a = [1, 2, 3];\n let mut b = [0, 0, 0];\n let b_ref = &mut b;\n let mut i = 0;\n let i_ref = &mut i;\n a.for_each(|x| {\n b_ref[*i_ref] = x * 2;\n *i_ref += 1;\n });\n assert_eq(b, [2, 4, 6]);\n assert_eq(i, 3);\n }\n\n #[test]\n fn for_eachi_example() {\n let a = [1, 2, 3];\n let mut b = [0, 0, 0];\n let b_ref = &mut b;\n a.for_eachi(|i, a| { b_ref[i] = i + a * 2; });\n assert_eq(b, [2, 5, 8]);\n }\n\n #[test]\n fn concat() {\n let arr1 = [1, 2, 3, 4];\n let arr2 = [6, 7, 8, 9, 10, 11];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1, 2, 3, 4, 6, 7, 8, 9, 10, 11]);\n }\n\n #[test]\n fn concat_zero_length_with_something() {\n let arr1 = [];\n let arr2 = [1];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1]);\n }\n\n #[test]\n fn concat_something_with_zero_length() {\n let arr1 = [1];\n let arr2 = [];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1]);\n }\n\n #[test]\n fn concat_zero_lengths() {\n let arr1: [Field; 0] = [];\n let arr2: [Field; 0] = [];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, []);\n }\n}\n","path":"std/array/mod.nr","function_locations":[{"start":480,"name":"[T; N]::len"},{"start":735,"name":"[T; N]::as_vector"},{"start":1112,"name":"[T; N]::as_slice"},{"start":1443,"name":"[T; N]::map"},{"start":2004,"name":"[T; N]::mapi"},{"start":2552,"name":"[T; N]::for_each"},{"start":2970,"name":"[T; N]::for_eachi"},{"start":3837,"name":"[T; N]::fold"},{"start":4355,"name":"[T; N]::reduce"},{"start":4865,"name":"[T; N]::all"},{"start":5338,"name":"[T; N]::any"},{"start":5881,"name":"[T; N]::concat"},{"start":6778,"name":"[T; N]::sort"},{"start":7794,"name":"[T; N]::sort_via"},{"start":8823,"name":"[u8; N]::as_str_unchecked"},{"start":8950,"name":"> for [u8; N]>::from"},{"start":9024,"name":"test::map_empty"},{"start":10134,"name":"test::sort_u32"},{"start":10189,"name":"test::test_sort"},{"start":10420,"name":"test::test_sort_100_values"},{"start":11588,"name":"test::test_sort_100_values_comptime"},{"start":11733,"name":"test::test_sort_via"},{"start":11980,"name":"test::test_sort_via_100_values"},{"start":13141,"name":"test::mapi_empty"},{"start":13236,"name":"test::for_each_empty"},{"start":13374,"name":"test::for_eachi_empty"},{"start":13513,"name":"test::map_example"},{"start":13650,"name":"test::mapi_example"},{"start":13799,"name":"test::for_each_example"},{"start":14139,"name":"test::for_eachi_example"},{"start":14350,"name":"test::concat"},{"start":14609,"name":"test::concat_zero_length_with_something"},{"start":14812,"name":"test::concat_something_with_zero_length"},{"start":15001,"name":"test::concat_zero_lengths"}]},"5":{"source":"use crate::meta::ctstring::AsCtString;\nuse crate::meta::derive_via;\n\n/// Compare two values for equality\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n if result {\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\ncomptime fn make_tuple_eq_body(n: u32) -> Quoted {\n let mut body = f\"self.0.eq(other.0)\".as_ctstring();\n for i in 1u32..n {\n body = body.append_fmtstr(f\" & self.{i}.eq(other.{i})\");\n }\n f\"{body}\".quoted_contents()\n}\n\nimpl Eq for (A, B) {\n fn eq(self, other: (A, B)) -> bool {\n make_tuple_eq_body!(2u32)\n }\n}\n\nimpl Eq for (A, B, C) {\n fn eq(self, other: (A, B, C)) -> bool {\n make_tuple_eq_body!(3u32)\n }\n}\n\nimpl Eq for (A, B, C, D) {\n fn eq(self, other: (A, B, C, D)) -> bool {\n make_tuple_eq_body!(4u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E) {\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n make_tuple_eq_body!(5u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F) {\n fn eq(self, other: (A, B, C, D, E, F)) -> bool {\n make_tuple_eq_body!(6u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G) {\n fn eq(self, other: (A, B, C, D, E, F, G)) -> bool {\n make_tuple_eq_body!(7u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H) {\n fn eq(self, other: (A, B, C, D, E, F, G, H)) -> bool {\n make_tuple_eq_body!(8u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I)) -> bool {\n make_tuple_eq_body!(9u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J)) -> bool {\n make_tuple_eq_body!(10u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J, K) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> bool {\n make_tuple_eq_body!(11u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> bool {\n make_tuple_eq_body!(12u32)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\n/// A value with three states: `Ordering::less()`, `Ordering::equal()` or `Ordering::greater()`.\n/// Most often used to encode the result of a comparison operation.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n/// Compare one object to another, returning whether it is less-than, equal-to,\n/// or greater-than the other object.\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let self_len = self.len();\n let other_len = other.len();\n let min_len = if self_len < other_len {\n self_len\n } else {\n other_len\n };\n\n let mut result = Ordering::equal();\n for i in 0..min_len {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n\n if result != Ordering::equal() {\n result\n } else {\n self_len.cmp(other_len)\n }\n }\n}\n\ncomptime fn make_tuple_ord_body(n: u32) -> Quoted {\n let last = n - 1u32;\n let mut body = if last == 1 {\n f\"let result = self.0.cmp(other.0);\".as_ctstring()\n } else {\n f\"let mut result = self.0.cmp(other.0);\".as_ctstring()\n };\n for i in 1u32..last {\n body = body.append_fmtstr(\n f\" if result == Ordering::equal() {{ result = self.{i}.cmp(other.{i}); }}\",\n );\n }\n body = body.append_fmtstr(\n f\" if result != Ordering::equal() {{ result }} else {{ self.{last}.cmp(other.{last}) }}\",\n );\n f\"{body}\".quoted_contents()\n}\n\nimpl Ord for (A, B) {\n fn cmp(self, other: (A, B)) -> Ordering {\n make_tuple_ord_body!(2u32)\n }\n}\n\nimpl Ord for (A, B, C) {\n fn cmp(self, other: (A, B, C)) -> Ordering {\n make_tuple_ord_body!(3u32)\n }\n}\n\nimpl Ord for (A, B, C, D) {\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n make_tuple_ord_body!(4u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E) {\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n make_tuple_ord_body!(5u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F) {\n fn cmp(self, other: (A, B, C, D, E, F)) -> Ordering {\n make_tuple_ord_body!(6u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G) {\n fn cmp(self, other: (A, B, C, D, E, F, G)) -> Ordering {\n make_tuple_ord_body!(7u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H)) -> Ordering {\n make_tuple_ord_body!(8u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I)) -> Ordering {\n make_tuple_ord_body!(9u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J)) -> Ordering {\n make_tuple_ord_body!(10u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J, K) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> Ordering {\n make_tuple_ord_body!(11u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> Ordering {\n make_tuple_ord_body!(12u32)\n }\n}\n\n/// Compares and returns the maximum of two values.\n///\n/// Returns the second argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::max(1, 2), 2);\n/// assert_eq(cmp::max(2, 2), 2);\n/// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n/// Compares and returns the minimum of two values.\n///\n/// Returns the first argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::min(1, 2), 1);\n/// assert_eq(cmp::min(2, 2), 2);\n/// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use super::{Eq, max, min, Ord};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n\n #[test]\n fn correctly_handles_unequal_length_vectors() {\n let vector_1 = [0, 1, 2, 3].as_vector();\n let vector_2 = [0, 1, 2].as_vector();\n assert(!vector_1.eq(vector_2));\n }\n\n #[test]\n fn lexicographic_ordering_for_vectors() {\n assert(\n [2_u32].as_vector().cmp([1_u32, 1_u32, 1_u32].as_vector())\n == super::Ordering::greater(),\n );\n assert(\n [1_u32, 2_u32].as_vector().cmp([1_u32, 2_u32, 3_u32].as_vector())\n == super::Ordering::less(),\n );\n }\n}\n","path":"std/cmp.nr","function_locations":[{"start":305,"name":"derive_eq"},{"start":851,"name":"::eq"},{"start":940,"name":"::eq"},{"start":1026,"name":"::eq"},{"start":1112,"name":"::eq"},{"start":1198,"name":"::eq"},{"start":1282,"name":"::eq"},{"start":1366,"name":"::eq"},{"start":1452,"name":"::eq"},{"start":1538,"name":"::eq"},{"start":1624,"name":"::eq"},{"start":1717,"name":"::eq"},{"start":1796,"name":"::eq"},{"start":1921,"name":"::eq"},{"start":2139,"name":"::eq"},{"start":2418,"name":">::eq"},{"start":2598,"name":"make_tuple_eq_body"},{"start":2859,"name":"::eq"},{"start":2991,"name":"::eq"},{"start":3136,"name":"::eq"},{"start":3294,"name":"::eq"},{"start":3465,"name":"::eq"},{"start":3649,"name":"::eq"},{"start":3846,"name":"::eq"},{"start":4056,"name":"::eq"},{"start":4279,"name":"::eq"},{"start":4516,"name":"::eq"},{"start":4766,"name":"::eq"},{"start":4876,"name":"::eq"},{"start":5477,"name":"Ordering::less"},{"start":5548,"name":"Ordering::equal"},{"start":5621,"name":"Ordering::greater"},{"start":5992,"name":"derive_ord"},{"start":6642,"name":"::cmp"},{"start":6889,"name":"::cmp"},{"start":7137,"name":"::cmp"},{"start":7385,"name":"::cmp"},{"start":7631,"name":"::cmp"},{"start":7877,"name":"::cmp"},{"start":8125,"name":"::cmp"},{"start":8373,"name":"::cmp"},{"start":8621,"name":"::cmp"},{"start":8875,"name":"::cmp"},{"start":8974,"name":"::cmp"},{"start":9444,"name":"::cmp"},{"start":9847,"name":"::cmp"},{"start":10415,"name":"make_tuple_ord_body"},{"start":11037,"name":"::cmp"},{"start":11179,"name":"::cmp"},{"start":11335,"name":"::cmp"},{"start":11505,"name":"::cmp"},{"start":11689,"name":"::cmp"},{"start":11887,"name":"::cmp"},{"start":12099,"name":"::cmp"},{"start":12325,"name":"::cmp"},{"start":12565,"name":"::cmp"},{"start":12820,"name":"::cmp"},{"start":13089,"name":"::cmp"},{"start":13451,"name":"max"},{"start":13828,"name":"min"},{"start":13982,"name":"cmp_tests::sanity_check_min"},{"start":14178,"name":"cmp_tests::sanity_check_max"},{"start":14400,"name":"cmp_tests::correctly_handles_unequal_length_vectors"},{"start":14600,"name":"cmp_tests::lexicographic_ordering_for_vectors"}]},"6":{"source":"use crate::{cmp::Eq, convert::From, runtime::is_unconstrained, static_assert};\n\n/// A `BoundedVec` is a growable storage similar to a built-in vector except that it\n/// is bounded with a maximum possible length. `BoundedVec` is also not\n/// subject to the same restrictions vectors are (notably, nested vectors are disallowed).\n///\n/// Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by\n/// pushing an additional element is also more efficient - the length only needs to be increased\n/// by one.\n///\n/// For these reasons `BoundedVec` should generally be preferred over vectors when there\n/// is a reasonable maximum bound that can be placed on the vector.\n///\n/// Example:\n///\n/// ```noir\n/// let mut vector: BoundedVec = BoundedVec::new();\n/// for i in 0..5 {\n/// vector.push(i);\n/// }\n/// assert(vector.len() == 5);\n/// assert(vector.max_len() == 10);\n/// ```\npub struct BoundedVec {\n storage: [T; MaxLen],\n len: u32,\n}\n\nimpl BoundedVec {\n /// Creates a new, empty vector of length zero.\n ///\n /// Since this container is backed by an array internally, it still needs an initial value\n /// to give each element. To resolve this, each element is zeroed internally. This value\n /// is guaranteed to be inaccessible unless `get_unchecked` is used.\n ///\n /// Example:\n ///\n /// ```noir\n /// let empty_vector: BoundedVec = BoundedVec::new();\n /// assert(empty_vector.len() == 0);\n /// ```\n ///\n /// Note that whenever calling `new` the maximum length of the vector should always be specified\n /// via a type signature:\n ///\n /// ```noir\n /// fn good() -> BoundedVec {\n /// // Ok! MaxLen is specified with a type annotation\n /// let v1: BoundedVec = BoundedVec::new();\n /// let v2 = BoundedVec::new();\n ///\n /// // Ok! MaxLen is known from the type of `good`'s return value\n /// v2\n /// }\n ///\n /// fn bad() {\n /// // Error: Type annotation needed\n /// // The compiler can't infer `MaxLen` from the following code:\n /// let mut v3 = BoundedVec::new();\n /// v3.push(5);\n /// }\n /// ```\n ///\n /// This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions\n /// but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a\n /// constraint failure at runtime when the vec is pushed to.\n pub fn new() -> Self {\n let zeroed = crate::mem::zeroed();\n BoundedVec { storage: [zeroed; MaxLen], len: 0 }\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this\n /// will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// let last = v.get(v.len() - 1);\n /// assert(first != last);\n /// }\n /// ```\n pub fn get(&self, index: u32) -> T {\n assert(index < self.len, \"Attempted to read past end of BoundedVec\");\n self.get_unchecked(index)\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero, without\n /// performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element,\n /// it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn sum_of_first_three(v: BoundedVec) -> u32 {\n /// // Always ensure the length is larger than the largest\n /// // index passed to get_unchecked\n /// assert(v.len() > 2);\n /// let first = v.get_unchecked(0);\n /// let second = v.get_unchecked(1);\n /// let third = v.get_unchecked(2);\n /// first + second + third\n /// }\n /// ```\n pub fn get_unchecked(&self, index: u32) -> T {\n self.storage[index]\n }\n\n /// Writes an element to the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// assert(first != 42);\n /// v.set(0, 42);\n /// let new_first = v.get(0);\n /// assert(new_first == 42);\n /// }\n /// ```\n pub fn set(&mut self, index: u32, value: T) {\n assert(index < self.len, \"Attempted to write past end of BoundedVec\");\n self.set_unchecked(index, value)\n }\n\n /// Writes an element to the vector at the given index, starting from zero, without performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element, it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn set_unchecked_example() {\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([1, 2]);\n ///\n /// // Here we're safely writing within the valid range of `vec`\n /// // `vec` now has the value [42, 2]\n /// vec.set_unchecked(0, 42);\n ///\n /// // We can then safely read this value back out of `vec`.\n /// // Notice that we use the checked version of `get` which would prevent reading unsafe values.\n /// assert_eq(vec.get(0), 42);\n ///\n /// // We've now written past the end of `vec`.\n /// // As this index is still within the maximum potential length of `v`,\n /// // it won't cause a constraint failure.\n /// vec.set_unchecked(2, 42);\n /// println(vec);\n ///\n /// // This will write past the end of the maximum potential length of `vec`,\n /// // it will then trigger a constraint failure.\n /// vec.set_unchecked(5, 42);\n /// println(vec);\n /// }\n /// ```\n pub fn set_unchecked(&mut self, index: u32, value: T) {\n self.storage[index] = value;\n }\n\n /// Pushes an element to the end of the vector. This increases the length\n /// of the vector by one.\n ///\n /// Panics if the new length of the vector will be greater than the max length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// v.push(1);\n /// v.push(2);\n ///\n /// // Panics with failed assertion \"push out of bounds\"\n /// v.push(3);\n /// ```\n pub fn push(&mut self, elem: T) {\n assert(self.len < MaxLen, \"push out of bounds\");\n\n self.storage[self.len] = elem;\n self.len += 1;\n }\n\n /// Returns the current length of this vector\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// assert(v.len() == 0);\n ///\n /// v.push(100);\n /// assert(v.len() == 1);\n ///\n /// v.push(200);\n /// v.push(300);\n /// v.push(400);\n /// assert(v.len() == 4);\n ///\n /// let _ = v.pop();\n /// let _ = v.pop();\n /// assert(v.len() == 2);\n /// ```\n pub fn len(&self) -> u32 {\n self.len\n }\n\n /// Returns the maximum length of this vector. This is always\n /// equal to the `MaxLen` parameter this vector was initialized with.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.max_len() == 5);\n /// v.push(10);\n /// assert(v.max_len() == 5);\n /// ```\n pub fn max_len(_self: &BoundedVec) -> u32 {\n MaxLen\n }\n\n /// Returns the internal array within this vector.\n ///\n /// Since arrays in Noir are immutable, mutating the returned storage array will not mutate\n /// the storage held internally by this vector.\n ///\n /// Note that uninitialized elements may be zeroed out!\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.storage() == [0, 0, 0, 0, 0]);\n ///\n /// v.push(57);\n /// assert(v.storage() == [57, 0, 0, 0, 0]);\n /// ```\n pub fn storage(&self) -> [T; MaxLen] {\n self.storage\n }\n\n /// Pushes each element from the given array to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([2, 4]);\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_array(&mut self, array: [T; Len]) {\n let new_len = self.len + array.len();\n assert(new_len <= MaxLen, \"extend_from_array out of bounds\");\n for i in 0..array.len() {\n self.storage[self.len + i] = array[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the given vector to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_vector([2, 4].as_vector());\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_vector(&mut self, vector: [T]) {\n let new_len = self.len + vector.len();\n assert(new_len <= MaxLen, \"extend_from_vector out of bounds\");\n for i in 0..vector.len() {\n self.storage[self.len + i] = vector[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the other vector to this vector. The length of\n /// the other vector is left unchanged.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// ```noir\n /// let mut v1: BoundedVec = BoundedVec::new();\n /// let mut v2: BoundedVec = BoundedVec::new();\n ///\n /// v2.extend_from_array([1, 2, 3]);\n /// v1.extend_from_bounded_vec(v2);\n ///\n /// assert(v1.storage() == [1, 2, 3, 0, 0]);\n /// assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]);\n /// ```\n pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) {\n let append_len = vec.len();\n let new_len = self.len + append_len;\n assert(new_len <= MaxLen, \"extend_from_bounded_vec out of bounds\");\n\n if is_unconstrained() {\n for i in 0..append_len {\n self.storage[self.len + i] = vec.get_unchecked(i);\n }\n } else {\n // The source vector can be longer than the destination, or vice versa;\n // regardless we will only ever be able to read or write whichever is\n // the shorter max length of the two. We asserted that the actual content fits,\n // but the capacity of the source vector could be higher.\n let max = crate::cmp::min(Len, MaxLen);\n\n // Save the last item in case we have to do a fixup on an already full array.\n let last = if MaxLen > 0 {\n self.storage[MaxLen - 1]\n } else {\n crate::mem::zeroed()\n };\n\n for src in 0..max {\n // Since we are iterating to the static capacity of the arrays,\n // the destination could be out of bounds. If that's the case,\n // overwrite the last item, which we'll fixup in the end.\n // NB using cmp::min resulted in more opcodes here.\n let mut dst = self.len + src;\n if dst >= MaxLen { dst = MaxLen - 1; };\n // Assigning the source or zeroed to avoid having to merge arrays in SSA.\n self.storage[dst] = if src < append_len {\n vec.get_unchecked(src)\n } else {\n last\n }\n }\n\n // Fixup the last item if we have to.\n if MaxLen > 0 {\n self.storage[MaxLen - 1] = if (self.len + append_len == MaxLen) & (append_len > 0) {\n vec.get_unchecked(append_len - 1)\n } else {\n last\n }\n }\n }\n self.len = new_len;\n }\n\n /// Creates a new vector, populating it with values derived from an array input.\n /// The maximum length of the vector is determined based on the type signature.\n ///\n /// Example:\n ///\n /// ```noir\n /// let bounded_vec: BoundedVec = BoundedVec::from_array([1, 2, 3])\n /// ```\n pub fn from_array(array: [T; Len]) -> Self {\n static_assert(Len <= MaxLen, \"from array out of bounds\");\n let mut vec: BoundedVec = BoundedVec::new();\n vec.extend_from_array(array);\n vec\n }\n\n /// Pops the element at the end of the vector. This will decrease the length\n /// of the vector by one.\n ///\n /// Panics if the vector is empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.push(1);\n /// v.push(2);\n ///\n /// let two = v.pop();\n /// let one = v.pop();\n ///\n /// assert(two == 2);\n /// assert(one == 1);\n ///\n /// // error: cannot pop from an empty vector\n /// let _ = v.pop();\n /// ```\n pub fn pop(&mut self) -> T {\n assert(self.len > 0, \"cannot pop from an empty vector\");\n self.len -= 1;\n\n let elem = self.storage[self.len];\n self.storage[self.len] = crate::mem::zeroed();\n elem\n }\n\n /// Returns true if the given predicate returns true for any element\n /// in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.extend_from_array([2, 4, 6]);\n ///\n /// let all_even = !v.any(|elem: u32| elem % 2 != 0);\n /// assert(all_even);\n /// ```\n pub fn any(self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n if is_unconstrained() {\n for i in 0..self.len {\n ret |= predicate(self.storage[i]);\n }\n } else {\n let mut exceeded_len = false;\n for i in 0..MaxLen {\n exceeded_len |= i == self.len;\n if !exceeded_len {\n ret |= predicate(self.storage[i]);\n }\n }\n }\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.map(|value| value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element\n /// in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.mapi(|i, value| i + value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(i, self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Calls a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_each(|value| result.push(value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Calls a closure on each element in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_eachi(|i, value| result.push(i + value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(i, self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function will zero out any elements at or past index `len` of `array`.\n /// This incurs an extra runtime cost of O(MaxLen). If you are sure your array is\n /// zeroed after that index, you can use [`from_parts_unchecked`][Self::from_parts_unchecked] to remove the extra loop.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n /// ```\n pub fn from_parts(mut array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n let zeroed = crate::mem::zeroed();\n\n if is_unconstrained() {\n for i in len..MaxLen {\n array[i] = zeroed;\n }\n } else {\n for i in 0..MaxLen {\n if i >= len {\n array[i] = zeroed;\n }\n }\n }\n\n BoundedVec { storage: array, len }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function is unsafe because it expects all elements past the `len` index\n /// of `array` to be zeroed, but does not check for this internally. Use `from_parts`\n /// for a safe version of this function which does zero out any indices past the\n /// given length. Invalidating this assumption can notably cause `BoundedVec::eq`\n /// to give incorrect results since it will check even elements past `len`.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n ///\n /// // invalid use!\n /// let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n /// let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n ///\n /// // both vecs have length 3 so we'd expect them to be equal, but this\n /// // fails because elements past the length are still checked in eq\n /// assert_eq(vec1, vec2); // fails\n /// ```\n pub fn from_parts_unchecked(array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n BoundedVec { storage: array, len }\n }\n}\n\nimpl Eq for BoundedVec\nwhere\n T: Eq,\n{\n fn eq(self, other: BoundedVec) -> bool {\n // TODO: https://github.com/noir-lang/noir/issues/4837\n //\n // We make the assumption that the user has used the proper interface for working with `BoundedVec`s\n // rather than directly manipulating the internal fields as this can result in an inconsistent internal state.\n if self.len == other.len {\n self.storage == other.storage\n } else {\n false\n }\n }\n}\n\nimpl From<[T; Len]> for BoundedVec {\n fn from(array: [T; Len]) -> BoundedVec {\n BoundedVec::from_array(array)\n }\n}\n\nmod bounded_vec_tests {\n\n mod get {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_elements_past_end_of_vec() {\n let vec: BoundedVec = BoundedVec::new();\n\n let _ = vec.get(0);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_beyond_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let _ = vec.get(3);\n }\n\n #[test]\n fn get_works_within_bounds() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(2), 3);\n assert_eq(vec.get(4), 5);\n }\n\n #[test]\n fn get_unchecked_works() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(0), 1);\n assert_eq(vec.get_unchecked(2), 3);\n }\n\n #[test]\n fn get_unchecked_works_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(4), 0);\n }\n }\n\n mod set {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn set_updates_values_properly() {\n let mut vec = BoundedVec::from_array([0, 0, 0, 0, 0]);\n\n vec.set(0, 42);\n assert_eq(vec.storage, [42, 0, 0, 0, 0]);\n\n vec.set(1, 43);\n assert_eq(vec.storage, [42, 43, 0, 0, 0]);\n\n vec.set(2, 44);\n assert_eq(vec.storage, [42, 43, 44, 0, 0]);\n\n vec.set(1, 10);\n assert_eq(vec.storage, [42, 10, 44, 0, 0]);\n\n vec.set(0, 0);\n assert_eq(vec.storage, [0, 10, 44, 0, 0]);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_writing_elements_past_end_of_vec() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.set(0, 42);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_setting_beyond_length() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.set(3, 4);\n }\n\n #[test]\n fn set_unchecked_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(0, 10);\n assert_eq(vec.get(0), 10);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn set_unchecked_operations_past_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(3, 40);\n assert_eq(vec.get(3), 40);\n }\n\n #[test]\n fn set_preserves_other_elements() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n vec.set(2, 30);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 30);\n assert_eq(vec.get(3), 4);\n assert_eq(vec.get(4), 5);\n }\n }\n\n mod any {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn returns_false_if_predicate_not_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, false, false]);\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn returns_true_if_predicate_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, true, true]);\n let result = vec.any(|value| value);\n\n assert(result);\n }\n\n #[test]\n fn returns_false_on_empty_boundedvec() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn any_with_complex_predicates() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n assert(vec.any(|x| x > 3));\n assert(!vec.any(|x| x > 10));\n assert(vec.any(|x| x % 2 == 0)); // has a even number\n assert(vec.any(|x| x == 3)); // has a specific value\n }\n\n #[test]\n fn any_with_partial_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n assert(vec.any(|x| x == 1));\n assert(vec.any(|x| x == 2));\n assert(!vec.any(|x| x == 3));\n }\n }\n\n mod map {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-map-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| value * 2);\n // docs:end:bounded-vec-map-example\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.map(|value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn map_with_conditional_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.map(|x| if x % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([1, 4, 3, 8]);\n assert_eq(result, expected);\n }\n\n #[test]\n fn map_preserves_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|x| x * 2);\n\n assert_eq(result.len(), vec.len());\n assert_eq(result.max_len(), vec.max_len());\n }\n\n #[test]\n fn map_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.map(|x| x * 2);\n assert_eq(result, vec);\n assert_eq(result.len(), 0);\n assert_eq(result.max_len(), 5);\n }\n }\n\n mod mapi {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-mapi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| i + value * 2);\n // docs:end:bounded-vec-mapi-example\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.mapi(|_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn mapi_with_index_branching_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.mapi(|i, x| if i % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([2, 2, 6, 4]);\n assert_eq(result, expected);\n }\n }\n\n mod for_each {\n use crate::collections::bounded_vec::BoundedVec;\n\n // map in terms of for_each\n fn for_each_map(\n input: BoundedVec,\n f: fn[Env](T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_each(|x| output_ref.push(f(x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-each-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_each(|value| { *acc_ref += value; });\n // docs:end:bounded-vec-for-each-example\n assert_eq(acc, 6);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| value * 2);\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_each_map(vec, |value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_each_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_each(|_| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_each_with_side_effects() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let mut seen = BoundedVec::::new();\n let seen_ref = &mut seen;\n vec.for_each(|x| seen_ref.push(x));\n assert_eq(seen, vec);\n }\n }\n\n mod for_eachi {\n use crate::collections::bounded_vec::BoundedVec;\n\n // mapi in terms of for_eachi\n fn for_eachi_mapi(\n input: BoundedVec,\n f: fn[Env](u32, T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_eachi(|i, x| output_ref.push(f(i, x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-eachi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_eachi(|i, value| { *acc_ref += i * value; });\n // docs:end:bounded-vec-for-eachi-example\n\n // 0 * 1 + 1 * 2 + 2 * 3\n assert_eq(acc, 8);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| i + value * 2);\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_eachi_mapi(vec, |_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_eachi_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_eachi(|_, _| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_eachi_with_index_tracking() {\n let vec: BoundedVec = BoundedVec::from_array([10, 20, 30]);\n let mut indices = BoundedVec::::new();\n let indices_ref = &mut indices;\n vec.for_eachi(|i, _| indices_ref.push(i));\n\n let expected = BoundedVec::from_array([0, 1, 2]);\n assert_eq(indices, expected);\n }\n\n }\n\n mod from_array {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty() {\n let empty_array: [Field; 0] = [];\n let bounded_vec = BoundedVec::from_array([]);\n\n assert_eq(bounded_vec.max_len(), 0);\n assert_eq(bounded_vec.len(), 0);\n assert_eq(bounded_vec.storage(), empty_array);\n }\n\n #[test]\n fn equal_len() {\n let array = [1, 2, 3];\n let bounded_vec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 3);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.storage(), array);\n }\n\n #[test]\n fn max_len_greater_then_array_len() {\n let array = [1, 2, 3];\n let bounded_vec: BoundedVec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n assert_eq(bounded_vec.get(2), 3);\n }\n\n #[test(should_fail_with = \"from array out of bounds\")]\n fn max_len_lower_then_array_len() {\n let _: BoundedVec = BoundedVec::from_array([0; 3]);\n }\n\n #[test]\n fn from_array_preserves_order() {\n let array = [5, 3, 1, 4, 2];\n let vec: BoundedVec = BoundedVec::from_array(array);\n for i in 0..array.len() {\n assert_eq(vec.get(i), array[i]);\n }\n }\n\n #[test]\n fn from_array_with_different_types() {\n let bool_array = [true, false, true];\n let bool_vec: BoundedVec = BoundedVec::from_array(bool_array);\n assert_eq(bool_vec.len(), 3);\n assert_eq(bool_vec.get(0), true);\n assert_eq(bool_vec.get(1), false);\n }\n }\n\n mod trait_from {\n use crate::collections::bounded_vec::BoundedVec;\n use crate::convert::From;\n\n #[test]\n fn simple() {\n let array = [1, 2];\n let bounded_vec: BoundedVec = BoundedVec::from(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 2);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n }\n }\n\n mod trait_eq {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty_equality() {\n let bounded_vec1: BoundedVec = BoundedVec::new();\n let bounded_vec2: BoundedVec = BoundedVec::new();\n\n assert_eq(bounded_vec1, bounded_vec2);\n }\n\n #[test]\n fn inequality() {\n let mut bounded_vec1: BoundedVec = BoundedVec::new();\n let mut bounded_vec2: BoundedVec = BoundedVec::new();\n bounded_vec1.push(1);\n bounded_vec2.push(2);\n\n assert(bounded_vec1 != bounded_vec2);\n }\n }\n\n mod from_parts {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn from_parts() {\n // docs:start:from-parts\n let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // Any elements past the given length are zeroed out, so these\n // two BoundedVecs will be completely equal\n let vec1: BoundedVec = BoundedVec::from_parts([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts([1, 2, 3, 2], 3);\n assert_eq(vec1, vec2);\n // docs:end:from-parts\n }\n\n #[test]\n fn from_parts_unchecked() {\n // docs:start:from-parts-unchecked\n let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // invalid use!\n let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n\n // both vecs have length 3 so we'd expect them to be equal, but this\n // fails because elements past the length are still checked in eq\n assert(vec1 != vec2);\n // docs:end:from-parts-unchecked\n }\n }\n\n mod push_pop {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn push_and_pop_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n assert_eq(vec.len(), 0);\n\n vec.push(1);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 1);\n\n vec.push(2);\n assert_eq(vec.len(), 2);\n assert_eq(vec.get(1), 2);\n\n let popped = vec.pop();\n assert_eq(popped, 2);\n assert_eq(vec.len(), 1);\n\n let popped2 = vec.pop();\n assert_eq(popped2, 1);\n assert_eq(vec.len(), 0);\n }\n\n #[test(should_fail_with = \"push out of bounds\")]\n fn push_to_full_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n vec.push(3); // should panic\n }\n\n #[test(should_fail_with = \"cannot pop from an empty vector\")]\n fn pop_from_empty_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n let _ = vec.pop(); // should panic\n }\n\n #[test]\n fn push_pop_cycle() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // push to full\n vec.push(1);\n vec.push(2);\n vec.push(3);\n assert_eq(vec.len(), 3);\n\n // pop all\n assert_eq(vec.pop(), 3);\n assert_eq(vec.pop(), 2);\n assert_eq(vec.pop(), 1);\n assert_eq(vec.len(), 0);\n\n // push again\n vec.push(4);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 4);\n }\n }\n\n mod extend {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn extend_from_array() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3]);\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3].as_vector());\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec() {\n // The source deliberately has a higher capacity,\n // to make sure we are not trying to assign out-of-bounds.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_limit() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_full_and_empty() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_zero_len() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_last_zeroed() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get_unchecked(3), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_empty_self() {\n // self.len == 0 with Len > MaxLen: the loop doesn't reach\n // the last storage slot, so the fixup must write it.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_equal_capacity() {\n // Len == MaxLen, fills to capacity.\n let mut vec1: BoundedVec = BoundedVec::new();\n vec1.push(1);\n let vec2: BoundedVec = BoundedVec::from_array([2, 3, 4]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 4);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n assert_eq(vec1.get(3), 4);\n }\n\n #[test(should_fail_with = \"extend_from_array out of bounds\")]\n fn extend_array_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3, 4]); // should panic\n }\n\n #[test(should_fail_with = \"extend_from_vector out of bounds\")]\n fn extend_vector_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3, 4].as_vector()); // S]should panic\n }\n\n #[test(should_fail_with = \"extend_from_bounded_vec out of bounds\")]\n fn extend_bounded_vec_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n let other: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n vec.extend_from_bounded_vec(other); // should panic\n }\n\n #[test]\n fn extend_with_empty_collections() {\n let mut vec: BoundedVec = BoundedVec::new();\n let original_len = vec.len();\n\n vec.extend_from_array([]);\n assert_eq(vec.len(), original_len);\n\n vec.extend_from_vector([].as_vector());\n assert_eq(vec.len(), original_len);\n\n let empty: BoundedVec = BoundedVec::new();\n vec.extend_from_bounded_vec(empty);\n assert_eq(vec.len(), original_len);\n }\n }\n\n mod storage {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn storage_consistency() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // test initial storage state\n assert_eq(vec.storage(), [0, 0, 0, 0, 0]);\n\n vec.push(1);\n vec.push(2);\n\n // test storage after modifications\n assert_eq(vec.storage(), [1, 2, 0, 0, 0]);\n\n // storage doesn't change length\n assert_eq(vec.len(), 2);\n assert_eq(vec.max_len(), 5);\n }\n\n #[test]\n fn storage_after_pop() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n let _ = vec.pop();\n // after pop, the last element should be zeroed\n assert_eq(vec.storage(), [1, 2, 0]);\n assert_eq(vec.len(), 2);\n }\n\n #[test]\n fn vector_immutable() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let storage = vec.storage();\n\n assert_eq(storage, [1, 2, 3]);\n\n // Verify that the original vector is unchanged\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n }\n}\n","path":"std/collections/bounded_vec.nr","function_locations":[{"start":2599,"name":"BoundedVec::new"},{"start":3202,"name":"BoundedVec::get"},{"start":4110,"name":"BoundedVec::get_unchecked"},{"start":4693,"name":"BoundedVec::set"},{"start":6221,"name":"BoundedVec::set_unchecked"},{"start":6759,"name":"BoundedVec::push"},{"start":7367,"name":"BoundedVec::len"},{"start":7808,"name":"BoundedVec::max_len"},{"start":8407,"name":"BoundedVec::storage"},{"start":8963,"name":"BoundedVec::extend_from_array"},{"start":9734,"name":"BoundedVec::extend_from_vector"},{"start":10679,"name":"BoundedVec::extend_from_bounded_vec"},{"start":13074,"name":"BoundedVec::from_array"},{"start":13817,"name":"BoundedVec::pop"},{"start":14440,"name":"BoundedVec::any"},{"start":15356,"name":"BoundedVec::map"},{"start":16356,"name":"BoundedVec::mapi"},{"start":17314,"name":"BoundedVec::for_each"},{"start":18119,"name":"BoundedVec::for_eachi"},{"start":19118,"name":"BoundedVec::from_parts"},{"start":20767,"name":"BoundedVec::from_parts_unchecked"},{"start":20979,"name":">::eq"},{"start":21550,"name":" for BoundedVec>::from"},{"start":21833,"name":"bounded_vec_tests::get::panics_when_reading_elements_past_end_of_vec"},{"start":22068,"name":"bounded_vec_tests::get::panics_when_reading_beyond_length"},{"start":22243,"name":"bounded_vec_tests::get::get_works_within_bounds"},{"start":22502,"name":"bounded_vec_tests::get::get_unchecked_works"},{"start":22746,"name":"bounded_vec_tests::get::get_unchecked_works_past_len"},{"start":23019,"name":"bounded_vec_tests::set::set_updates_values_properly"},{"start":23657,"name":"bounded_vec_tests::set::panics_when_writing_elements_past_end_of_vec"},{"start":23892,"name":"bounded_vec_tests::set::panics_when_setting_beyond_length"},{"start":24067,"name":"bounded_vec_tests::set::set_unchecked_operations"},{"start":24399,"name":"bounded_vec_tests::set::set_unchecked_operations_past_len"},{"start":24663,"name":"bounded_vec_tests::set::set_preserves_other_elements"},{"start":25131,"name":"bounded_vec_tests::any::returns_false_if_predicate_not_satisfied"},{"start":25385,"name":"bounded_vec_tests::any::returns_true_if_predicate_satisfied"},{"start":25634,"name":"bounded_vec_tests::any::returns_false_on_empty_boundedvec"},{"start":25845,"name":"bounded_vec_tests::any::any_with_complex_predicates"},{"start":26208,"name":"bounded_vec_tests::any::any_with_partial_vector"},{"start":26595,"name":"bounded_vec_tests::map::applies_function_correctly"},{"start":27017,"name":"bounded_vec_tests::map::applies_function_that_changes_return_type"},{"start":27365,"name":"bounded_vec_tests::map::does_not_apply_function_past_len"},{"start":27738,"name":"bounded_vec_tests::map::map_with_conditional_logic"},{"start":28062,"name":"bounded_vec_tests::map::map_preserves_length"},{"start":28354,"name":"bounded_vec_tests::map::map_on_empty_vector"},{"start":28728,"name":"bounded_vec_tests::mapi::applies_function_correctly"},{"start":29161,"name":"bounded_vec_tests::mapi::applies_function_that_changes_return_type"},{"start":29518,"name":"bounded_vec_tests::mapi::does_not_apply_function_past_len"},{"start":29900,"name":"bounded_vec_tests::mapi::mapi_with_index_branching_logic"},{"start":30459,"name":"bounded_vec_tests::for_each::for_each_map"},{"start":30689,"name":"bounded_vec_tests::for_each::smoke_test"},{"start":31097,"name":"bounded_vec_tests::for_each::applies_function_correctly"},{"start":31431,"name":"bounded_vec_tests::for_each::applies_function_that_changes_return_type"},{"start":31789,"name":"bounded_vec_tests::for_each::does_not_apply_function_past_len"},{"start":32170,"name":"bounded_vec_tests::for_each::for_each_on_empty_vector"},{"start":32456,"name":"bounded_vec_tests::for_each::for_each_with_side_effects"},{"start":33013,"name":"bounded_vec_tests::for_eachi::for_eachi_mapi"},{"start":33250,"name":"bounded_vec_tests::for_eachi::smoke_test"},{"start":33706,"name":"bounded_vec_tests::for_eachi::applies_function_correctly"},{"start":34050,"name":"bounded_vec_tests::for_eachi::applies_function_that_changes_return_type"},{"start":34418,"name":"bounded_vec_tests::for_eachi::does_not_apply_function_past_len"},{"start":34805,"name":"bounded_vec_tests::for_eachi::for_eachi_on_empty_vector"},{"start":35098,"name":"bounded_vec_tests::for_eachi::for_eachi_with_index_tracking"},{"start":35575,"name":"bounded_vec_tests::from_array::empty"},{"start":35885,"name":"bounded_vec_tests::from_array::equal_len"},{"start":36202,"name":"bounded_vec_tests::from_array::max_len_greater_then_array_len"},{"start":36673,"name":"bounded_vec_tests::from_array::max_len_lower_then_array_len"},{"start":36816,"name":"bounded_vec_tests::from_array::from_array_preserves_order"},{"start":37105,"name":"bounded_vec_tests::from_array::from_array_with_different_types"},{"start":37542,"name":"bounded_vec_tests::trait_from::simple"},{"start":37980,"name":"bounded_vec_tests::trait_eq::empty_equality"},{"start":38229,"name":"bounded_vec_tests::trait_eq::inequality"},{"start":38638,"name":"bounded_vec_tests::from_parts::from_parts"},{"start":39228,"name":"bounded_vec_tests::from_parts::from_parts_unchecked"},{"start":40010,"name":"bounded_vec_tests::push_pop::push_and_pop_operations"},{"start":40636,"name":"bounded_vec_tests::push_pop::push_to_full_vector"},{"start":40910,"name":"bounded_vec_tests::push_pop::pop_from_empty_vector"},{"start":41079,"name":"bounded_vec_tests::push_pop::push_pop_cycle"},{"start":41725,"name":"bounded_vec_tests::extend::extend_from_array"},{"start":42071,"name":"bounded_vec_tests::extend::extend_from_vector"},{"start":42435,"name":"bounded_vec_tests::extend::extend_from_bounded_vec"},{"start":43056,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_limit"},{"start":43570,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_full_and_empty"},{"start":44074,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_zero_len"},{"start":44368,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_last_zeroed"},{"start":44793,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_empty_self"},{"start":45360,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_equal_capacity"},{"start":45947,"name":"bounded_vec_tests::extend::extend_array_beyond_max_len"},{"start":46225,"name":"bounded_vec_tests::extend::extend_vector_beyond_max_len"},{"start":46528,"name":"bounded_vec_tests::extend::extend_bounded_vec_beyond_max_len"},{"start":46814,"name":"bounded_vec_tests::extend::extend_with_empty_collections"},{"start":47414,"name":"bounded_vec_tests::storage::storage_consistency"},{"start":47916,"name":"bounded_vec_tests::storage::storage_after_pop"},{"start":48234,"name":"bounded_vec_tests::storage::vector_immutable"}]},"16":{"source":"use crate::field::field_less_than;\nuse crate::runtime::is_unconstrained;\n\n// The low and high decomposition of the field modulus\npub(crate) global PLO: Field = 53438638232309528389504892708671455233;\npub(crate) global PHI: Field = 64323764613183177041862057485226039389;\n\npub(crate) global TWO_POW_128: Field = 0x100000000000000000000000000000000;\n\n// Decomposes a single field into two 16 byte fields.\nfn compute_decomposition(x: Field) -> (Field, Field) {\n // Here's we're taking advantage of truncating 128 bit limbs from the input field\n // and then subtracting them from the input such the field division is equivalent to integer division.\n let low = (x as u128) as Field;\n let high = (x - low) / TWO_POW_128;\n\n (low, high)\n}\n\npub(crate) unconstrained fn decompose_hint(x: Field) -> (Field, Field) {\n compute_decomposition(x)\n}\n\nunconstrained fn lte_hint(x: Field, y: Field) -> bool {\n if x == y {\n true\n } else {\n field_less_than(x, y)\n }\n}\n\n// Assert that (alo > blo && ahi >= bhi) || (alo <= blo && ahi > bhi)\nfn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) {\n let (alo, ahi) = a;\n let (blo, bhi) = b;\n // Safety: borrow is enforced to be boolean due to its type.\n // if borrow is 0, it asserts that (alo > blo && ahi >= bhi)\n // if borrow is 1, it asserts that (alo <= blo && ahi > bhi)\n unsafe {\n let borrow = lte_hint(alo, blo);\n\n let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128;\n let rhi = ahi - bhi - (borrow as Field);\n\n rlo.assert_max_bit_size::<128>();\n rhi.assert_max_bit_size::<128>();\n }\n}\n\n/// Decompose a single field into two 16 byte fields.\npub fn decompose(x: Field) -> (Field, Field) {\n if is_unconstrained() {\n compute_decomposition(x)\n } else {\n // Safety: decomposition is properly checked below\n unsafe {\n // Take hints of the decomposition\n let (xlo, xhi) = decompose_hint(x);\n\n // Range check the limbs\n xlo.assert_max_bit_size::<128>();\n xhi.assert_max_bit_size::<128>();\n\n // Check that the decomposition is correct\n assert_eq(x, xlo + TWO_POW_128 * xhi);\n\n // Assert that the decomposition of P is greater than the decomposition of x\n assert_gt_limbs((PLO, PHI), (xlo, xhi));\n (xlo, xhi)\n }\n }\n}\n\npub fn assert_gt(a: Field, b: Field) {\n if is_unconstrained() {\n assert(\n // Safety: already unconstrained\n unsafe { field_less_than(b, a) },\n );\n } else {\n // Decompose a and b\n let a_limbs = decompose(a);\n let b_limbs = decompose(b);\n\n // Assert that a_limbs is greater than b_limbs\n assert_gt_limbs(a_limbs, b_limbs)\n }\n}\n\npub fn assert_lt(a: Field, b: Field) {\n assert_gt(b, a);\n}\n\npub fn gt(a: Field, b: Field) -> bool {\n if is_unconstrained() {\n // Safety: unsafe in unconstrained\n unsafe {\n field_less_than(b, a)\n }\n } else if a == b {\n false\n } else {\n // Safety: Take a hint of the comparison and verify it\n unsafe {\n if field_less_than(a, b) {\n assert_gt(b, a);\n false\n } else {\n assert_gt(a, b);\n true\n }\n }\n }\n}\n\npub fn lt(a: Field, b: Field) -> bool {\n gt(b, a)\n}\n\nmod tests {\n // TODO: Allow imports from \"super\"\n use crate::field::bn254::{assert_gt, decompose, gt, lt, lte_hint, PHI, PLO, TWO_POW_128};\n\n #[test]\n fn check_decompose() {\n assert_eq(decompose(TWO_POW_128), (0, 1));\n assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1));\n assert_eq(decompose(0x1234567890), (0x1234567890, 0));\n }\n\n #[test]\n unconstrained fn check_lte_hint() {\n assert(lte_hint(0, 1));\n assert(lte_hint(0, 0x100));\n assert(lte_hint(0x100, TWO_POW_128 - 1));\n assert(!lte_hint(0 - 1, 0));\n\n assert(lte_hint(0, 0));\n assert(lte_hint(0x100, 0x100));\n assert(lte_hint(0 - 1, 0 - 1));\n }\n\n #[test]\n fn check_gt() {\n assert(gt(1, 0));\n assert(gt(0x100, 0));\n assert(gt((0 - 1), (0 - 2)));\n assert(gt(TWO_POW_128, 0));\n assert(!gt(0, 0));\n assert(!gt(0, 0x100));\n assert(gt(0 - 1, 0 - 2));\n assert(!gt(0 - 2, 0 - 1));\n assert_gt(0 - 1, 0);\n }\n\n #[test]\n fn check_plo_phi() {\n assert_eq(PLO + PHI * TWO_POW_128, 0);\n let p_bytes = crate::field::modulus_le_bytes();\n let mut p_low: Field = 0;\n let mut p_high: Field = 0;\n\n let mut offset = 1;\n for i in 0..16 {\n p_low += (p_bytes[i] as Field) * offset;\n p_high += (p_bytes[i + 16] as Field) * offset;\n offset *= 256;\n }\n assert_eq(p_low, PLO);\n assert_eq(p_high, PHI);\n }\n\n #[test]\n fn check_decompose_edge_cases() {\n assert_eq(decompose(0), (0, 0));\n assert_eq(decompose(TWO_POW_128 - 1), (TWO_POW_128 - 1, 0));\n assert_eq(decompose(TWO_POW_128 + 1), (1, 1));\n assert_eq(decompose(TWO_POW_128 * 2), (0, 2));\n assert_eq(decompose(TWO_POW_128 * 2 + 0x1234567890), (0x1234567890, 2));\n }\n\n #[test]\n fn check_decompose_large_values() {\n let large_field = 0xffffffffffffffff;\n let (lo, hi) = decompose(large_field);\n assert_eq(large_field, lo + TWO_POW_128 * hi);\n\n let large_value = large_field - TWO_POW_128;\n let (lo2, hi2) = decompose(large_value);\n assert_eq(large_value, lo2 + TWO_POW_128 * hi2);\n }\n\n #[test]\n fn check_lt_comprehensive() {\n assert(lt(0, 1));\n assert(!lt(1, 0));\n assert(!lt(0, 0));\n assert(!lt(42, 42));\n\n assert(lt(TWO_POW_128 - 1, TWO_POW_128));\n assert(!lt(TWO_POW_128, TWO_POW_128 - 1));\n }\n}\n","path":"std/field/bn254.nr","function_locations":[{"start":456,"name":"compute_decomposition"},{"start":818,"name":"decompose_hint"},{"start":906,"name":"lte_hint"},{"start":1116,"name":"assert_gt_limbs"},{"start":1725,"name":"decompose"},{"start":2431,"name":"assert_gt"},{"start":2837,"name":"assert_lt"},{"start":2901,"name":"gt"},{"start":3405,"name":"lt"},{"start":3607,"name":"tests::check_decompose"},{"start":3857,"name":"tests::check_lte_hint"},{"start":4164,"name":"tests::check_gt"},{"start":4494,"name":"tests::check_plo_phi"},{"start":4989,"name":"tests::check_decompose_edge_cases"},{"start":5349,"name":"tests::check_decompose_large_values"},{"start":5710,"name":"tests::check_lt_comprehensive"}]},"17":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [bool; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [bool; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [bool; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = false if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = true.\n pub fn sgn0(self) -> bool {\n (self as u8) % 2 == 1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [bool; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [bool; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [bool] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [bool] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_be_bits();\n assert_eq(bits, [false, false, false, false, false, false, true, false]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_le_bits();\n assert_eq(bits, [false, true, false, false, false, false, false, false]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_field.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_val.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [bool; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [false; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [bool; 8] = 1.to_le_bits();\n let expected: [bool; 8] = [true, false, false, false, false, false, false, false];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [bool; 8] = 4.to_le_bits();\n let expected: [bool; 8] = [false, false, true, false, false, false, false, false];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), false);\n assert_eq(2.sgn0(), false);\n assert_eq(4.sgn0(), false);\n assert_eq(100.sgn0(), false);\n\n assert_eq(1.sgn0(), true);\n assert_eq(3.sgn0(), true);\n assert_eq(5.sgn0(), true);\n assert_eq(101.sgn0(), true);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [bool; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits(bits: [bool; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits(bits: [bool; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1]);\n p_minus_1_bits[254 - 1] = false;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(!p_plus_4_bits[254 - 3]);\n p_plus_4_bits[254 - 3] = true;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_be_bits();\n assert(p_plus_4_converted_bits[254 - 3]);\n p_plus_4_converted_bits[254 - 3] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_be_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0]);\n p_minus_1_bits[0] = false;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(!p_plus_4_bits[2]);\n p_plus_4_bits[2] = true;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_le_bits();\n assert(p_plus_4_converted_bits[2]);\n p_plus_4_converted_bits[2] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_le_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n}\n","path":"std/field/mod.nr","function_locations":[{"start":380,"name":"Field::assert_max_bit_size"},{"start":1196,"name":"Field::to_le_bits"},{"start":2387,"name":"Field::to_be_bits"},{"start":3562,"name":"Field::to_le_bytes"},{"start":5033,"name":"Field::to_be_bytes"},{"start":5904,"name":"Field::to_le_radix"},{"start":6362,"name":"Field::to_be_radix"},{"start":7053,"name":"Field::pow_32"},{"start":7455,"name":"Field::sgn0"},{"start":7538,"name":"Field::lt"},{"start":7918,"name":"Field::from_le_bytes"},{"start":8476,"name":"Field::from_be_bytes"},{"start":8757,"name":"__assert_max_bit_size"},{"start":8885,"name":"__to_le_radix"},{"start":9013,"name":"__to_be_radix"},{"start":9734,"name":"__to_le_bits"},{"start":10452,"name":"__to_be_bits"},{"start":10527,"name":"modulus_num_bits"},{"start":10603,"name":"modulus_be_bits"},{"start":10679,"name":"modulus_le_bits"},{"start":10755,"name":"modulus_be_bytes"},{"start":10831,"name":"modulus_le_bytes"},{"start":10992,"name":"__field_less_than"},{"start":11068,"name":"field_less_than"},{"start":11210,"name":"bytes32_to_field"},{"start":11617,"name":"lt_fallback"},{"start":12579,"name":"tests::test_to_be_bits"},{"start":12852,"name":"tests::test_to_le_bits"},{"start":13127,"name":"tests::test_to_be_bytes"},{"start":13433,"name":"tests::test_to_le_bytes"},{"start":13739,"name":"tests::test_to_be_radix"},{"start":14321,"name":"tests::test_to_le_radix"},{"start":14921,"name":"tests::test_to_le_radix_1"},{"start":15374,"name":"tests::test_to_le_radix_brillig_1"},{"start":15728,"name":"tests::test_to_le_radix_3"},{"start":16039,"name":"tests::test_to_le_radix_brillig_3"},{"start":16467,"name":"tests::test_to_le_radix_512"},{"start":16876,"name":"tests::not_enough_limbs_brillig"},{"start":17072,"name":"tests::not_enough_limbs"},{"start":17214,"name":"tests::test_field_less_than"},{"start":17469,"name":"tests::test_large_field_values_unconstrained"},{"start":17922,"name":"tests::test_large_field_values"},{"start":18369,"name":"tests::test_decomposition_edge_cases"},{"start":18959,"name":"tests::test_pow_32"},{"start":19288,"name":"tests::test_sgn0"},{"start":19710,"name":"tests::test_bit_decomposition_overflow"},{"start":19992,"name":"tests::test_byte_decomposition_overflow"},{"start":20209,"name":"tests::test_to_from_be_bytes_bn254_edge_cases"},{"start":22160,"name":"tests::test_to_from_le_bytes_bn254_edge_cases"},{"start":24245,"name":"tests::from_le_bits"},{"start":24792,"name":"tests::from_be_bits"},{"start":25038,"name":"tests::test_to_from_be_bits_bn254_edge_cases"},{"start":26971,"name":"tests::test_to_from_le_bits_bn254_edge_cases"}]},"18":{"source":"// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\nuse crate::static_assert;\n\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated(\"This function has been moved to std::hash::keccakf1600\")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you're working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n \"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n // we use the unsafe version because the multi_scalar_mul will constrain the scalars.\n points[i] = from_field_unsafe(input[i]);\n }\n let generators = derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n crate::assert_constant(separator);\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = from_field_unsafe(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators(\"pedersen_hash_length\".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n crate::assert_constant(starting_index);\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\n#[field(bn254)]\n// Decompose the input 'bn254 scalar' into two 128 bits limbs.\n// It is called 'unsafe' because it does not assert the limbs are 128 bits\n// Assuming the limbs are 128 bits:\n// Assert the decomposition does not overflow the field size.\nfn from_field_unsafe(scalar: Field) -> EmbeddedCurveScalar {\n // Safety: xlo and xhi decomposition is checked below\n let (xlo, xhi) = unsafe { crate::field::bn254::decompose_hint(scalar) };\n // Check that the decomposition is correct\n assert_eq(scalar, xlo + crate::field::bn254::TWO_POW_128 * xhi);\n // Check that the decomposition does not overflow the field size\n let (a, b) = if xhi == crate::field::bn254::PHI {\n (xlo, crate::field::bn254::PLO)\n } else {\n (xhi, crate::field::bn254::PHI)\n };\n crate::field::bn254::assert_lt(a, b);\n\n EmbeddedCurveScalar { lo: xlo, hi: xhi }\n}\n\npub fn poseidon2_permutation(input: [Field; N]) -> [Field; N] {\n static_assert(\n N == POSEIDON2_CONFIG_STATE_SIZE,\n f\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\",\n );\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal(input: [Field; N]) -> [Field; N] {}\n\n#[foreign(poseidon2_config_state_size)]\ncomptime fn poseidon2_config_state_size() -> u32 {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n /// Returns the hash value without consuming the hasher.\n /// Override this for more efficient implementations that avoid copying.\n /// TODO: deprecate finish() and replace it\n fn finish_ref(&self) -> Field {\n (*self).finish()\n }\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault;\n\nimpl BuildHasher for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl Default for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for [T]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n },\n );\n}\n","path":"std/hash/mod.nr","function_locations":[{"start":572,"name":"sha256_compression"},{"start":707,"name":"keccakf1600"},{"start":882,"name":"keccak::keccakf1600"},{"start":1044,"name":"blake2s"},{"start":1142,"name":"blake3"},{"start":1629,"name":"__blake3"},{"start":1747,"name":"pedersen_commitment"},{"start":1976,"name":"pedersen_commitment_with_separator"},{"start":2460,"name":"pedersen_hash"},{"start":2617,"name":"pedersen_hash_with_separator"},{"start":3597,"name":"derive_generators"},{"start":3956,"name":"__derive_generators"},{"start":4271,"name":"from_field_unsafe"},{"start":4912,"name":"poseidon2_permutation"},{"start":5268,"name":"poseidon2_permutation_internal"},{"start":5361,"name":"poseidon2_config_state_size"},{"start":5672,"name":"derive_hash"},{"start":6897,"name":">::build_hasher"},{"start":7029,"name":">::default"},{"start":7161,"name":"::hash"},{"start":7291,"name":"::hash"},{"start":7431,"name":"::hash"},{"start":7571,"name":"::hash"},{"start":7711,"name":"::hash"},{"start":7852,"name":"::hash"},{"start":7991,"name":"::hash"},{"start":8137,"name":"::hash"},{"start":8284,"name":"::hash"},{"start":8431,"name":"::hash"},{"start":8579,"name":"::hash"},{"start":8726,"name":"::hash"},{"start":8858,"name":"::hash"},{"start":9047,"name":"::hash"},{"start":9287,"name":"::hash"},{"start":9503,"name":"::hash"},{"start":9766,"name":"::hash"},{"start":10076,"name":"::hash"},{"start":10472,"name":"assert_pedersen"}]},"41":{"source":"use crate::cmp::{Eq, Ord, Ordering};\nuse crate::default::Default;\nuse crate::hash::{Hash, Hasher};\n\n/// Represents a value of type T or its absence.\n/// Use `Option::some(value)` to construct a value or `Option::none()` to record the absence of one.\npub struct Option {\n _is_some: bool,\n _value: T,\n}\n\nimpl Option {\n /// Constructs a None value\n pub fn none() -> Self {\n Self { _is_some: false, _value: crate::mem::zeroed() }\n }\n\n /// Constructs a Some wrapper around the given value\n pub fn some(_value: T) -> Self {\n Self { _is_some: true, _value }\n }\n\n /// True if this Option is None\n pub fn is_none(&self) -> bool {\n !self._is_some\n }\n\n /// True if this Option is Some\n pub fn is_some(&self) -> bool {\n self._is_some\n }\n\n /// Asserts `self.is_some()` and returns the wrapped value.\n pub fn unwrap(self) -> T {\n assert(self._is_some);\n self._value\n }\n\n /// Returns the inner value without asserting `self.is_some()`\n /// Note that if `self` is `None`, there is no guarantee what value will be returned,\n /// only that it will be of type `T`.\n pub fn unwrap_unchecked(self) -> T {\n self._value\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.\n pub fn unwrap_or(self, default: T) -> T {\n if self._is_some {\n self._value\n } else {\n default\n }\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return\n /// a default value.\n pub fn unwrap_or_else(self, default: fn[Env]() -> T) -> T {\n if self._is_some {\n self._value\n } else {\n default()\n }\n }\n\n /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value\n pub fn expect(self, message: fmtstr) -> T {\n assert(self.is_some(), message);\n self._value\n }\n\n /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.\n pub fn map(self, f: fn[Env](T) -> U) -> Option {\n if self._is_some {\n Option::some(f(self._value))\n } else {\n Option::none()\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.\n pub fn map_or(self, default: U, f: fn[Env](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.\n pub fn map_or_else(self, default: fn[Env1]() -> U, f: fn[Env2](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default()\n }\n }\n\n /// Returns None if self is None. Otherwise, this returns `other`.\n pub fn and(self, other: Self) -> Self {\n if self.is_none() {\n Option::none()\n } else {\n other\n }\n }\n\n /// If self is None, this returns None. Otherwise, this calls the given function\n /// with the Some value contained within self, and returns the result of that call.\n ///\n /// In some languages this function is called `flat_map` or `bind`.\n pub fn and_then(self, f: fn[Env](T) -> Option) -> Option {\n if self._is_some {\n f(self._value)\n } else {\n Option::none()\n }\n }\n\n /// If self is Some, return self. Otherwise, return `other`.\n pub fn or(self, other: Self) -> Self {\n if self._is_some {\n self\n } else {\n other\n }\n }\n\n /// If self is Some, return self. Otherwise, return `default()`.\n pub fn or_else(self, default: fn[Env]() -> Self) -> Self {\n if self._is_some {\n self\n } else {\n default()\n }\n }\n\n // If only one of the two Options is Some, return that option.\n // Otherwise, if both options are Some or both are None, None is returned.\n pub fn xor(self, other: Self) -> Self {\n if self._is_some {\n if other._is_some {\n Option::none()\n } else {\n self\n }\n } else if other._is_some {\n other\n } else {\n Option::none()\n }\n }\n\n /// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.\n /// Otherwise, this returns `None`\n pub fn filter(self, predicate: fn[Env](T) -> bool) -> Self {\n if self._is_some {\n if predicate(self._value) {\n self\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n }\n\n /// Flattens an Option> into a Option.\n /// This returns None if the outer Option is None. Otherwise, this returns the inner Option.\n pub fn flatten(option: Option>) -> Option {\n if option._is_some {\n option._value\n } else {\n Option::none()\n }\n }\n}\n\nimpl Default for Option {\n fn default() -> Self {\n Option::none()\n }\n}\n\nimpl Eq for Option\nwhere\n T: Eq,\n{\n fn eq(self, other: Self) -> bool {\n if self._is_some == other._is_some {\n if self._is_some {\n self._value == other._value\n } else {\n true\n }\n } else {\n false\n }\n }\n}\n\nimpl Hash for Option\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self._is_some.hash(state);\n if self._is_some {\n self._value.hash(state);\n }\n }\n}\n\n// For this impl we're declaring Option::none < Option::some\nimpl Ord for Option\nwhere\n T: Ord,\n{\n fn cmp(self, other: Self) -> Ordering {\n if self._is_some {\n if other._is_some {\n self._value.cmp(other._value)\n } else {\n Ordering::greater()\n }\n } else if other._is_some {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n","path":"std/option.nr","function_locations":[{"start":389,"name":"Option::none"},{"start":553,"name":"Option::some"},{"start":672,"name":"Option::is_none"},{"start":774,"name":"Option::is_some"},{"start":898,"name":"Option::unwrap"},{"start":1196,"name":"Option::unwrap_unchecked"},{"start":1368,"name":"Option::unwrap_or"},{"start":1668,"name":"Option::unwrap_or_else"},{"start":1969,"name":"Option::expect"},{"start":2190,"name":"Option::map"},{"start":2490,"name":"Option::map_or"},{"start":2784,"name":"Option::map_or_else"},{"start":3009,"name":"Option::and"},{"start":3446,"name":"Option::and_then"},{"start":3669,"name":"Option::or"},{"start":3902,"name":"Option::or_else"},{"start":4192,"name":"Option::xor"},{"start":4636,"name":"Option::filter"},{"start":5065,"name":"Option::flatten"},{"start":5242,"name":">::default"},{"start":5357,"name":">::eq"},{"start":5706,"name":">::hash"},{"start":5975,"name":">::cmp"}]},"42":{"source":"/// Halt the program at runtime with the given error message.\n///\n/// The provided error message must be either a `str` or a `fmtstr`.\npub fn panic(message: T) -> U\nwhere\n T: StringLike,\n{\n assert(false, message);\n crate::mem::zeroed()\n}\n\ntrait StringLike {}\n\nimpl StringLike for str {}\nimpl StringLike for fmtstr {}\n","path":"std/panic.nr","function_locations":[{"start":196,"name":"panic"}]},"52":{"source":"use crate::{\n authwit::{authorization_interface::AuthorizationInterface, AuthorizationSelector},\n context::{gas::GasOpts, PrivateContext, PublicContext},\n hash::hash_args,\n macros::authorization::authorization,\n oracle::{execution_cache::load, offchain_effect::emit_offchain_effect},\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::AztecAddress,\n constants::{\n CANONICAL_AUTH_REGISTRY_ADDRESS, DOM_SEP__AUTHWIT_INNER, DOM_SEP__AUTHWIT_NULLIFIER, DOM_SEP__AUTHWIT_OUTER,\n },\n hash::poseidon2_hash_with_separator,\n traits::{Serialize, ToField},\n};\n\n/// Authentication witness helper library\n///\n/// Authentication Witness is a scheme for authenticating actions on Aztec, so users can allow third-parties (e.g.\n/// protocols or other users) to execute an action on their behalf.\n///\n/// This library provides helper functions to manage such witnesses. The authentication witness, is some \"witness\"\n/// (data) that authenticates a `message_hash`. The simplest example of an authentication witness, is a signature. The\n/// signature is the \"evidence\", that the signer has seen the message, agrees with it, and has allowed it. It does not\n/// need to be a signature. It could be any kind of \"proof\" that the message is allowed. Another proof could be knowing\n/// some kind of secret, or having some kind of \"token\" that allows the message.\n///\n/// The `message_hash` is a hash of the following structure: hash(consumer, chain_id, version, inner_hash)\n/// - consumer: the address of the contract that is \"consuming\" the message,\n/// - chain_id: the chain id of the chain that the message is being consumed on,\n/// - version: the version of the chain that the message is being consumed on,\n/// - inner_hash: the hash of the \"inner\" message that is being consumed, this is the \"actual\" message or action.\n///\n/// While the `inner_hash` could be anything, such as showing you signed a specific message, it will often be a hash of\n/// the \"action\" to approve, along with who made the call. As part of this library, we provide a few helper functions\n/// to deal with such messages.\n///\n/// For example, we provide helper function that is used for checking that the message is an encoding of the current\n/// call. This can be used to let some contract \"allow\" another contract to act on its behalf, as long as it can show\n/// that it is acting on behalf of the contract.\n///\n/// If we take a case of allowing a contract to transfer tokens on behalf of an account, the `inner_hash` can be\n/// derived as: inner_hash = hash(caller, \"transfer\", hash(to, amount))\n///\n/// Where the `caller` would be the address of the contract that is trying to transfer the tokens, and `to` and\n/// `amount` the arguments for the transfer.\n///\n/// Note that we have both a `caller` and a `consumer`, the `consumer` will be the contract that is consuming the\n/// message, in the case of the transfer, it would be the `Token` contract itself, while the caller, will be the actor\n/// that is allowed to transfer the tokens.\n///\n///\n/// The authentication mechanism works differently in public and private contexts. In private, we recall that\n/// everything is executed on the user's device, so we can use `oracles` to \"ask\" the user (not contract) for\n/// information. In public we cannot do this, since it is executed by the sequencer (someone else). Therefore we can\n/// instead use a \"registry\" to store the messages that we have approved.\n///\n/// A simple example would be a \"token\" that is being \"pulled\" from one account into another. We will first outline how\n/// this would look in private, and then in public later.\n///\n/// Say that a user `Alice` wants to deposit some tokens into a DeFi protocol (say a DEX). `Alice` would make a\n/// `deposit` transaction, that she is executing using her account contract. The account would call the `DeFi` contract\n/// to execute `deposit`, which would try to pull funds from the `Token` contract. Since the `DeFi` contract is trying\n/// to pull funds from an account that is not its own, it needs to convince the `Token` contract that it is allowed to\n/// do so.\n///\n/// This is where the authentication witness comes in The `Token` contract computes a `message_hash` from the\n/// `transfer` call, and then asks `Alice Account` contract to verify that the `DeFi` contract is allowed to execute\n/// that call.\n///\n/// `Alice Account` contract can then ask `Alice` if she wants to allow the `DeFi` contract to pull funds from her\n/// account. If she does, she will sign the `message_hash` and return the signature to the `Alice Account` which will\n/// validate it and return success to the `Token` contract which will then allow the `DeFi` contract to pull funds from\n/// `Alice`.\n///\n/// To ensure that the same \"approval\" cannot be used multiple times, we also compute a `nullifier` for the\n/// authentication witness, and emit it from the `Token` contract (consumer).\n///\n/// Note that we can do this flow as we are in private were we can do oracle calls out from contracts.\n///\n///\n/// Person Contract Contract Contract\n/// Alice Alice Account Token DeFi\n/// | | | |\n/// | Defi.deposit(Token, 1000) | |\n/// |----------------->| | |\n/// | | deposit(Token, 1000) |\n/// | |---------------------------------------->|\n/// | | | |\n/// | | | transfer(Alice, Defi, 1000)\n/// | | |<---------------------|\n/// | | | |\n/// | | Check if Defi may call transfer(Alice, Defi, 1000)\n/// | |<-----------------| |\n/// | | | |\n/// | Please give me AuthWit for DeFi | |\n/// | calling transfer(Alice, Defi, 1000) | |\n/// |<-----------------| | |\n/// | | | |\n/// | | | |\n/// | AuthWit for transfer(Alice, Defi, 1000) |\n/// |----------------->| | |\n/// | | AuthWit validity | |\n/// | |----------------->| |\n/// | | | |\n/// | | throw if invalid AuthWit |\n/// | | | |\n/// | | emit AuthWit nullifier |\n/// | | | |\n/// | | transfer(Alice, Defi, 1000) |\n/// | | | |\n/// | | | |\n/// | | | success |\n/// | | |--------------------->|\n/// | | | |\n/// | | | |\n/// | | | deposit(Token, 1000)\n/// | | | |\n/// | | | |\n///\n///\n/// If we instead were in public, we cannot do the same flow. Instead we would use an authentication registry to store\n/// the messages that we have approved.\n///\n/// To approve a message, `Alice Account` can make a `set_authorized` call to the registry, to set a `message_hash` as\n/// authorized. This is essentially a mapping from `message_hash` to `true` for `Alice Contract`. Every account has its\n/// own map in the registry, so `Alice` cannot approve a message for `Bob`.\n///\n/// The `Token` contract can then try to \"spend\" the approval by calling `consume` on the registry. If the message was\n/// approved, the value is updated to `false`, and we return the success flag. For more information on the registry,\n/// see `main.nr` in `auth_registry_contract`.\n///\n/// Person Contract Contract Contract Contract\n/// Alice Alice Account Registry Token DeFi\n/// | | | | |\n/// | Registry.set_authorized(..., true) | | |\n/// |----------------->| | | |\n/// | | set_authorized(..., true) | |\n/// | |------------------->| | |\n/// | | | | |\n/// | | set authorized to true | |\n/// | | | | |\n/// | | | | |\n/// | Defi.deposit(Token, 1000) | | |\n/// |----------------->| | | |\n/// | | deposit(Token, 1000) | |\n/// | |-------------------------------------------------------------->|\n/// | | | | |\n/// | | | transfer(Alice, Defi, 1000) |\n/// | | | |<---------------------|\n/// | | | | |\n/// | | | Check if Defi may call transfer(Alice, Defi, 1000)\n/// | | |<------------------| |\n/// | | | | |\n/// | | throw if invalid AuthWit | |\n/// | | | | |\n/// | | | | |\n/// | | set authorized to false | |\n/// | | | | |\n/// | | | | |\n/// | | | AuthWit validity | |\n/// | | |------------------>| |\n/// | | | | |\n/// | | | | transfer(Alice, Defi, 1000)\n/// | | | |<-------------------->|\n/// | | | | |\n/// | | | | success |\n/// | | | |--------------------->|\n/// | | | | |\n/// | | | | deposit(Token, 1000)\n/// | | | | |\n///\n///\n/// --- FAQ ---\n/// Q: Why are we using a success flag of `poseidon2_hash_bytes(\"IS_VALID()\")` instead of just returning a boolean?\n/// A: We want to make sure that we don't accidentally return `true` if there is a collision in the function\n/// selector. By returning a hash of `IS_VALID()`, it becomes very unlikely that there is both a collision and we\n/// return a success flag.\n///\n/// Q: Why are we using static calls?\n/// A: We are using static calls to ensure that the account contract cannot re-enter. If it was a normal call, it\n/// could make a new call and do a re-entry attack. Using a static ensures that it cannot update any state.\n///\n/// Q: Would it not be cheaper to use a nullifier instead of updating state in public?\n/// A: At a quick glance, a public state update + nullifier is 96 bytes, but two state updates are 128, so it would\n/// be cheaper to use a nullifier, if this is the way it would always be done. However, if both the approval and the\n/// consumption is done in the same transaction, then we will be able to squash the updates (only final tx state diff\n/// is posted to DA), and now it is cheaper.\n///\n/// Q: Why is the chain id and the version part of the message hash?\n/// A: The chain id and the version is part of the message hash to ensure that the message is only valid on a\n/// specific chain to avoid a case where the same message could be used across multiple chains.\n\npub global IS_VALID_SELECTOR: Field = 0x47dacd73; // 4 last bytes of\n// poseidon2_hash_bytes(\"IS_VALID()\")\n\n/// A struct that represents a contract call the user can authorize. It's associated identifier is generated by\n/// serializing and hashing it. The user is expected to sign this hash to signal the contract call can be performed on\n/// their behalf\n#[authorization]\nstruct CallAuthorization {\n msg_sender: AztecAddress,\n selector: FunctionSelector,\n args_hash: Field,\n}\n\n/// A struct that represents a request to authorize a call, which is used to emit an offchain effect so the user/wallet\n/// can understand what they are being asked to sign. It is generated from a CallAuthorization by adding metadata to\n/// it, such as the selector for the authorization, the inner hash, and the actual arguments that are being passed to\n/// the function call.\n#[derive(Serialize)]\nstruct CallAuthorizationRequest {\n selector: AuthorizationSelector,\n inner_hash: Field,\n on_behalf_of: AztecAddress,\n msg_sender: AztecAddress,\n fn_selector: FunctionSelector,\n args_hash: Field,\n}\n\nunconstrained fn emit_authorization_as_offchain_effect(\n authorization: CallAuthorization,\n inner_hash: Field,\n on_behalf_of: AztecAddress,\n) {\n let args: [Field; N] = load(authorization.args_hash);\n let authorization_request = CallAuthorizationRequest {\n selector: authorization.get_authorization_selector(),\n inner_hash: inner_hash,\n on_behalf_of: on_behalf_of,\n msg_sender: authorization.msg_sender,\n fn_selector: authorization.selector,\n args_hash: authorization.args_hash,\n };\n emit_offchain_effect(authorization_request.serialize().concat(args))\n}\n\n/// Assert that `on_behalf_of` has authorized the current call with a valid authentication witness\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Additionally, this function emits the identifying information of the call as an offchain effect so PXE can rely the\n/// information to the user/wallet in a readable way. To that effect, it is generic over N, where N is the number of\n/// arguments the authorized functions takes. This is used to load the arguments from the execution cache. This\n/// function is intended to be called via a macro, which will use the turbofish operator to specify the number of\n/// arguments.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call\npub fn assert_current_call_valid_authwit(context: &mut PrivateContext, on_behalf_of: AztecAddress) {\n let args_hash: Field = context.get_args_hash();\n\n let authorization =\n CallAuthorization { msg_sender: context.maybe_msg_sender().unwrap(), selector: context.selector(), args_hash };\n let inner_hash = compute_inner_authwit_hash(authorization.serialize());\n // Safety: Offchain effects are by definition unconstrained. They are emitted via an oracle which we don't use for\n // anything besides its side effects, therefore this is safe to call.\n unsafe { emit_authorization_as_offchain_effect::(authorization, inner_hash, on_behalf_of) };\n\n assert_inner_hash_valid_authwit(context, on_behalf_of, inner_hash);\n}\n\n/// Assert that a specific `inner_hash` is valid for the `on_behalf_of` address\n///\n/// Used as an internal function for `assert_current_call_valid_authwit` and can be used as a standalone function when\n/// the `inner_hash` is from a different source, e.g., say a block of text etc.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call @param inner_hash The hash of the\n/// message to authorize\npub fn assert_inner_hash_valid_authwit(context: &mut PrivateContext, on_behalf_of: AztecAddress, inner_hash: Field) {\n // We perform a static call here and not a standard one to ensure that the account contract cannot re-enter.\n let result: Field = context\n .static_call_private_function(\n on_behalf_of,\n comptime { FunctionSelector::from_signature(\"verify_private_authwit(Field)\") },\n [inner_hash],\n )\n .get_preimage();\n assert(result == IS_VALID_SELECTOR, \"Message not authorized by account\");\n // Compute the nullifier, similar computation to the outer hash, but without the chain_id and version. Those should\n // already be handled in the verification, so we just need something to nullify, that allows the same inner_hash\n // for multiple actors.\n let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash);\n context.push_nullifier(nullifier);\n}\n\n/// Assert that `on_behalf_of` has authorized the current call in the authentication registry\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Note that the authentication registry will take the `msg_sender` into account as the consumer, so this will only\n/// work if the `msg_sender` is the same as the `consumer` when the `message_hash` was inserted into the registry.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call\npub unconstrained fn assert_current_call_valid_authwit_public(context: PublicContext, on_behalf_of: AztecAddress) {\n let inner_hash = compute_inner_authwit_hash([\n context.maybe_msg_sender().unwrap().to_field(),\n context.selector().to_field(),\n context.get_args_hash(),\n ]);\n assert_inner_hash_valid_authwit_public(context, on_behalf_of, inner_hash);\n}\n\n/// Assert that `on_behalf_of` has authorized a specific `inner_hash` in the authentication registry\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Note that the authentication registry will take the `msg_sender` into account as the consumer, so this will only\n/// work if the `msg_sender` is the same as the `consumer` when the `message_hash` was inserted into the registry.\n///\n/// @param on_behalf_of The address that has allegedly authorized the `inner_hash`\npub unconstrained fn assert_inner_hash_valid_authwit_public(\n context: PublicContext,\n on_behalf_of: AztecAddress,\n inner_hash: Field,\n) {\n let results: [Field] = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"consume((Field),Field)\") },\n [on_behalf_of.to_field(), inner_hash],\n GasOpts::default(),\n );\n assert(results.len() == 1, \"Invalid response from registry\");\n assert(results[0] == IS_VALID_SELECTOR, \"Message not authorized by account\");\n}\n\n/// Compute the `message_hash` from a function call to be used by an authentication witness\n///\n/// Useful for when you need a non-account contract to approve during execution. For example if you need a contract to\n/// make a call to nested contract, e.g., contract A wants to exit token T to L1 using bridge B, so it needs to allow B\n/// to transfer T on its behalf.\n///\n/// @param caller The address of the contract that is calling the function, in the example above, this would be B\n/// @param consumer The address of the contract that is consuming the message, in the example above, this would be T\n/// @param chain_id The chain id of the chain that the message is being consumed on @param version The version of the\n/// chain that the message is being consumed on @param selector The function selector of the function that is being\n/// called @param args The arguments of the function that is being called\npub fn compute_authwit_message_hash_from_call(\n caller: AztecAddress,\n consumer: AztecAddress,\n chain_id: Field,\n version: Field,\n selector: FunctionSelector,\n args: [Field; N],\n) -> Field {\n let args_hash = hash_args(args);\n let inner_hash = compute_inner_authwit_hash([caller.to_field(), selector.to_field(), args_hash]);\n compute_authwit_message_hash(consumer, chain_id, version, inner_hash)\n}\n\n/// Computes the `inner_hash` of the authentication witness\n///\n/// This is used internally, but also useful in cases where you want to compute the `inner_hash` for a specific message\n/// that is not necessarily a call, but just some \"bytes\" or text.\n///\n/// @param args The arguments to hash\npub fn compute_inner_authwit_hash(args: [Field; N]) -> Field {\n poseidon2_hash_with_separator(args, DOM_SEP__AUTHWIT_INNER)\n}\n\n/// Computes the `authwit_nullifier` for a specific `on_behalf_of` and `inner_hash`\n///\n/// Using the `on_behalf_of` and the `inner_hash` to ensure that the nullifier is siloed for a specific `on_behalf_of`.\n///\n/// @param on_behalf_of The address that has authorized the `inner_hash` @param inner_hash The hash of the message to\n/// authorize\npub fn compute_authwit_nullifier(on_behalf_of: AztecAddress, inner_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [on_behalf_of.to_field(), inner_hash],\n DOM_SEP__AUTHWIT_NULLIFIER,\n )\n}\n\n/// Computes the `message_hash` for the authentication witness\n///\n/// @param consumer The address of the contract that is consuming the message @param chain_id The chain id of the chain\n/// that the message is being consumed on @param version The version of the chain that the message is being consumed on\n/// @param inner_hash The hash of the \"inner\" message that is being consumed\npub fn compute_authwit_message_hash(\n consumer: AztecAddress,\n chain_id: Field,\n version: Field,\n inner_hash: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [consumer.to_field(), chain_id, version, inner_hash],\n DOM_SEP__AUTHWIT_OUTER,\n )\n}\n\n/// Helper function to set the authorization status of a message hash\n///\n/// Wraps a public call to the authentication registry to set the authorization status of a `message_hash`\n///\n/// @param message_hash The hash of the message to authorize @param authorize True if the message should be authorized,\n/// false if it should be revoked\npub unconstrained fn set_authorized(context: PublicContext, message_hash: Field, authorize: bool) {\n let res = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"set_authorized(Field,bool)\") },\n [message_hash, authorize as Field],\n GasOpts::default(),\n );\n assert(res.len() == 0);\n}\n\n/// Helper function to reject all authwits\n///\n/// Wraps a public call to the authentication registry to set the `reject_all` flag\n///\n/// @param reject True if all authwits should be rejected, false otherwise\npub unconstrained fn set_reject_all(context: PublicContext, reject: bool) {\n let res = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"set_reject_all(bool)\") },\n [reject as Field],\n GasOpts::default(),\n );\n assert(res.len() == 0);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/authwit/auth.nr","function_locations":[{"start":14768,"name":"emit_authorization_as_offchain_effect"},{"start":16200,"name":"assert_current_call_valid_authwit"},{"start":17389,"name":"assert_inner_hash_valid_authwit"},{"start":18929,"name":"assert_current_call_valid_authwit_public"},{"start":19955,"name":"assert_inner_hash_valid_authwit_public"},{"start":21499,"name":"compute_authwit_message_hash_from_call"},{"start":22083,"name":"compute_inner_authwit_hash"},{"start":22585,"name":"compute_authwit_nullifier"},{"start":23238,"name":"compute_authwit_message_hash"},{"start":23815,"name":"set_authorized"},{"start":24381,"name":"set_reject_all"}]},"59":{"source":"use crate::oracle::capsules;\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// A dynamically sized array backed by PXE's non-volatile database (called capsules). Values are persisted until\n/// deleted, so they can be e.g. stored during simulation of a transaction and later retrieved during witness\n/// generation. All values are scoped per contract address, so external contracts cannot access them.\npub struct CapsuleArray {\n contract_address: AztecAddress,\n /// The base slot is where the array length is stored in capsules. Array elements are stored in consecutive slots\n /// after the base slot. For example, with base slot 5: the length is at slot 5, the first element (index 0) is at\n /// slot 6, the second element (index 1) is at slot 7, and so on.\n base_slot: Field,\n /// Scope for capsule isolation. Capsule operations are scoped to the given address, allowing multiple independent\n /// namespaces within the same contract.\n scope: AztecAddress,\n}\n\nimpl CapsuleArray {\n /// Returns a CapsuleArray scoped to a specific address.\n ///\n /// Array elements are stored in contiguous slots\n /// following the base slot, so there should be sufficient space between array base slots to accommodate elements.\n /// A reasonable strategy is to make the base slot a hash of a unique value.\n pub unconstrained fn at(contract_address: AztecAddress, base_slot: Field, scope: AztecAddress) -> Self {\n Self { contract_address, base_slot, scope }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n // An uninitialized array defaults to a length of 0.\n capsules::load(self.contract_address, self.base_slot, self.scope).unwrap_or(0) as u32\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let current_length = self.len();\n\n // The slot corresponding to the index `current_length` is the first slot immediately after the end of the\n // array, which is where we want to place the new value.\n capsules::store(\n self.contract_address,\n self.slot_at(current_length),\n value,\n self.scope,\n );\n\n // Then we simply update the length.\n let new_length = current_length + 1;\n capsules::store(\n self.contract_address,\n self.base_slot,\n new_length,\n self.scope,\n );\n }\n\n /// Retrieves the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n assert(index < self.len(), \"Attempted to read past the length of a CapsuleArray\");\n\n capsules::load(self.contract_address, self.slot_at(index), self.scope).unwrap()\n }\n\n /// Deletes the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n let current_length = self.len();\n assert(index < current_length, \"Attempted to delete past the length of a CapsuleArray\");\n\n // In order to be able to remove elements at arbitrary indices, we need to shift the entire contents of the\n // array past the removed element one slot backward so that we don't end up with a gap and preserve the\n // contiguous slots. We can skip this when deleting the last element however.\n if index != current_length - 1 {\n // The source and destination regions overlap, but `copy` supports this.\n capsules::copy(\n self.contract_address,\n self.slot_at(index + 1),\n self.slot_at(index),\n current_length - index - 1,\n self.scope,\n );\n }\n\n // We can now delete the last element (which has either been copied to the slot immediately before it, or was\n // the element we meant to delete in the first place) and update the length.\n capsules::delete(\n self.contract_address,\n self.slot_at(current_length - 1),\n self.scope,\n );\n capsules::store(\n self.contract_address,\n self.base_slot,\n current_length - 1,\n self.scope,\n );\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. The order in which values\n /// are processed is arbitrary.\n ///\n /// ## Array Mutation\n ///\n /// It is safe to delete the current element (and only the current element) from inside the callback via `remove`:\n /// ```noir\n /// array.for_each(|index, value| {\n /// if some_condition(value) {\n /// array.remove(index); // safe only for this index\n /// }\n /// }\n /// ```\n ///\n /// If all elements in the array need to iterated over and then removed, then using `for_each` results in optimal\n /// efficiency.\n ///\n /// It is **not** safe to push new elements into the array from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n // Iterating over all elements is simple, but we want to do it in such a way that a) deleting the current\n // element is safe to do, and b) deleting *all* elements is optimally efficient. This is because CapsuleArrays\n // are typically used to hold pending tasks, so iterating them while clearing completed tasks (sometimes\n // unconditionally, resulting in a full clear) is a very common access pattern.\n //\n // The way we achieve this is by iterating backwards: each element can always be deleted since it won't change\n // any preceding (lower) indices, and if every element is deleted then every element will (in turn) be the last\n // element. This results in an optimal full clear since `remove` will be able to skip the `capsules::copy` call\n // to shift any elements past the deleted one (because there will be none).\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n\n unconstrained fn slot_at(self, index: u32) -> Field {\n // Elements are stored immediately after the base slot, so we add 1 to it to compute the slot for the first\n // element.\n self.base_slot + 1 + index as Field\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::CapsuleArray;\n\n global SLOT: Field = 1230;\n\n #[test]\n unconstrained fn empty_array() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array: CapsuleArray = CapsuleArray::at(contract_address, SLOT, scope);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn empty_array_read() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n let _: Field = array.get(0);\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn read_past_len() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(5);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 8);\n assert_eq(array.get(2), 9);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We store all values that we were called with and check that all (value, index) tuples are present. Note\n // that we do not care about the order in which each tuple was passed to the closure.\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all_no_copy() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We test that the aztec_utl_copyCapsule was never called, which is the expensive operation we want to\n // avoid.\n let mock = std::test::OracleMock::mock(\"aztec_utl_copyCapsule\");\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(mock.times_called(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_scopes_are_isolated() {\n let mut env = TestEnvironment::new();\n let scope_a = env.create_light_account();\n let scope_b = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array_a = CapsuleArray::at(contract_address, SLOT, scope_a);\n let array_b = CapsuleArray::at(contract_address, SLOT, scope_b);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/capsules/mod.nr","function_locations":[{"start":1478,"name":"CapsuleArray::at"},{"start":1641,"name":"CapsuleArray::len"},{"start":1935,"name":"CapsuleArray::push"},{"start":2748,"name":"CapsuleArray::get"},{"start":3083,"name":"CapsuleArray::remove"},{"start":5345,"name":"CapsuleArray::for_each"},{"start":6413,"name":"CapsuleArray::slot_at"},{"start":6789,"name":"test::empty_array"},{"start":7263,"name":"test::empty_array_read"},{"start":7638,"name":"test::array_push"},{"start":8156,"name":"test::read_past_len"},{"start":8559,"name":"test::array_remove_last"},{"start":8997,"name":"test::array_remove_some"},{"start":9729,"name":"test::array_remove_all"},{"start":10296,"name":"test::for_each_called_with_all_elements"},{"start":11389,"name":"test::for_each_remove_some"},{"start":12081,"name":"test::for_each_remove_all"},{"start":12619,"name":"test::for_each_remove_all_no_copy"},{"start":13383,"name":"test::different_scopes_are_isolated"}]},"68":{"source":"use crate::{\n context::gas::GasOpts,\n hash::{\n compute_l1_to_l2_message_hash, compute_l1_to_l2_message_nullifier, compute_secret_hash,\n compute_siloed_nullifier,\n },\n oracle::avm,\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::{AztecAddress, EthAddress},\n constants::{MAX_U32_VALUE, NULL_MSG_SENDER_CONTRACT_ADDRESS},\n traits::{Empty, FromField, Packable, Serialize, ToField},\n utils::writer::Writer,\n};\n\n/// # PublicContext\n///\n/// The **main interface** between an #[external(\"public\")] function and the Aztec blockchain.\n///\n/// An instance of the PublicContext is initialized automatically at the outset of every public function, within the\n/// #[external(\"public\")] macro, so you'll never need to consciously instantiate this yourself.\n///\n/// The instance is always named `context`, and it will always be available within the body of every\n/// #[external(\"public\")] function in your smart contract.\n///\n/// Typical usage for a smart contract developer will be to call getter methods of the PublicContext.\n///\n/// _Pushing_ data and requests to the context is mostly handled within aztec-nr's own functions, so typically a smart\n/// contract developer won't need to call any setter methods directly.\n///\n/// ## Responsibilities\n/// - Exposes contextual data to a public function:\n/// - Data relating to how this public function was called:\n/// - msg_sender, this_address\n/// - Data relating to the current blockchain state:\n/// - timestamp, block_number, chain_id, version\n/// - Gas and fee information\n/// - Provides state access:\n/// - Read/write public storage (key-value mapping)\n/// - Check existence of notes and nullifiers (Some patterns use notes & nullifiers to store public (not private)\n/// information)\n/// - Enables consumption of L1->L2 messages.\n/// - Enables calls to other public smart contract functions:\n/// - Writes data to the blockchain:\n/// - Updates to public state variables\n/// - New public logs (for events)\n/// - New L2->L1 messages\n/// - New notes & nullifiers (E.g. pushing public info to notes/nullifiers, or for completing \"partial notes\")\n///\n/// ## Key Differences from Private Execution\n///\n/// Unlike private functions -- which are executed on the user's device and which can only reference historic state --\n/// public functions are executed by a block proposer and are executed \"live\" on the _current_ tip of the chain. This\n/// means public functions can:\n/// - Read and write _current_ public state\n/// - Immediately see the effects of earlier transactions in the same block\n///\n/// Also, public functions are executed within a zkVM (the \"AVM\"), so that they can _revert_ whilst still ensuring\n/// payment to the proposer and prover. (Private functions cannot revert: they either succeed, or they cannot be\n/// included).\n///\n/// ## Optimising Public Functions\n///\n/// Using the AVM to execute public functions means they compile down to \"AVM bytecode\" instead of the ACIR that\n/// private functions (standalone circuits) compile to. Therefore the approach to optimising a public function is\n/// fundamentally different from optimising a public function.\n///\npub struct PublicContext {\n pub args_hash: Option,\n pub compute_args_hash: fn() -> Field,\n}\n\nimpl Eq for PublicContext {\n fn eq(self, other: Self) -> bool {\n (self.args_hash == other.args_hash)\n // Can't compare the function compute_args_hash\n }\n}\n\nimpl PublicContext {\n /// Creates a new PublicContext instance.\n ///\n /// Low-level function: This is called automatically by the #[external(\"public\")] macro, so you shouldn't need to\n /// be called directly by smart contract developers.\n ///\n /// # Arguments\n /// * `compute_args_hash` - Function to compute the args_hash\n ///\n /// # Returns\n /// * A new PublicContext instance\n ///\n pub fn new(compute_args_hash: fn() -> Field) -> Self {\n PublicContext { args_hash: Option::none(), compute_args_hash }\n }\n\n /// Emits a _public_ log that will be visible onchain to everyone.\n ///\n /// # Arguments\n /// * `tag` - A tag placed at `fields[0]` of the emitted log. Nodes index logs by this value, allowing\n /// clients to efficiently query for matching logs without scanning all of them.\n /// * `log` - The data to log, must implement Serialize trait.\n ///\n /// ## Safety\n ///\n /// The `tag` should be domain-separated (e.g. via [`crate::protocol::hash::compute_log_tag`]) to prevent\n /// collisions between logs from different sources. Without domain separation, two unrelated log types that\n /// happen to share a raw tag value become indistinguishable. Prefer `self.emit(event)` for events, which\n /// handles tagging automatically.\n pub fn emit_public_log_unsafe(_self: Self, tag: Field, log: T)\n where\n T: Serialize,\n {\n // We use a Writer to serialize the log directly after the tag, avoiding an extra O(n) copy that would\n // result from serializing first and then prepending the tag.\n let mut writer: Writer<1 + ::N> = Writer::new();\n writer.write(tag);\n Serialize::stream_serialize(log, &mut writer);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_public_log(writer.finish().as_vector()) };\n }\n\n /// Checks if a given note hash exists in the note hash tree at a particular leaf_index.\n ///\n /// # Arguments\n /// * `note_hash` - The note hash to check for existence\n /// * `leaf_index` - The index where the note hash should be located\n ///\n /// # Returns\n /// * `bool` - True if the note hash exists at the specified index\n ///\n pub fn note_hash_exists(_self: Self, note_hash: Field, leaf_index: u64) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::note_hash_exists(note_hash, leaf_index)\n }\n }\n\n /// Checks if a specific L1-to-L2 message exists in the L1-to-L2 message tree at a particular leaf index.\n ///\n /// Common use cases include token bridging, cross-chain governance, and triggering L2 actions based on L1 events.\n ///\n /// This function should be called before attempting to consume an L1-to-L2 message.\n ///\n /// # Arguments\n /// * `msg_hash` - Hash of the L1-to-L2 message to check\n /// * `msg_leaf_index` - The index where the message should be located\n ///\n /// # Returns\n /// * `bool` - True if the message exists at the specified index\n ///\n /// # Advanced\n /// * Uses the AVM l1_to_l2_msg_exists opcode for tree lookup\n /// * Messages are copied from L1 Inbox to L2 by block proposers\n ///\n pub fn l1_to_l2_msg_exists(_self: Self, msg_hash: Field, msg_leaf_index: Field) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself TODO(alvaro): Make l1l2msg leaf index a u64 upstream\n unsafe {\n avm::l1_to_l2_msg_exists(msg_hash, msg_leaf_index as u64)\n }\n }\n\n /// Returns `true` if an `unsiloed_nullifier` has been emitted by `contract_address`.\n ///\n /// Note that unsiloed nullifiers are not the actual values stored in the nullifier tree: they are first siloed via\n /// [`crate::hash::compute_siloed_nullifier`] with the emitting contract's address.\n ///\n /// ## Use Cases\n ///\n /// Nullifiers are typically used as a _privacy-preserving_ record of a one-time action, but they can also be used\n /// to efficiently record _public_ one-time actions as well. This is cheaper than using public storage, and has the\n /// added benefit of the nullifier being emittable from a private function.\n ///\n /// An example is to check whether a contract has been published: we emit a nullifier that is deterministic and\n /// which has a _public_ preimage.\n ///\n /// ## Public vs Private\n ///\n /// In general, one should not attempt to prove nullifier non-existence in private, as that will not consider the\n /// possibility of the nullifier having been emitted in any transaction between the anchor block and the inclusion\n /// block. Private functions instead prove existence via\n /// [`crate::context::PrivateContext::assert_nullifier_exists`]\n /// and 'prove' non-existence by _emitting_ the nullifer, which would cause the transaction to fail if the\n /// nullifier existed.\n ///\n /// This is not the case in public functions, which **do** have access to the tip of the blockchain and so can\n /// reliably prove whether a nullifier exists or not.\n ///\n /// ## Safety\n ///\n /// While it is safe to rely on this function's return value to determine if a nullifier exists or not, it is often\n /// **not** safe to infer additional information from that. In particular, it is **unsafe** to infer that the\n /// existence of a nullifier emitted from a private function implies that all other side-effects of said private\n /// execution have been completed, more concretely that any enqueued public calls have been executed.\n ///\n /// For example, if a function in contract `A` privately emits nullifier `X` and then enqueues public function `Y`,\n /// then it is **unsafe** for a contract `B` to infer that `Y` has alredy executed simply because `X` exists.\n ///\n /// This is because **all** private transaction effects are committed _before_ enqueued public functions are run\n /// (in\n /// order to not reveal detailed timing information about the transaction), so it is possible to observe a\n /// nullifier that was emitted alongside the enqueuing of a public call **before** said call has been completed.\n ///\n /// ## Cost\n ///\n /// This emits the `CHECKNULLIFIEREXISTS` opcode, which conceptually performs a merkle inclusion proof on the\n /// nullifier tree (both when the nullifier exists and when it doesn't).\n pub fn nullifier_exists_unsafe(_self: Self, unsiloed_nullifier: Field, contract_address: AztecAddress) -> bool {\n let siloed_nullifier = compute_siloed_nullifier(contract_address, unsiloed_nullifier);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::nullifier_exists(siloed_nullifier)\n }\n }\n\n /// Consumes a message sent from Ethereum (L1) to Aztec (L2) -- effectively marking it as \"read\".\n ///\n /// Use this function if you only want the message to ever be \"referred to\" once. Once consumed using this method,\n /// the message cannot be consumed again, because a nullifier is emitted. If your use case wants for the message to\n /// be read unlimited times, then you can always read any historic message from the L1-to-L2 messages tree, using\n /// the `l1_to_l2_msg_exists` method. Messages never technically get deleted from that tree.\n ///\n /// The message will first be inserted into an Aztec \"Inbox\" smart contract on L1. It will not be available for\n /// consumption immediately. Messages get copied-over from the L1 Inbox to L2 by the next Proposer in batches. So\n /// you will need to wait until the messages are copied before you can consume them.\n ///\n /// # Arguments\n /// * `content` - The message content that was sent from L1\n /// * `secret` - Secret value used for message privacy (if needed)\n /// * `sender` - Ethereum address that sent the message\n /// * `leaf_index` - Index of the message in the L1-to-L2 message tree\n ///\n /// # Advanced\n /// * Validates message existence in the L1-to-L2 message tree\n /// * Prevents double-consumption by emitting a nullifier\n /// * Message hash is computed from all parameters + chain context\n /// * Will revert if message doesn't exist or was already consumed\n ///\n pub fn consume_l1_to_l2_message(self: Self, content: Field, secret: Field, sender: EthAddress, leaf_index: Field) {\n let secret_hash = compute_secret_hash(secret);\n let message_hash = compute_l1_to_l2_message_hash(\n sender,\n self.chain_id(),\n /*recipient=*/\n self.this_address(),\n self.version(),\n content,\n secret_hash,\n leaf_index,\n );\n let nullifier = compute_l1_to_l2_message_nullifier(message_hash, secret);\n\n assert(!self.nullifier_exists_unsafe(nullifier, self.this_address()), \"L1-to-L2 message is already nullified\");\n assert(self.l1_to_l2_msg_exists(message_hash, leaf_index), \"Tried to consume nonexistent L1-to-L2 message\");\n\n self.push_nullifier(nullifier);\n }\n\n /// Sends an \"L2 -> L1 message\" from this function (Aztec, L2) to a smart contract on Ethereum (L1). L1 contracts\n /// which are designed to send/receive messages to/from Aztec are called \"Portal Contracts\".\n ///\n /// Common use cases include withdrawals, cross-chain asset transfers, and triggering L1 actions based on L2 state\n /// changes.\n ///\n /// The message will be inserted into an Aztec \"Outbox\" contract on L1, when this transaction's block is proposed\n /// to L1. Sending the message will not result in any immediate state changes in the target portal contract. The\n /// message will need to be manually consumed from the Outbox through a separate Ethereum transaction: a user will\n /// need to call a function of the portal contract -- a function specifically designed to make a call to the Outbox\n /// to consume the message. The message will only be available for consumption once the _epoch_ proof has been\n /// submitted. Given that there are multiple Aztec blocks within an epoch, it might take some time for this epoch\n /// proof to be submitted -- especially if the block was near the start of an epoch.\n ///\n /// # Arguments\n /// * `recipient` - Ethereum address that will receive the message\n /// * `content` - Message content (32 bytes as a Field element)\n ///\n pub fn message_portal(_self: Self, recipient: EthAddress, content: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::send_l2_to_l1_msg(recipient, content) };\n }\n\n /// Calls a public function on another contract.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Arguments to pass to the function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn call_public_function(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Makes a read-only call to a public function on another contract.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be staticcalls.\n ///\n /// Useful for querying data from other contracts safely.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Array of arguments to pass to the called function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn static_call_public_function(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call_static(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Adds a new note hash to the Aztec blockchain's global Note Hash Tree.\n ///\n /// Notes are ordinarily constructed and emitted by _private_ functions, to ensure that both the content of the\n /// note, and the contract that emitted the note, stay private.\n ///\n /// There are however some useful patterns whereby a note needs to contain _public_ data. The ability to push a new\n /// note_hash from a _public_ function means that notes can be injected with public data immediately -- as soon as\n /// the public value is known. The slower alternative would be to submit a follow-up transaction so that a private\n /// function can inject the data. Both are possible on Aztec.\n ///\n /// Search \"Partial Note\" for a very common pattern which enables a note to be \"partially\" populated with some data\n /// in a _private_ function, and then later \"completed\" with some data in a public function.\n ///\n /// # Arguments\n /// * `note_hash` - The hash of the note to add to the tree\n ///\n /// # Advanced\n /// * The note hash will be siloed with the contract address by the protocol\n ///\n pub fn push_note_hash(_self: Self, note_hash: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_note_hash(note_hash) };\n }\n\n /// Creates a new [nullifier](crate::nullifier).\n ///\n /// While nullifiers are primarily intended as a _privacy-preserving_ record of a one-time action, they can also\n /// be used to efficiently record _public_ one-time actions. This function allows creating nullifiers from public\n /// contract functions, which behave just like those created from private functions.\n ///\n /// ## Safety\n ///\n /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state.\n ///\n /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that\n /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a\n /// variable as initialized). Note nullifiers should only be created via\n /// [`crate::context::PrivateContext::push_nullifier_for_note_hash`].\n ///\n /// ## Advanced\n ///\n /// The raw `nullifier` is not what is inserted into the Aztec state tree: it will be first siloed by contract\n /// address via [`crate::protocol::hash::compute_siloed_nullifier`] in order to prevent accidental or malicious\n /// interference of nullifiers from different contracts.\n pub fn push_nullifier(_self: Self, nullifier: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_nullifier(nullifier) };\n }\n\n /// Returns the address of the current contract being executed.\n ///\n /// This is equivalent to `address(this)` in Solidity (hence the name). Use this to identify the current contract's\n /// address, commonly needed for access control or when interacting with other contracts.\n ///\n /// # Returns\n /// * `AztecAddress` - The contract address of the current function being executed.\n ///\n pub fn this_address(_self: Self) -> AztecAddress {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::address()\n }\n }\n\n /// Returns the contract address that initiated this function call.\n ///\n /// This is similar to `msg.sender` in Solidity (hence the name).\n ///\n /// Important Note: If the calling function is a _private_ function, then it had the option of hiding its address\n /// when enqueuing this public function call. In such cases, this method will return `Option::none`.\n /// If the calling function is a _public_ function, it will always return an `Option::some` (i.e. a\n /// non-null value).\n ///\n /// # Returns\n /// * `Option` - The address of the smart contract that called this function (be it an app contract\n /// or a user's account contract).\n ///\n /// # Advanced\n /// * Value is provided by the AVM sender opcode\n /// * In nested calls, this is the immediate caller, not the original transaction sender\n ///\n pub fn maybe_msg_sender(_self: Self) -> Option {\n // Safety: AVM opcodes are constrained by the AVM itself\n let maybe_msg_sender = unsafe { avm::sender() };\n if maybe_msg_sender == NULL_MSG_SENDER_CONTRACT_ADDRESS {\n Option::none()\n } else {\n Option::some(maybe_msg_sender)\n }\n }\n\n /// Returns the function selector of the currently-executing function.\n ///\n /// This is similar to `msg.sig` in Solidity, returning the first 4 bytes of the function signature.\n ///\n /// # Returns\n /// * `FunctionSelector` - The 4-byte function identifier\n ///\n /// # Advanced\n /// * Extracted from the first element of calldata\n /// * Used internally for function dispatch in the AVM\n ///\n pub fn selector(_self: Self) -> FunctionSelector {\n // The selector is the first element of the calldata when calling a public function through dispatch.\n // Safety: AVM opcodes are constrained by the AVM itself.\n let raw_selector: [Field; 1] = unsafe { avm::calldata_copy(0, 1) };\n FunctionSelector::from_field(raw_selector[0])\n }\n\n /// Returns the hash of the arguments passed to the current function.\n ///\n /// Very low-level function: The #[external(\"public\")] macro uses this internally. Smart contract developers\n /// typically won't need to access this directly as arguments are automatically made available.\n ///\n /// # Returns\n /// * `Field` - Hash of the function arguments\n ///\n pub fn get_args_hash(mut self) -> Field {\n if !self.args_hash.is_some() {\n self.args_hash = Option::some((self.compute_args_hash)());\n }\n\n self.args_hash.unwrap_unchecked()\n }\n\n /// Returns the \"transaction fee\" for the current transaction. This is the final tx fee that will be deducted from\n /// the fee_payer's \"fee-juice\" balance (in the protocol's Base Rollup circuit).\n ///\n /// # Returns\n /// * `Field` - The actual, final cost of the transaction, taking into account: the actual gas used during the\n /// setup and app-logic phases, and the fixed amount of gas that's been allocated by the user for the teardown\n /// phase. I.e. effectiveL2FeePerGas * l2GasUsed + effectiveDAFeePerGas * daGasUsed\n ///\n /// This will return `0` during the \"setup\" and \"app-logic\" phases of tx execution (because the final tx fee is not\n /// known at that time). This will only return a nonzero value during the \"teardown\" phase of execution, where the\n /// final tx fee can actually be computed.\n ///\n /// Regardless of _when_ this function is called during the teardown phase, it will always return the same final tx\n /// fee value. The teardown phase does not consume a variable amount of gas: it always consumes a pre-allocated\n /// amount of gas, as specified by the user when they generate their tx.\n ///\n pub fn transaction_fee(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::transaction_fee()\n }\n }\n\n /// Returns the chain ID of the current network.\n ///\n /// This is similar to `block.chainid` in Solidity. Returns the unique identifier for the blockchain network this\n /// transaction is executing on.\n ///\n /// Helps prevent cross-chain replay attacks. Useful if implementing multi-chain contract logic.\n ///\n /// # Returns\n /// * `Field` - The chain ID as a field element\n ///\n pub fn chain_id(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::chain_id()\n }\n }\n\n /// Returns the Aztec protocol version that this transaction is executing under. Different versions may have\n /// different rules, opcodes, or cryptographic primitives.\n ///\n /// This is similar to how Ethereum has different EVM versions.\n ///\n /// Useful for forward/backward compatibility checks\n ///\n /// Not to be confused with contract versions; this is the protocol version.\n ///\n /// # Returns\n /// * `Field` - The protocol version as a field element\n ///\n pub fn version(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::version()\n }\n }\n /// Returns the current block number.\n ///\n /// This is similar to `block.number` in Solidity.\n ///\n /// Note: the current block number is only available within a public function (as opposed to a private function).\n ///\n /// Note: the time intervals between blocks should not be relied upon as being consistent:\n /// - Timestamps of blocks fall within a range, rather than at exact regular intervals.\n /// - Slots can be missed.\n /// - Protocol upgrades can completely change the intervals between blocks (and indeed the current roadmap plans to\n /// reduce the time between blocks, eventually). Use `context.timestamp()` for more-reliable time-based logic.\n ///\n /// # Returns\n /// * `u32` - The current block number\n ///\n pub fn block_number(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::block_number()\n }\n }\n\n /// Returns the timestamp of the current block.\n ///\n /// This is similar to `block.timestamp` in Solidity.\n ///\n /// All functions of all transactions in a block share the exact same timestamp (even though technically each\n /// transaction is executed one-after-the-other).\n ///\n /// Important note: Timestamps of Aztec blocks are not at reliably-fixed intervals. The proposer of the block has\n /// some flexibility to choose a timestamp which is in a valid _range_: Obviously the timestamp of this block must\n /// be strictly greater than that of the previous block, and must must be less than the timestamp of whichever\n /// ethereum block the aztec block is proposed to. Furthermore, if the timestamp is not deemed close enough to the\n /// actual current time, the committee of validators will not attest to the block.\n ///\n /// # Returns\n /// * `u64` - Unix timestamp in seconds\n ///\n pub fn timestamp(_self: Self) -> u64 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::timestamp()\n }\n }\n\n /// Returns the fee per unit of L2 gas for this transaction (aka the \"L2 gas price\"), as chosen by the user.\n ///\n /// L2 gas covers the cost of executing public functions and handling side-effects within the AVM.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of L2 gas\n ///\n /// Wallet developers should be mindful that the choice of gas price (which is publicly visible) can leak\n /// information about the user, e.g.:\n /// - which wallet software the user is using;\n /// - the amount of time which has elapsed from the time the user's wallet chose a gas price (at the going rate),\n /// to the time of tx submission. This can give clues about the proving time, and hence the nature of the tx.\n /// - the urgency of the transaction (which is kind of unavoidable, if the tx is indeed urgent).\n /// - the wealth of the user.\n /// - the exact user (if the gas price is explicitly chosen by the user to be some unique number like 0.123456789,\n /// or their favorite number). Wallet devs might wish to consider fuzzing the choice of gas price.\n ///\n pub fn min_fee_per_l2_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_l2_gas()\n }\n }\n\n /// Returns the fee per unit of DA (Data Availability) gas (aka the \"DA gas price\").\n ///\n /// DA gas covers the cost of making transaction data available on L1.\n ///\n /// See the warning in `min_fee_per_l2_gas` for how gas prices can be leaky.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of DA gas\n ///\n pub fn min_fee_per_da_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_da_gas()\n }\n }\n\n /// Returns the remaining L2 gas available for this transaction.\n ///\n /// Different AVM opcodes consume different amounts of gas.\n ///\n /// # Returns\n /// * `u32` - Remaining L2 gas units\n ///\n pub fn l2_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::l2_gas_left()\n }\n }\n\n /// Returns the remaining DA (Data Availability) gas available for this transaction.\n ///\n /// DA gas is consumed when emitting data that needs to be made available on L1, such as public logs or state\n /// updates. All of the side-effects from the private part of the tx also consume DA gas before execution of any\n /// public functions even begins.\n ///\n /// # Returns\n /// * `u32` - Remaining DA gas units\n ///\n pub fn da_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::da_gas_left()\n }\n }\n\n /// Checks if the current execution is within a staticcall context, where no state changes or logs are allowed to\n /// be emitted (by this function or any nested function calls).\n ///\n /// # Returns\n /// * `bool` - True if in staticcall context, false otherwise\n ///\n pub fn is_static_call(_self: Self) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::is_static_call()\n }\n }\n\n /// Reads raw field values from public storage. Reads N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to read from\n ///\n /// # Returns\n /// * `[Field; N]` - Array of N field values from consecutive storage slots\n ///\n /// # Generic Parameters\n /// * `N` - the number of consecutive slots to return, starting from the `storage_slot`.\n ///\n pub fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n let mut out = [0; N];\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n out[i] = unsafe { avm::storage_read(storage_slot + i as Field, self.this_address().to_field()) };\n }\n out\n }\n\n /// Reads a typed value from public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to read from\n ///\n /// # Returns\n /// * `T` - The deserialized value from storage\n ///\n /// # Generic Parameters\n /// * `T` - The type that the caller expects to read from the `storage_slot`.\n ///\n pub fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n\n /// Writes raw field values to public storage. Writes to N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// Public storage writes take effect immediately.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to write to\n /// * `values` - Array of N Fields to write to storage\n ///\n pub fn raw_storage_write(_self: Self, storage_slot: Field, values: [Field; N]) {\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::storage_write(storage_slot + i as Field, values[i]) };\n }\n }\n\n /// Writes a typed value to public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to write to\n /// * `value` - The typed value to write to storage\n ///\n /// # Generic Parameters\n /// * `T` - The type to write to storage.\n ///\n pub fn storage_write(self, storage_slot: Field, value: T)\n where\n T: Packable,\n {\n self.raw_storage_write(storage_slot, value.pack());\n }\n}\n\nimpl Empty for PublicContext {\n fn empty() -> Self {\n PublicContext::new(|| 0)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/public_context.nr","function_locations":[{"start":3353,"name":"::eq"},{"start":3938,"name":"PublicContext::new"},{"start":4887,"name":"PublicContext::emit_public_log_unsafe"},{"start":5811,"name":"PublicContext::note_hash_exists"},{"start":6824,"name":"PublicContext::l1_to_l2_msg_exists"},{"start":10039,"name":"PublicContext::nullifier_exists_unsafe"},{"start":11904,"name":"PublicContext::consume_l1_to_l2_message"},{"start":14021,"name":"PublicContext::message_portal"},{"start":14911,"name":"PublicContext::call_public_function"},{"start":16543,"name":"PublicContext::static_call_public_function"},{"start":18327,"name":"PublicContext::push_note_hash"},{"start":19766,"name":"PublicContext::push_nullifier"},{"start":20356,"name":"PublicContext::this_address"},{"start":21451,"name":"PublicContext::maybe_msg_sender"},{"start":22223,"name":"PublicContext::selector"},{"start":22962,"name":"PublicContext::get_args_hash"},{"start":24354,"name":"PublicContext::transaction_fee"},{"start":24943,"name":"PublicContext::chain_id"},{"start":25613,"name":"PublicContext::version"},{"start":26553,"name":"PublicContext::block_number"},{"start":27665,"name":"PublicContext::timestamp"},{"start":28946,"name":"PublicContext::min_fee_per_l2_gas"},{"start":29473,"name":"PublicContext::min_fee_per_da_gas"},{"start":29871,"name":"PublicContext::l2_gas_left"},{"start":30487,"name":"PublicContext::da_gas_left"},{"start":30952,"name":"PublicContext::is_static_call"},{"start":31794,"name":"PublicContext::raw_storage_read"},{"start":32652,"name":"PublicContext::storage_read"},{"start":33320,"name":"PublicContext::raw_storage_write"},{"start":34054,"name":"PublicContext::storage_write"},{"start":34179,"name":"::empty"}]},"70":{"source":"use crate::oracle::{execution::get_utility_context, storage::storage_read};\nuse crate::protocol::{abis::block_header::BlockHeader, address::AztecAddress, traits::Packable};\n\n// If you'll modify this struct don't forget to update utility_context.ts as well.\npub struct UtilityContext {\n block_header: BlockHeader,\n contract_address: AztecAddress,\n}\n\nimpl UtilityContext {\n pub unconstrained fn new() -> Self {\n get_utility_context()\n }\n\n pub unconstrained fn at(contract_address: AztecAddress) -> Self {\n // We get a context with default contract address, and then we construct the final context with the provided\n // contract address.\n let default_context = get_utility_context();\n\n Self { block_header: default_context.block_header, contract_address }\n }\n\n pub fn block_header(self) -> BlockHeader {\n self.block_header\n }\n\n pub fn block_number(self) -> u32 {\n self.block_header.block_number()\n }\n\n pub fn timestamp(self) -> u64 {\n self.block_header.timestamp()\n }\n\n pub fn this_address(self) -> AztecAddress {\n self.contract_address\n }\n\n pub fn version(self) -> Field {\n self.block_header.version()\n }\n\n pub fn chain_id(self) -> Field {\n self.block_header.chain_id()\n }\n\n pub unconstrained fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n storage_read(self.block_header, self.this_address(), storage_slot)\n }\n\n pub unconstrained fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/utility_context.nr","function_locations":[{"start":416,"name":"UtilityContext::new"},{"start":523,"name":"UtilityContext::at"},{"start":855,"name":"UtilityContext::block_header"},{"start":927,"name":"UtilityContext::block_number"},{"start":1011,"name":"UtilityContext::timestamp"},{"start":1104,"name":"UtilityContext::this_address"},{"start":1177,"name":"UtilityContext::version"},{"start":1257,"name":"UtilityContext::chain_id"},{"start":1404,"name":"UtilityContext::raw_storage_read"},{"start":1596,"name":"UtilityContext::storage_read"}]},"72":{"source":"//! The `self` contract value for public execution contexts.\n\nuse crate::{\n context::{calls::{PublicCall, PublicStaticCall}, PublicContext},\n event::{event_emission::emit_event_in_public, event_interface::EventInterface},\n};\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Core interface for interacting with aztec-nr contract features in public execution contexts.\n///\n/// This struct is automatically injected into every [`external`](crate::macros::functions::external) and\n/// [`internal`](crate::macros::functions::internal) contract function marked with `\"public\"` by the Aztec macro\n/// system and is accessible through the `self` variable.\n///\n/// ## Type Parameters\n///\n/// - `Storage`: The contract's storage struct (defined with [`storage`](crate::macros::storage::storage), or `()` if\n/// the contract has no storage\n/// - `CallSelf`: Macro-generated type for calling contract's own non-view functions\n/// - `CallSelfStatic`: Macro-generated type for calling contract's own view functions\n/// - `CallInternal`: Macro-generated type for calling internal functions\npub struct ContractSelfPublic {\n /// The address of this contract\n pub address: AztecAddress,\n\n /// The contract's storage instance, representing the struct to which the\n /// [`storage`](crate::macros::storage::storage) macro was applied in your contract. If the contract has no\n /// storage, the type of this will be `()`.\n ///\n /// This storage instance is specialized for the current execution context (public) and\n /// provides access to the contract's state variables.\n ///\n /// ## Developer Note\n ///\n /// If you've arrived here while trying to access your contract's storage while the `Storage` generic type is set\n /// to unit type `()`, it means you haven't yet defined a Storage struct using the\n /// [`storage`](crate::macros::storage::storage) macro in your contract. For guidance on setting this up, please\n /// refer to our docs: https://docs.aztec.network/developers/docs/guides/smart_contracts/storage\n pub storage: Storage,\n\n /// The public execution context.\n pub context: PublicContext,\n\n /// Provides type-safe methods for calling this contract's own non-view functions.\n ///\n /// Example API:\n /// ```noir\n /// self.call_self.some_public_function(args)\n /// ```\n pub call_self: CallSelf,\n\n /// Provides type-safe methods for calling this contract's own view functions.\n ///\n /// Example API:\n /// ```noir\n /// self.call_self_static.some_view_function(args)\n /// ```\n pub call_self_static: CallSelfStatic,\n\n /// Provides type-safe methods for calling internal functions.\n ///\n /// Example API:\n /// ```noir\n /// self.internal.some_internal_function(args)\n /// ```\n pub internal: CallInternal,\n}\n\nimpl ContractSelfPublic {\n /// Creates a new `ContractSelfPublic` instance for a public function.\n ///\n /// This constructor is called automatically by the macro system and should not be called directly.\n pub fn new(\n context: PublicContext,\n storage: Storage,\n call_self: CallSelf,\n call_self_static: CallSelfStatic,\n internal: CallInternal,\n ) -> Self {\n Self { context, storage, address: context.this_address(), call_self, call_self_static, internal }\n }\n\n /// The address of the contract address that made this function call.\n ///\n /// This is similar to Solidity's `msg.sender` value.\n ///\n /// ## Incognito Calls\n ///\n /// Contracts can call public functions from private ones hiding their identity (see\n ///\n /// [`ContractSelfPrivate::enqueue_incognito`](crate::contract_self::ContractSelfPrivate::enqueue_incognito)).\n /// This function reverts when executed in such a context.\n ///\n /// If you need to handle these cases, use [`PublicContext::maybe_msg_sender`].\n pub fn msg_sender(self: Self) -> AztecAddress {\n self.context.maybe_msg_sender().unwrap()\n }\n\n /// Emits an event publicly.\n ///\n /// Public events are emitted as plaintext and are therefore visible to everyone. This is is the same as Solidity\n /// events on EVM chains.\n ///\n /// Unlike private events, they don't require delivery of an event message.\n ///\n /// # Example\n /// ```noir\n /// #[event]\n /// struct Update { value: Field }\n ///\n /// #[external(\"public\")]\n /// fn publish_update(value: Field) {\n /// self.emit(Update { value });\n /// }\n /// ```\n ///\n /// # Cost\n ///\n /// Public event emission is achieved by emitting public transaction logs. A total of `N+1` fields are emitted,\n /// where `N` is the serialization length of the event.\n pub fn emit(&mut self, event: Event)\n where\n Event: EventInterface + Serialize,\n {\n emit_event_in_public(self.context, event);\n }\n\n /// Makes a public contract call.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `call` - The object representing the public function to invoke.\n ///\n /// # Returns\n /// * `T` - Whatever data the called function has returned.\n ///\n /// # Example\n /// ```noir\n /// self.call(Token::at(address).transfer_in_public(recipient, amount));\n /// ```\n ///\n pub unconstrained fn call(self, call: PublicCall) -> T\n where\n T: Deserialize,\n {\n call.call(self.context)\n }\n\n /// Makes a public read-only contract call.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be static calls.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `call` - The object representing the read-only public function to invoke.\n ///\n /// # Returns\n /// * `T` - Whatever data the called function has returned.\n ///\n /// # Example\n /// ```noir\n /// self.view(Token::at(address).balance_of_public(recipient));\n /// ```\n ///\n pub unconstrained fn view(self, call: PublicStaticCall) -> T\n where\n T: Deserialize,\n {\n call.view(self.context)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/contract_self/contract_self_public.nr","function_locations":[{"start":3401,"name":"ContractSelfPublic::new"},{"start":4116,"name":"ContractSelfPublic::msg_sender"},{"start":5004,"name":"ContractSelfPublic::emit"},{"start":5645,"name":"ContractSelfPublic::call"},{"start":6466,"name":"ContractSelfPublic::view"}]},"75":{"source":"use crate::oracle::ephemeral;\nuse crate::protocol::traits::{Deserialize, Serialize};\n\n/// A dynamically sized array that exists only during a single contract call frame.\n///\n/// Ephemeral arrays are backed by in-memory storage on the PXE side rather than a persistent database. Each contract\n/// call frame gets its own isolated slot space of ephemeral arrays. Child simulations cannot see the parent's\n/// ephemeral arrays, and vice versa.\n///\n/// Each logical array operation (push, pop, get, etc.) is a single oracle call, making ephemeral arrays significantly\n/// cheaper than capsule arrays.\n///\n/// ## Use Cases\n///\n/// Ephemeral arrays are designed for passing data between PXE (TypeScript) and contracts (Noir) during simulation,\n/// for example, note validation requests or event validation responses. This data type is appropriate for data that\n/// is not supposed to be persisted.\n///\n/// For data that needs to persist across simulations, contract calls, etc, use\n/// [`CapsuleArray`](crate::capsules::CapsuleArray) instead.\npub struct EphemeralArray {\n pub slot: Field,\n}\n\nimpl EphemeralArray {\n /// Returns a handle to an ephemeral array at the given slot, which may already contain data (e.g. populated\n /// by an oracle).\n pub unconstrained fn at(slot: Field) -> Self {\n Self { slot }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n ephemeral::len_oracle(self.slot)\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n let _ = ephemeral::push_oracle(self.slot, serialized);\n }\n\n /// Removes and returns the last element. Panics if the array is empty.\n pub unconstrained fn pop(self) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::pop_oracle(self.slot);\n Deserialize::deserialize(serialized)\n }\n\n /// Retrieves the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::get_oracle(self.slot, index);\n Deserialize::deserialize(serialized)\n }\n\n /// Overwrites the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn set(self, index: u32, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n ephemeral::set_oracle(self.slot, index, serialized);\n }\n\n /// Removes the element at `index`, shifting subsequent elements backward. Panics if out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n ephemeral::remove_oracle(self.slot, index);\n }\n\n /// Removes all elements from the array and returns self for chaining (e.g. `EphemeralArray::at(slot).clear()`\n /// to get a guaranteed-empty array at a given slot).\n pub unconstrained fn clear(self) -> Self {\n ephemeral::clear_oracle(self.slot);\n self\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. Iteration proceeds\n /// backwards so that it is safe to remove the current element (and only the current element) inside the\n /// callback.\n ///\n /// It is **not** safe to push new elements from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use crate::test::mocks::MockStruct;\n use super::EphemeralArray;\n\n global SLOT: Field = 1230;\n global OTHER_SLOT: Field = 5670;\n\n #[test]\n unconstrained fn empty_array() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn empty_array_read() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.get(0);\n });\n }\n\n #[test(should_fail_with = \"is empty\")]\n unconstrained fn empty_array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.pop();\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn read_past_len() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.push(10);\n\n let popped: Field = array.pop();\n assert_eq(popped, 10);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test]\n unconstrained fn array_set() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.set(0, 99);\n assert_eq(array.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.remove(0);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_slots_are_isolated() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array_a = EphemeralArray::at(SLOT);\n let array_b = EphemeralArray::at(OTHER_SLOT);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn works_with_multi_field_type() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n\n let a = MockStruct::new(5, 6);\n let b = MockStruct::new(7, 8);\n array.push(a);\n array.push(b);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), a);\n assert_eq(array.get(1), b);\n\n let popped: MockStruct = array.pop();\n assert_eq(popped, b);\n assert_eq(array.len(), 1);\n });\n }\n\n #[test]\n unconstrained fn clear_returns_self() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(array.len(), 0);\n\n array.push(42);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 42);\n });\n }\n\n #[test]\n unconstrained fn clear_wipes_previous_data() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n array.push(1);\n array.push(2);\n array.push(3);\n assert_eq(array.len(), 3);\n\n // Clear the same slot, previous data should be gone.\n let fresh: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(fresh.len(), 0);\n fresh.push(4);\n assert_eq(fresh.get(0), 4);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/ephemeral/mod.nr","function_locations":[{"start":1305,"name":"EphemeralArray::at"},{"start":1438,"name":"EphemeralArray::len"},{"start":1618,"name":"EphemeralArray::push"},{"start":1888,"name":"EphemeralArray::pop"},{"start":2176,"name":"EphemeralArray::get"},{"start":2475,"name":"EphemeralArray::set"},{"start":2743,"name":"EphemeralArray::remove"},{"start":3022,"name":"EphemeralArray::clear"},{"start":3593,"name":"EphemeralArray::for_each"},{"start":3983,"name":"test::empty_array"},{"start":4280,"name":"test::empty_array_read"},{"start":4550,"name":"test::empty_array_pop"},{"start":4783,"name":"test::array_push"},{"start":5122,"name":"test::read_past_len"},{"start":5376,"name":"test::array_pop"},{"start":5783,"name":"test::array_set"},{"start":6081,"name":"test::array_remove_last"},{"start":6376,"name":"test::array_remove_some"},{"start":6847,"name":"test::array_remove_all"},{"start":7273,"name":"test::for_each_called_with_all_elements"},{"start":8009,"name":"test::for_each_remove_some"},{"start":8561,"name":"test::for_each_remove_all"},{"start":8960,"name":"test::different_slots_are_isolated"},{"start":9534,"name":"test::works_with_multi_field_type"},{"start":10148,"name":"test::clear_returns_self"},{"start":10535,"name":"test::clear_wipes_previous_data"}]},"77":{"source":"use crate::{event::EventSelector, messages::logs::event::MAX_EVENT_SERIALIZED_LEN};\nuse crate::protocol::{\n constants::DOM_SEP__EVENT_COMMITMENT,\n hash::{poseidon2_hash_with_separator, poseidon2_hash_with_separator_bounded_vec},\n traits::{Serialize, ToField},\n};\n\npub trait EventInterface {\n fn get_event_type_id() -> EventSelector;\n}\n\n/// A private event's commitment is a value stored on-chain which is used to verify that the event was indeed emitted.\n///\n/// It requires a `randomness` value that must be produced alongside the event in order to perform said validation.\n/// This random value prevents attacks in which someone guesses plausible events (e.g. 'Alice transfers to Bob an\n/// amount of 10'), since they will not be able to test for existence of their guessed events without brute-forcing the\n/// entire `Field` space by guessing `randomness` values.\npub fn compute_private_event_commitment(event: Event, randomness: Field) -> Field\nwhere\n Event: EventInterface + Serialize,\n{\n poseidon2_hash_with_separator(\n [randomness, Event::get_event_type_id().to_field()].concat(event.serialize()),\n DOM_SEP__EVENT_COMMITMENT,\n )\n}\n\n/// Unconstrained variant of [`compute_private_event_commitment`] which takes the event in serialized form.\n///\n/// This function is unconstrained as the mechanism it uses to compute the commitment would be very inefficient in a\n/// constrained environment (due to the hashing of a dynamically sized array). This is not an issue as it is typically\n/// invoked when processing event messages, which is an unconstrained operation.\npub unconstrained fn compute_private_serialized_event_commitment(\n serialized_event: BoundedVec,\n randomness: Field,\n event_type_id: Field,\n) -> Field {\n let mut commitment_preimage =\n BoundedVec::<_, 2 + MAX_EVENT_SERIALIZED_LEN>::from_array([randomness, event_type_id]);\n commitment_preimage.extend_from_bounded_vec(serialized_event);\n\n poseidon2_hash_with_separator_bounded_vec(commitment_preimage, DOM_SEP__EVENT_COMMITMENT)\n}\n\nmod test {\n use crate::event::event_interface::{\n compute_private_event_commitment, compute_private_serialized_event_commitment, EventInterface,\n };\n use crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN;\n use crate::protocol::traits::{Serialize, ToField};\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn max_size_serialized_event_commitment() {\n let serialized_event = BoundedVec::from_array([0; MAX_EVENT_SERIALIZED_LEN]);\n let _ = compute_private_serialized_event_commitment(serialized_event, 0, 0);\n }\n\n #[test]\n unconstrained fn event_commitment_equivalence() {\n let event = MockEvent::new(VALUE).build_event();\n\n assert_eq(\n compute_private_event_commitment(event, RANDOMNESS),\n compute_private_serialized_event_commitment(\n BoundedVec::from_array(event.serialize()),\n RANDOMNESS,\n MockEvent::get_event_type_id().to_field(),\n ),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_interface.nr","function_locations":[{"start":1013,"name":"compute_private_event_commitment"},{"start":1803,"name":"compute_private_serialized_event_commitment"},{"start":2570,"name":"test::max_size_serialized_event_commitment"},{"start":2814,"name":"test::event_commitment_equivalence"}]},"79":{"source":"use crate::protocol::{hash::poseidon2_hash_bytes, traits::{Deserialize, Empty, FromField, Serialize, ToField}};\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct EventSelector {\n // Low 32 bits of the poseidon2 hash of the event signature.\n inner: u32,\n}\n\nimpl FromField for EventSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for EventSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for EventSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl EventSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n EventSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_selector.nr","function_locations":[{"start":337,"name":"::from_field"},{"start":449,"name":"::to_field"},{"start":542,"name":"::empty"},{"start":647,"name":"EventSelector::from_u32"},{"start":751,"name":"EventSelector::from_signature"},{"start":985,"name":"EventSelector::zero"}]},"81":{"source":"//! Aztec hash functions.\n\nuse crate::protocol::{\n address::{AztecAddress, EthAddress},\n constants::{\n DOM_SEP__FUNCTION_ARGS, DOM_SEP__MESSAGE_NULLIFIER, DOM_SEP__PUBLIC_BYTECODE, DOM_SEP__PUBLIC_CALLDATA,\n DOM_SEP__SECRET_HASH, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS,\n },\n hash::{poseidon2_hash_subarray, poseidon2_hash_with_separator, sha256_to_field},\n traits::ToField,\n};\n\npub use crate::protocol::hash::compute_siloed_nullifier;\n\npub fn compute_secret_hash(secret: Field) -> Field {\n poseidon2_hash_with_separator([secret], DOM_SEP__SECRET_HASH)\n}\n\npub fn compute_l1_to_l2_message_hash(\n sender: EthAddress,\n chain_id: Field,\n recipient: AztecAddress,\n version: Field,\n content: Field,\n secret_hash: Field,\n leaf_index: Field,\n) -> Field {\n let mut hash_bytes = [0 as u8; 224];\n let sender_bytes: [u8; 32] = sender.to_field().to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n let recipient_bytes: [u8; 32] = recipient.to_field().to_be_bytes();\n let version_bytes: [u8; 32] = version.to_be_bytes();\n let content_bytes: [u8; 32] = content.to_be_bytes();\n let secret_hash_bytes: [u8; 32] = secret_hash.to_be_bytes();\n let leaf_index_bytes: [u8; 32] = leaf_index.to_be_bytes();\n\n for i in 0..32 {\n hash_bytes[i] = sender_bytes[i];\n hash_bytes[i + 32] = chain_id_bytes[i];\n hash_bytes[i + 64] = recipient_bytes[i];\n hash_bytes[i + 96] = version_bytes[i];\n hash_bytes[i + 128] = content_bytes[i];\n hash_bytes[i + 160] = secret_hash_bytes[i];\n hash_bytes[i + 192] = leaf_index_bytes[i];\n }\n\n sha256_to_field(hash_bytes)\n}\n\n// The nullifier of a l1 to l2 message is the hash of the message salted with the secret\npub fn compute_l1_to_l2_message_nullifier(message_hash: Field, secret: Field) -> Field {\n poseidon2_hash_with_separator([message_hash, secret], DOM_SEP__MESSAGE_NULLIFIER)\n}\n\n// Computes the hash of input arguments or return values for private functions, or for authwit creation.\npub fn hash_args(args: [Field; N]) -> Field {\n if args.len() == 0 {\n 0\n } else {\n poseidon2_hash_with_separator(args, DOM_SEP__FUNCTION_ARGS)\n }\n}\n\n// Computes the hash of calldata for public functions.\npub fn hash_calldata_array(calldata: [Field; N]) -> Field {\n poseidon2_hash_with_separator(calldata, DOM_SEP__PUBLIC_CALLDATA)\n}\n\n/// Computes the public bytecode commitment for a contract class. The commitment is `hash([(length | separator),\n/// ...bytecode])`.\n///\n/// @param packed_bytecode - The packed bytecode of the contract class. 0th word is the length in bytes.\n/// packed_bytecode is mutable so that we can avoid copying the array to construct one starting with first_field\n/// instead of length. @returns The public bytecode commitment.\npub fn compute_public_bytecode_commitment(\n mut packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],\n) -> Field {\n // First field element contains the length of the bytecode\n let bytecode_length_in_bytes: u32 = packed_public_bytecode[0] as u32;\n let bytecode_length_in_fields: u32 = (bytecode_length_in_bytes / 31) + (bytecode_length_in_bytes % 31 != 0) as u32;\n // Don't allow empty public bytecode. AVM doesn't handle execution of contracts that exist with empty bytecode.\n assert(bytecode_length_in_fields != 0);\n assert(bytecode_length_in_fields < MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS);\n\n // Packed_bytecode's 0th entry is the length. Append it to the separator before hashing.\n let first_field = DOM_SEP__PUBLIC_BYTECODE.to_field() + (packed_public_bytecode[0] as u64 << 32) as Field;\n packed_public_bytecode[0] = first_field;\n\n // `fields_to_hash` is the number of fields from the start of `packed_public_bytecode` that should be included in\n // the hash. Fields after this length are ignored. +1 to account for the prepended field.\n let num_fields_to_hash = bytecode_length_in_fields + 1;\n\n poseidon2_hash_subarray(packed_public_bytecode, num_fields_to_hash)\n}\n\n#[test]\nunconstrained fn secret_hash_matches_typescript() {\n let secret = 8;\n let hash = compute_secret_hash(secret);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let secret_hash_from_ts = 0x1848b066724ab0ffb50ecb0ee3398eb839f162823d262bad959721a9c13d1e96;\n\n assert_eq(hash, secret_hash_from_ts);\n}\n\n#[test]\nunconstrained fn var_args_hash_matches_typescript() {\n let mut input = [0; 100];\n for i in 0..100 {\n input[i] = i as Field;\n }\n let hash = hash_args(input);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let var_args_hash_from_ts = 0x262e5e121a8efc0382566ab42f0ae2a78bd85db88484f83018fe07fc2552ba0c;\n\n assert_eq(hash, var_args_hash_from_ts);\n}\n\n#[test]\nunconstrained fn compute_calldata_hash() {\n let mut input = [0; 100];\n for i in 0..input.len() {\n input[i] = i as Field;\n }\n let hash = hash_calldata_array(input);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let calldata_hash_from_ts = 0x14a1539bdb1d26e03097cf4d40c87e02ca03f0bb50a3e617ace5a7bfd3943944;\n\n // Used in cpp vm2 tests:\n assert_eq(hash, calldata_hash_from_ts);\n}\n\n#[test]\nunconstrained fn public_bytecode_commitment() {\n let mut input = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS];\n let len = 99;\n for i in 1..len + 1 {\n input[i] = i as Field;\n }\n input[0] = (len as Field) * 31;\n let hash = compute_public_bytecode_commitment(input);\n // Used in cpp vm2 tests:\n assert_eq(hash, 0x09348974e76c3602893d7a4b4bb52c2ec746f1ade5004ac471d0fbb4587a81a6);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/hash.nr","function_locations":[{"start":519,"name":"compute_secret_hash"},{"start":800,"name":"compute_l1_to_l2_message_hash"},{"start":1858,"name":"compute_l1_to_l2_message_nullifier"},{"start":2110,"name":"hash_args"},{"start":2362,"name":"hash_calldata_array"},{"start":2994,"name":"compute_public_bytecode_commitment"},{"start":4153,"name":"secret_hash_matches_typescript"},{"start":4512,"name":"var_args_hash_matches_typescript"},{"start":4922,"name":"compute_calldata_hash"},{"start":5385,"name":"public_bytecode_commitment"}]},"92":{"source":"use crate::protocol::{\n address::aztec_address::AztecAddress,\n constants::{DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, DOM_SEP__ECDH_FIELD_MASK, DOM_SEP__ECDH_SUBKEY},\n hash::poseidon2_hash_with_separator,\n point::Point,\n scalar::Scalar,\n traits::{FromField, ToField},\n};\nuse std::{embedded_curve_ops::multi_scalar_mul, ops::Neg};\n\n/// Computes a standard ECDH shared secret: secret * public_key = shared_secret.\n///\n/// The input secret is known only to one party. The output shared secret can be derived given knowledge of\n/// `public_key`'s key-pair and the public ephemeral secret, using this same function (with reversed inputs).\n///\n/// E.g.: Epk = esk * G // ephemeral key-pair\n/// Pk = sk * G // recipient key-pair\n/// Shared secret S = esk * Pk = sk * Epk\n///\n/// See also: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman\npub fn derive_ecdh_shared_secret(secret: Scalar, public_key: Point) -> Point {\n // TODO(F-553): Drop the `.to_embedded()` / `.into()` round-trip once the custom `Point` wrapper is removed and we\n // use `EmbeddedCurvePoint` directly.\n multi_scalar_mul([public_key.to_embedded()], [secret]).into()\n}\n\n/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.\n///\n/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`\npub(crate) fn compute_app_siloed_shared_secret(shared_secret: Point, contract_address: AztecAddress) -> Field {\n poseidon2_hash_with_separator(\n [shared_secret.x, shared_secret.y, contract_address.to_field()],\n DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET,\n )\n}\n\n/// Derives an indexed subkey from an app-siloed shared secret, used for AES key/IV derivation.\n///\n/// `s_i = h(DOM_SEP__ECDH_SUBKEY + i, s_app)`\npub(crate) fn derive_shared_secret_subkey(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_SUBKEY + index)\n}\n\n/// Derives an indexed field mask from an app-siloed shared secret, used for masking ciphertext fields.\n///\n/// `m_i = h(DOM_SEP__ECDH_FIELD_MASK + i, s_app)`\npub(crate) fn derive_shared_secret_field_mask(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_FIELD_MASK + index)\n}\n\n#[test]\nunconstrained fn test_consistency_with_typescript() {\n let secret = Scalar {\n lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,\n hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,\n };\n let point = Point {\n x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,\n y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,\n is_infinite: false,\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret, point);\n\n // This is just pasted from a test run. The original typescript code from which this could be generated seems to\n // have been deleted by someone, and soon the typescript code for encryption and decryption won't be needed, so\n // this will have to do.\n let hard_coded_shared_secret = Point {\n x: 0x15d55a5b3b2caa6a6207f313f05c5113deba5da9927d6421bcaa164822b911bc,\n y: 0x0974c3d0825031ae933243d653ebb1a0b08b90ee7f228f94c5c74739ea3c871e,\n is_infinite: false,\n };\n assert_eq(shared_secret, hard_coded_shared_secret);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_from_address_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let mut pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let mut pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let address_b = AztecAddress::from_field(pk_b.x);\n\n // We were lazy in deriving the secret keys, and didn't check the resulting y-coordinates of the pk_a or pk_b to be\n // less than half the field modulus. If needed, we negate the pk's so that they yield valid address points. (We\n // could also have negated the secrets, but there's no negate method for EmbeddedCurvesScalar).\n pk_a = if (AztecAddress::from_field(pk_a.x).to_address_point().unwrap().inner == pk_a) {\n pk_a\n } else {\n pk_a.neg()\n };\n pk_b = if (address_b.to_address_point().unwrap().inner == pk_b) {\n pk_b\n } else {\n pk_b.neg()\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, address_b.to_address_point().unwrap().inner);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_app_siloed_shared_secret_differs_per_contract() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(Scalar { lo: 0x3456, hi: 0x4567 }).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n\n let contract_a = AztecAddress::from_field(0xAAAA);\n let contract_b = AztecAddress::from_field(0xBBBB);\n\n let s_app_a = compute_app_siloed_shared_secret(shared_secret, contract_a);\n let s_app_b = compute_app_siloed_shared_secret(shared_secret, contract_b);\n\n assert(s_app_a != s_app_b, \"app-siloed secrets must differ for different contracts\");\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/keys/ecdh_shared_secret.nr","function_locations":[{"start":954,"name":"derive_ecdh_shared_secret"},{"start":1485,"name":"compute_app_siloed_shared_secret"},{"start":1876,"name":"derive_shared_secret_subkey"},{"start":2194,"name":"derive_shared_secret_field_mask"},{"start":2336,"name":"test_consistency_with_typescript"},{"start":3450,"name":"test_shared_secret_computation_in_both_directions"},{"start":4017,"name":"test_shared_secret_computation_from_address_in_both_directions"},{"start":5278,"name":"test_app_siloed_shared_secret_differs_per_contract"}]},"97":{"source":"// Not all log levels are currently used, but we provide the full set so that new call sites can use any level. Because\n// of that we tag all with `#[allow(dead_code)]` to prevent warnings.\n//\n// All wrappers resolve function paths at comptime via `resolve_fn` so that the emitted `Quoted` code works both inside\n// aztec-nr (where `crate::` = aztec) and inside macro-generated contract code (where `crate::` = the contract).\n\nuse std::meta::ctstring::AsCtString;\n\ncomptime fn log_prefix(msg: str) -> CtString {\n \"[aztec-nr] \".as_ctstring().append_str(msg)\n}\n\n// --- No-args variants (direct call) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log });\n quote { $f($msg) }\n}\n\n// --- Format variants (return lambda for runtime args) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n// See module-level comment for why this is needed.\ncomptime fn resolve_fn(path: Quoted) -> TypedExpr {\n path.as_expr().unwrap().resolve(Option::none())\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/logging.nr","function_locations":[{"start":525,"name":"log_prefix"},{"start":717,"name":"aztecnr_fatal_log"},{"start":943,"name":"aztecnr_error_log"},{"start":1168,"name":"aztecnr_warn_log"},{"start":1392,"name":"aztecnr_info_log"},{"start":1619,"name":"aztecnr_verbose_log"},{"start":1847,"name":"aztecnr_debug_log"},{"start":2073,"name":"aztecnr_trace_log"},{"start":2367,"name":"aztecnr_fatal_log_format"},{"start":2622,"name":"aztecnr_error_log_format"},{"start":2876,"name":"aztecnr_warn_log_format"},{"start":3129,"name":"aztecnr_info_log_format"},{"start":3385,"name":"aztecnr_verbose_log_format"},{"start":3642,"name":"aztecnr_debug_log_format"},{"start":3897,"name":"aztecnr_trace_log_format"},{"start":4151,"name":"resolve_fn"}]},"99":{"source":"use crate::logging;\nuse crate::macros::{notes::NOTES, utils::get_trait_impl_method};\n\n/// Generates two contract library methods called `_compute_note_hash` and `_compute_note_nullifier`, plus a\n/// (deprecated) wrapper called `_compute_note_hash_and_nullifier`, which are used for note discovery (i.e. these are\n/// of the `aztec::messages::discovery::ComputeNoteHash` and `aztec::messages::discovery::ComputeNoteNullifier` types).\npub(crate) comptime fn generate_contract_library_methods_compute_note_hash_and_nullifier() -> Quoted {\n let compute_note_hash = generate_contract_library_method_compute_note_hash();\n let compute_note_nullifier = generate_contract_library_method_compute_note_nullifier();\n\n quote {\n $compute_note_hash\n $compute_note_nullifier\n\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n #[allow(dead_code)]\n unconstrained fn _compute_note_hash_and_nullifier(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n note_nonce: Field,\n ) -> Option {\n _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash| {\n\n let siloed_note_hash = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash);\n let unique_note_hash = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash);\n \n let inner_nullifier = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness);\n\n aztec::messages::discovery::NoteHashAndNullifier {\n note_hash,\n inner_nullifier,\n }\n })\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_hash() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the note hash (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_note_hash = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_note_hash },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n Option::some($compute_note_hash(note, owner, storage_slot, randomness))\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed).\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_nullifier() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the inner nullifier (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_nullifier_unconstrained = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_nullifier_unconstrained },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n // The message discovery process finds settled notes, that is, notes that were created in\n // prior transactions and are therefore already part of the note hash tree. The note hash\n // for nullification is hence the unique note hash.\n $compute_nullifier_unconstrained(note, owner, unique_note_hash)\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data.\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec/compute_note_hash_and_nullifier.nr","function_locations":[{"start":534,"name":"generate_contract_library_methods_compute_note_hash_and_nullifier"},{"start":2449,"name":"generate_contract_library_method_compute_note_hash"},{"start":7674,"name":"generate_contract_library_method_compute_note_nullifier"}]},"100":{"source":"mod compute_note_hash_and_nullifier;\n\nuse crate::{\n macros::{\n calls_generation::{\n external_functions::{generate_external_function_calls, generate_external_function_self_calls_structs},\n internal_functions::generate_call_internal_struct,\n },\n dispatch::generate_public_dispatch,\n emit_public_init_nullifier::generate_emit_public_init_nullifier,\n internals_functions_generation::{create_fn_abi_exports, process_functions},\n storage::STORAGE_LAYOUT_NAME,\n utils::{is_fn_contract_library_method, is_fn_external, is_fn_internal, is_fn_test, module_has_storage},\n },\n messages::discovery::CustomMessageHandler,\n};\n\nuse compute_note_hash_and_nullifier::generate_contract_library_methods_compute_note_hash_and_nullifier;\n\n/// Configuration for the [`aztec`] macro.\n///\n/// This type lets users override different parts of the default aztec-nr contract behavior, such\n/// as message handling. These are advanced features that require careful understanding of\n/// the behavior of these systems.\n///\n/// ## Examples\n///\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyContract { ... }\n/// ```\npub struct AztecConfig {\n custom_message_handler: Option>,\n}\n\nimpl AztecConfig {\n /// Creates a new `AztecConfig` with default values.\n ///\n /// Calling `new` is equivalent to invoking the [`aztec`] macro with no parameters. The different methods\n /// (e.g. [`AztecConfig::custom_message_handler`]) can then be used to change the default behavior.\n pub comptime fn new() -> Self {\n Self { custom_message_handler: Option::none() }\n }\n\n /// Sets a handler for custom messages.\n ///\n /// This enables contracts to process non-standard messages (i.e. any with a message type that is not in\n /// [`crate::messages::msg_type`]).\n ///\n /// `handler` must be a function that conforms to the\n /// [`crate::messages::discovery::CustomMessageHandler`] type signature.\n pub comptime fn custom_message_handler(_self: Self, handler: CustomMessageHandler<()>) -> Self {\n Self { custom_message_handler: Option::some(handler) }\n }\n}\n\n/// Enables aztec-nr features on a `contract`.\n///\n/// All aztec-nr contracts should have this macro invoked on them, as it is the one that processes all contract\n/// functions, notes, storage, generates interfaces for external calls, and creates the message processing\n/// boilerplate.\n///\n/// ## Examples\n///\n/// Most contracts can simply invoke the macro with no parameters, resulting in default aztec-nr behavior:\n/// ```noir\n/// #[aztec]\n/// contract MyContract { ... }\n/// ```\n///\n/// Advanced contracts can use [`AztecConfig`] to customize parts of its behavior, such as message\n/// processing.\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyAdvancedContract { ... }\n/// ```\n#[varargs]\npub comptime fn aztec(m: Module, args: [AztecConfig]) -> Quoted {\n let num_args = args.len();\n let config = if num_args == 0 {\n AztecConfig::new()\n } else if num_args == 1 {\n args[0]\n } else {\n panic(f\"#[aztec] expects 0 or 1 arguments, got {num_args}\")\n };\n\n // Functions that don't have #[external(...)], #[contract_library_method], or #[test] are not allowed in contracts.\n check_each_fn_macroified(m);\n\n // We generate new functions prefixed with `__aztec_nr_internals__` and we replace the original functions' bodies\n // with `static_assert(false, ...)` to prevent them from being called directly from within the contract.\n let functions = process_functions(m);\n\n // We generate structs and their implementations necessary for convenient functions calls.\n let interface = generate_contract_interface(m);\n let self_call_structs = generate_external_function_self_calls_structs(m);\n let call_internal_struct = generate_call_internal_struct(m);\n\n // We generate ABI exports for all the external functions in the contract.\n let fn_abi_exports = create_fn_abi_exports(m);\n\n // We generate `_compute_note_hash`, `_compute_note_nullifier` (and the deprecated\n // `_compute_note_hash_and_nullifier` wrapper) and `sync_state` functions only if they are not already implemented.\n // If they are implemented we just insert empty quotes.\n let contract_library_method_compute_note_hash_and_nullifier = if !m.functions().any(|f| {\n // Note that we don't test for `_compute_note_hash` or `_compute_note_nullifier` in order to make this simpler\n // - users must either implement all three or none.\n // Down the line we'll remove this check and use `AztecConfig`.\n f.name() == quote { _compute_note_hash_and_nullifier }\n }) {\n generate_contract_library_methods_compute_note_hash_and_nullifier()\n } else {\n quote {}\n };\n let process_custom_message_option = if config.custom_message_handler.is_some() {\n let handler = config.custom_message_handler.unwrap();\n quote { Option::some($handler) }\n } else {\n quote { Option::>::none() }\n };\n\n let offchain_inbox_sync_option = quote {\n Option::some(aztec::messages::processing::offchain::sync_inbox)\n };\n\n let sync_state_fn_and_abi_export = if !m.functions().any(|f| f.name() == quote { sync_state }) {\n generate_sync_state(process_custom_message_option, offchain_inbox_sync_option)\n } else {\n quote {}\n };\n\n if m.functions().any(|f| f.name() == quote { offchain_receive }) {\n panic(\n \"User-defined 'offchain_receive' is not allowed. The function is auto-injected by the #[aztec] macro. See https://docs.aztec.network/errors/7\",\n );\n }\n let offchain_receive_fn_and_abi_export = generate_offchain_receive();\n\n let (has_public_init_nullifier_fn, emit_public_init_nullifier_fn_body) = generate_emit_public_init_nullifier(m);\n let public_dispatch = generate_public_dispatch(m, has_public_init_nullifier_fn);\n\n quote {\n $interface\n $self_call_structs\n $call_internal_struct\n $functions\n $fn_abi_exports\n $contract_library_method_compute_note_hash_and_nullifier\n $public_dispatch\n $sync_state_fn_and_abi_export\n $emit_public_init_nullifier_fn_body\n $offchain_receive_fn_and_abi_export\n }\n}\n\ncomptime fn generate_contract_interface(m: Module) -> Quoted {\n let calls = generate_external_function_calls(m);\n\n let module_name = m.name();\n\n let has_storage_layout = module_has_storage(m) & STORAGE_LAYOUT_NAME.get(m).is_some();\n let storage_layout_getter = if has_storage_layout {\n let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap();\n quote {\n pub fn storage_layout() -> StorageLayoutFields {\n $storage_layout_name.fields\n }\n }\n } else {\n quote {}\n };\n\n let library_storage_layout_getter = if has_storage_layout {\n quote {\n #[contract_library_method]\n $storage_layout_getter\n }\n } else {\n quote {}\n };\n\n quote {\n pub struct $module_name {\n pub target_contract: aztec::protocol::address::AztecAddress\n }\n\n impl $module_name {\n $calls\n\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> Self {\n Self { target_contract: addr }\n }\n\n pub fn interface() -> Self {\n Self { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $storage_layout_getter\n }\n\n #[contract_library_method]\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> $module_name {\n $module_name { target_contract: addr }\n }\n\n #[contract_library_method]\n pub fn interface() -> $module_name {\n $module_name { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $library_storage_layout_getter\n\n }\n}\n\n/// Generates the `sync_state` utility function that performs message discovery.\ncomptime fn generate_sync_state(process_custom_message_option: Quoted, offchain_inbox_sync_option: Quoted) -> Quoted {\n quote {\n pub struct sync_state_parameters {\n pub scope: aztec::protocol::address::AztecAddress,\n }\n\n #[abi(functions)]\n pub struct sync_state_abi {\n parameters: sync_state_parameters,\n }\n\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn sync_state(scope: aztec::protocol::address::AztecAddress) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::discovery::do_sync_state(\n address,\n _compute_note_hash,\n _compute_note_nullifier,\n $process_custom_message_option,\n $offchain_inbox_sync_option,\n scope,\n );\n }\n }\n}\n\n/// Generates an `offchain_receive` utility function that lets callers add messages to the offchain message inbox.\n///\n/// For more details, see `aztec::messages::processing::offchain::receive`.\ncomptime fn generate_offchain_receive() -> Quoted {\n quote {\n pub struct offchain_receive_parameters {\n pub messages: BoundedVec<\n aztec::messages::processing::offchain::OffchainMessage,\n aztec::messages::processing::offchain::MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL,\n >,\n }\n\n #[abi(functions)]\n pub struct offchain_receive_abi {\n parameters: offchain_receive_parameters,\n }\n\n /// Receives offchain messages into this contract's offchain inbox for subsequent processing.\n ///\n /// Each message is routed to the inbox scoped to its `recipient` field.\n ///\n /// For more details, see `aztec::messages::processing::offchain::receive`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn offchain_receive(\n messages: BoundedVec<\n aztec::messages::processing::offchain::OffchainMessage,\n aztec::messages::processing::offchain::MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL,\n >,\n ) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::processing::offchain::receive(address, messages);\n }\n }\n}\n\n/// Checks that all functions in the module have a context macro applied.\n///\n/// Non-macroified functions are not allowed in contracts. They must all be one of\n/// [`crate::macros::functions::external`], [`crate::macros::functions::internal`] or `test`.\ncomptime fn check_each_fn_macroified(m: Module) {\n for f in m.functions() {\n let name = f.name();\n if !is_fn_external(f) & !is_fn_contract_library_method(f) & !is_fn_internal(f) & !is_fn_test(f) {\n // We don't suggest that #[contract_library_method] is allowed because we don't want to introduce another\n // concept\n panic(\n f\"Function {name} must be marked as either #[external(...)], #[internal(...)], or #[test]\",\n );\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec.nr","function_locations":[{"start":1648,"name":"AztecConfig::new"},{"start":2156,"name":"AztecConfig::custom_message_handler"},{"start":3050,"name":"aztec"},{"start":6527,"name":"generate_contract_interface"},{"start":8389,"name":"generate_sync_state"},{"start":9443,"name":"generate_offchain_receive"},{"start":11087,"name":"check_each_fn_macroified"}]},"105":{"source":"use crate::macros::internals_functions_generation::external_functions_registry::get_public_functions;\nuse crate::protocol::meta::utils::get_params_len_quote;\nuse crate::utils::cmap::CHashMap;\nuse super::functions::initialization_utils::EMIT_PUBLIC_INIT_NULLIFIER_FN_NAME;\nuse super::utils::compute_fn_selector;\nuse std::panic;\n\n/// Generates a `public_dispatch` function for an Aztec contract module `m`.\n///\n/// The generated function dispatches public calls based on selector to the appropriate contract function. If\n/// `generate_emit_public_init_nullifier` is true, it also handles dispatch to the macro-generated\n/// `__emit_public_init_nullifier` function.\npub comptime fn generate_public_dispatch(m: Module, generate_emit_public_init_nullifier: bool) -> Quoted {\n let functions = get_public_functions(m);\n\n let unit = get_type::<()>();\n\n let seen_selectors = &mut CHashMap::::new();\n\n let mut ifs = functions.map(|function: FunctionDefinition| {\n let parameters = function.parameters();\n let return_type = function.return_type();\n\n let fn_name = function.name();\n let selector: Field = compute_fn_selector(fn_name, parameters);\n\n // Since function selectors are computed as the first 4 bytes of the hash of the function signature, it's\n // possible to have collisions. With the following check, we ensure it doesn't happen within the same contract.\n let existing_fn = seen_selectors.get(selector);\n if existing_fn.is_some() {\n let existing_fn = existing_fn.unwrap();\n panic(\n f\"Public function selector collision detected between functions '{fn_name}' and '{existing_fn}'\",\n );\n }\n seen_selectors.insert(selector, fn_name);\n\n let params_len_quote = get_params_len_quote(parameters);\n\n let initial_read = if parameters.len() == 0 {\n quote {}\n } else {\n // The initial calldata_copy offset is 1 to skip the Field selector The expected calldata is the\n // serialization of\n // - FunctionSelector: the selector of the function intended to dispatch\n // - Parameters: the parameters of the function intended to dispatch That is, exactly what is expected for\n // a call to the target function, but with a selector added at the beginning.\n quote {\n let input_calldata: [Field; $params_len_quote] = aztec::oracle::avm::calldata_copy(1, $params_len_quote);\n let mut reader = aztec::protocol::utils::reader::Reader::new(input_calldata);\n }\n };\n\n let parameter_index: &mut u32 = &mut 0;\n let reads = parameters.map(|param: (Quoted, Type)| {\n let parameter_index_value = *parameter_index;\n let param_name = f\"arg{parameter_index_value}\".quoted_contents();\n let param_type = param.1;\n let read = quote {\n let $param_name: $param_type = aztec::protocol::traits::Deserialize::stream_deserialize(&mut reader);\n };\n *parameter_index += 1;\n quote { $read }\n });\n let read = reads.join(quote { });\n\n let mut args = @[];\n for parameter_index in 0..parameters.len() {\n let param_name = f\"arg{parameter_index}\".quoted_contents();\n args = args.push_back(quote { $param_name });\n }\n\n // We call a function whose name is prefixed with `__aztec_nr_internals__`. This is necessary because the\n // original function is intentionally made uncallable, preventing direct invocation within the contract.\n // Instead, a new function with the same name, but prefixed by `__aztec_nr_internals__`, has been generated to\n // be called here. For more details see the `process_functions` function.\n let name = f\"__aztec_nr_internals__{fn_name}\".quoted_contents();\n let args = args.join(quote { , });\n let call = quote { $name($args) };\n\n let return_code = if return_type == unit {\n quote {\n $call;\n // Force early return.\n aztec::oracle::avm::avm_return([]);\n }\n } else {\n quote {\n let return_value = aztec::protocol::traits::Serialize::serialize($call);\n aztec::oracle::avm::avm_return(return_value.as_vector());\n }\n };\n\n let if_ = quote {\n if selector == $selector {\n $initial_read\n $read\n $return_code\n }\n };\n if_\n });\n\n // If we injected the auto-generated public function to emit the public initialization nullifier, then\n // we'll also need to handle its dispatch.\n if generate_emit_public_init_nullifier {\n let name = EMIT_PUBLIC_INIT_NULLIFIER_FN_NAME;\n let init_nullifier_selector: Field = compute_fn_selector(name, @[]);\n\n ifs = ifs.push_back(\n quote {\n if selector == $init_nullifier_selector {\n $name();\n aztec::oracle::avm::avm_return([]);\n }\n },\n );\n }\n\n if ifs.len() == 0 {\n // No dispatch function if there are no public functions\n quote {}\n } else {\n let ifs = ifs.push_back(quote { panic(f\"Unknown selector {selector}\") });\n let dispatch = ifs.join(quote { });\n\n let body = quote {\n // We mark this as public because our whole system depends on public functions having this attribute.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]\n pub unconstrained fn public_dispatch(selector: Field) {\n $dispatch\n }\n };\n\n body\n }\n}\n\ncomptime fn get_type() -> Type {\n let t: T = std::mem::zeroed();\n std::meta::type_of(t)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/dispatch.nr","function_locations":[{"start":768,"name":"generate_public_dispatch"},{"start":5832,"name":"get_type"}]},"113":{"source":"use crate::macros::{\n functions::auth_registry::AUTHORIZE_ONCE_REGISTRY,\n utils::{is_fn_initializer, is_fn_only_self, is_fn_view},\n};\n\n/// Gathers all attributes relevant to the function's ABI and returns a quote that can be applied to the newly\n/// generated function. We apply the abi marker attributes instead of the original ones (e.g. abi_view instead of view)\n/// to avoid the relevant attribute's functionality from getting triggered.\npub(crate) comptime fn get_abi_relevant_attributes(f: FunctionDefinition) -> Quoted {\n let mut attributes = quote {};\n\n if is_fn_view(f) {\n attributes = quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_view] };\n }\n\n if is_fn_only_self(f) {\n attributes =\n quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_only_self] };\n }\n\n if is_fn_initializer(f) {\n attributes =\n quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_initializer] };\n }\n\n attributes\n}\n\n/// Injects an authwit verification check of the form:\n/// ```\n/// if (!from.eq(context.maybe_msg_sender().unwrap())) {\n/// assert_current_call_valid_authwit::(&mut context, from);\n/// } else {\n/// assert(authwit_nonce, \"Invalid authwit nonce. When 'from' and 'msg_sender' are the\n/// same, authwit_nonce must be zero\");\n/// }\n/// ```\n/// where `from` and `authwit_nonce` are the names of the parameters that are expected to be present in the function\n/// definition. This check is injected by the `#[authorize_once(\"from_arg_name\", \"nonce_arg_name\")]`, which allows the\n/// user to define which parameters to use.\n///\n/// # Arguments\n/// * `f` - The function definition to inject the authwit verification check into. The function must have parameters\n/// matching the names specified in the `#[authorize_once]` attribute.\n/// * `is_private` - Whether the function is a private function (`true`) or a public function (`false`). This\n/// determines which authwit verification method to use: `assert_current_call_valid_authwit` for private functions or\n/// `assert_current_call_valid_authwit_public` for public functions.\npub(crate) comptime fn create_authorize_once_check(f: FunctionDefinition, is_private: bool) -> Quoted {\n let maybe_authorize_once_args = AUTHORIZE_ONCE_REGISTRY.get(f);\n let authorize_once_args = if maybe_authorize_once_args.is_some() {\n maybe_authorize_once_args.unwrap()\n } else {\n // We need to for authorize_once to have already executed so that we can retrieve its params - this depends on\n // the order in which the attributes are applied.\n panic(\n f\"Functions marked with #[authorize_once] must have the #[external(\\\"private\\\")] or #[external(\\\"public\\\")] attribute placed last\",\n )\n };\n\n let (from_arg_name, nonce_arg_name) = authorize_once_args;\n let name: Quoted = f.name();\n\n let from_arg_candidates = f.parameters().filter(|(name, _)| name == f\"{from_arg_name}\".quoted_contents());\n let (from_arg_name_quoted, from_arg_type) = if from_arg_candidates.len() == 1 {\n from_arg_candidates[0]\n } else {\n panic(\n f\"Function {name} does not have a {from_arg_name} parameter. Please specify which one to use in #[authorize_once(\\\"...\\\", \\\"authwit_nonce\\\")]\",\n )\n };\n if from_arg_type != quote { crate::protocol::address::aztec_address::AztecAddress }.as_type() {\n panic(\n f\"Argument {from_arg_name_quoted} in function {name} must be of type AztecAddress, but is of type {from_arg_type}\",\n )\n }\n\n let nonce_arg_candidates = f.parameters().filter(|(name, _)| name == f\"{nonce_arg_name}\".quoted_contents());\n let (nonce_arg_name_quoted, nonce_arg_type) = if nonce_arg_candidates.len() == 1 {\n nonce_arg_candidates[0]\n } else {\n panic(\n f\"Function {name} does not have a {nonce_arg_name}. Please specify which one to use in #[authorize_once(\\\"from\\\", \\\"...\\\")]\",\n )\n };\n if nonce_arg_type != quote { Field }.as_type() {\n panic(\n f\"Argument {nonce_arg_name_quoted} in function {name} must be of type Field, but is of type {nonce_arg_type}\",\n );\n }\n\n let nonce_check_quote = f\"{nonce_arg_name_quoted} == 0\".quoted_contents();\n\n let fn_call = if is_private {\n let params = f.parameters();\n let serialized_len_quote = if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as aztec::protocol::traits::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n };\n quote { aztec::authwit::auth::assert_current_call_valid_authwit::<($serialized_len_quote)> }\n } else {\n quote { aztec::authwit::auth::assert_current_call_valid_authwit_public }\n };\n let invalid_nonce_message = f\"Invalid authwit nonce. When '{from_arg_name}' and 'msg_sender' are the same, '{nonce_arg_name}' must be zero\"\n .as_quoted_str();\n quote { \n if (!$from_arg_name_quoted.eq(self.msg_sender())) {\n $fn_call(self.context, $from_arg_name_quoted);\n } else {\n assert($nonce_check_quote, $invalid_nonce_message);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr","function_locations":[{"start":532,"name":"get_abi_relevant_attributes"},{"start":2334,"name":"create_authorize_once_check"}]},"116":{"source":"use crate::macros::{\n internals_functions_generation::external::helpers::{create_authorize_once_check, get_abi_relevant_attributes},\n utils::{\n fn_has_authorize_once, fn_has_noinitcheck, is_fn_initializer, is_fn_only_self, is_fn_view,\n module_has_initializer, module_has_storage,\n },\n};\n\npub(crate) comptime fn generate_public_external(f: FunctionDefinition) -> Quoted {\n let module_has_initializer = module_has_initializer(f.module());\n let module_has_storage = module_has_storage(f.module());\n\n // Public functions undergo a lot of transformations from their Aztec.nr form.\n let original_params = f.parameters();\n\n let args_len_quote = if original_params.len() == 0 {\n // If the function has no parameters, we set the args_len to 0.\n quote { 0 }\n } else {\n // The following will give us ::N + ::N + ...\n original_params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::protocol::traits::Serialize>::N\n }\n })\n .join(quote {+})\n };\n\n let storage_init = if module_has_storage {\n quote {\n let storage = Storage::init(context);\n }\n } else {\n // Contract does not have Storage defined, so we set storage to the unit type `()`. ContractSelfPublic requires\n // a storage struct in its constructor. Using an Option type would lead to worse developer experience and\n // higher constraint counts so we use the unit type `()` instead.\n quote {\n let storage = ();\n }\n };\n\n // Unlike in the private case, in public the `context` does not need to receive the hash of the original params.\n let contract_self_creation = quote {\n #[allow(unused_variables)]\n let mut self = {\n let context = aztec::context::PublicContext::new(|| {\n // We start from 1 because we skip the selector for the dispatch function.\n let serialized_args : [Field; $args_len_quote] = aztec::oracle::avm::calldata_copy(1, $args_len_quote);\n aztec::hash::hash_args(serialized_args)\n });\n $storage_init\n let self_address = context.this_address();\n let call_self: CallSelf = CallSelf { address: self_address, context };\n let call_self_static: CallSelfStatic = CallSelfStatic { address: self_address, context };\n let internal: CallInternal = CallInternal { context };\n aztec::contract_self::ContractSelfPublic::new(context, storage, call_self, call_self_static, internal)\n };\n };\n\n let original_function_name = f.name();\n\n // Modifications introduced by the different marker attributes.\n let internal_check = if is_fn_only_self(f) {\n let assertion_message = f\"Function {original_function_name} can only be called by the same contract\";\n quote { assert(self.msg_sender() == self.address, $assertion_message); }\n } else {\n quote {}\n };\n\n let view_check = if is_fn_view(f) {\n let assertion_message = f\"Function {original_function_name} can only be called statically\".as_quoted_str();\n quote { assert(self.context.is_static_call(), $assertion_message); }\n } else {\n quote {}\n };\n\n let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) {\n (\n quote { aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_public(self.context); },\n quote { aztec::macros::functions::initialization_utils::mark_as_initialized_from_public_initializer(self.context); },\n )\n } else {\n (quote {}, quote {})\n };\n\n // Initialization checks are not included in contracts that don't have initializers.\n let init_check = if module_has_initializer & !fn_has_noinitcheck(f) & !is_fn_initializer(f) {\n quote { aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); }\n } else {\n quote {}\n };\n\n // Inject the authwit check if the function is marked with #[authorize_once].\n let authorize_once_check = if fn_has_authorize_once(f) {\n create_authorize_once_check(f, false)\n } else {\n quote {}\n };\n\n let to_prepend = quote {\n $contract_self_creation\n $assert_initializer\n $init_check\n $internal_check\n $view_check\n $authorize_once_check\n };\n\n // `mark_as_initialized` is placed after the user's function body. If it ran at the beginning, the contract\n // would appear initialized while the initializer is still running, allowing contracts called by the initializer\n // to re-enter into a half-initialized contract.\n let to_append = quote {\n $mark_as_initialized\n };\n\n let fn_name = f\"__aztec_nr_internals__{original_function_name}\".quoted_contents();\n let body = f.body();\n let return_type = f.return_type();\n\n // New function parameters are the same as the original function's ones.\n let params = original_params.map(|(param_name, param_type)| quote { $param_name: $param_type }).join(quote {, });\n\n // Preserve all attributes that are relevant to the function's ABI.\n let abi_relevant_attributes = get_abi_relevant_attributes(f);\n\n // All public functions are automatically made unconstrained, even if they were not marked as such. This is because\n // instead of compiling into a circuit, they will compile to bytecode that will be later transpiled into AVM\n // bytecode.\n quote {\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]\n $abi_relevant_attributes\n unconstrained fn $fn_name($params) -> pub $return_type {\n $to_prepend\n $body\n $to_append\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr","function_locations":[{"start":392,"name":"generate_public_external"}]},"126":{"source":"use crate::logging::{aztecnr_debug_log, aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\npub(crate) mod nonce_discovery;\npub(crate) mod partial_notes;\npub(crate) mod private_events;\npub mod private_notes;\npub mod process_message;\n\nuse crate::{\n messages::{\n discovery::process_message::process_message_ciphertext,\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{\n MessageContext, offchain::OffchainInboxSync, OffchainMessageWithContext,\n pending_tagged_log::PendingTaggedLog, validate_and_store_enqueued_notes_and_events,\n },\n },\n oracle::message_processing,\n utils::array,\n};\n\npub struct NoteHashAndNullifier {\n /// The result of [`crate::note::note_interface::NoteHash::compute_note_hash`].\n pub note_hash: Field,\n /// The result of [`crate::note::note_interface::NoteHash::compute_nullifier_unconstrained`].\n ///\n /// This value is unconstrained, as all of message discovery is unconstrained. It is `None` if the nullifier\n /// cannot be computed (e.g. because the nullifier hiding key is not available).\n pub inner_nullifier: Option,\n}\n\n/// A contract's way of computing note hashes.\n///\n/// Each contract in the network is free to compute their note's hash as they see fit - the hash function itself is not\n/// enshrined or standardized. Some aztec-nr functions however do need to know the details of this computation (e.g.\n/// when finding new notes), which is what this type represents.\n///\n/// This function takes a note's packed content, storage slot, note type ID, address of the emitting contract and\n/// randomness, and attempts to compute its inner note hash (not siloed by address nor uniqued by nonce).\n///\n/// ## Transient Notes\n///\n/// This function is meant to always be used on **settled** notes, i.e. those that have been inserted into the trees\n/// and for which the nonce is known. It is never invoked in the context of a transient note, as those are not involved\n/// in message processing.\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract by inspecting all note types in use and the storage layout. This injected function is a\n/// `#[contract_library_method]` called `_compute_note_hash`, and it looks something like this:\n///\n/// ```noir\n/// |packed_note, owner, storage_slot, note_type_id, _contract_address, randomness| {\n/// if note_type_id == MyNoteType::get_id() {\n/// if packed_note.len() != MY_NOTE_TYPE_SERIALIZATION_LENGTH {\n/// Option::none()\n/// } else {\n/// let note = MyNoteType::unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n/// Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n/// }\n/// } else if note_type_id == MyOtherNoteType::get_id() {\n/// ... // Similar to above but calling MyOtherNoteType::unpack\n/// } else {\n/// Option::none() // Unknown note type ID\n/// };\n/// }\n/// ```\npub type ComputeNoteHash = unconstrained fn(/* packed_note */BoundedVec, /*\n owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress, /*\nrandomness */ Field) -> Option;\n\n/// A contract's way of computing note nullifiers.\n///\n/// Like [`ComputeNoteHash`], each contract is free to derive nullifiers as they see fit. This function takes the\n/// unique note hash (used as the note hash for nullification for settled notes), plus the note's packed content and\n/// metadata, and attempts to compute the inner nullifier (not siloed by address).\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract called `_compute_note_nullifier`. It dispatches on `note_type_id` similarly to\n/// [`ComputeNoteHash`], then calls the note's\n/// [`compute_nullifier_unconstrained`](crate::note::note_interface::NoteHash::compute_nullifier_unconstrained) method.\npub type ComputeNoteNullifier = unconstrained fn(/* unique_note_hash */Field, /* packed_note */ BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/* randomness */ Field) -> Option;\n\n/// Deprecated: use [`ComputeNoteHash`] and [`ComputeNoteNullifier`] instead.\npub type ComputeNoteHashAndNullifier = unconstrained fn[Env](/* packed_note */BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/*randomness */ Field, /* note nonce */ Field) -> Option;\n\n/// A handler for custom messages.\n///\n/// Contracts that emit custom messages (i.e. any with a message type that is not in [`crate::messages::msg_type`])\n/// need to use [`crate::macros::AztecConfig::custom_message_handler`] with a function of this type in order to\n/// process them. They will otherwise be **silently ignored**.\npub type CustomMessageHandler = unconstrained fn[Env](\n/* contract_address */AztecAddress,\n/* msg_type_id */ u64,\n/* msg_metadata */ u64,\n/* msg_content */ BoundedVec,\n/* message_context */ MessageContext,\n/* scope */ AztecAddress);\n\n/// Synchronizes the contract's private state with the network.\n///\n/// As blocks are mined, it is possible for a contract's private state to change (e.g. with new notes being created),\n/// but because these changes are private they will be invisible to most actors. This is the function that processes\n/// new transactions in order to discover new notes, events, and other kinds of private state changes.\n///\n/// The private state will be synchronized up to the block that will be used for private transactions (i.e. the anchor\n/// block. This will typically be close to the tip of the chain.\npub unconstrained fn do_sync_state(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n offchain_inbox_sync: Option>,\n scope: AztecAddress,\n) {\n aztecnr_debug_log!(\"Performing state synchronization\");\n\n // First we process all private logs, which can contain different kinds of messages e.g. private notes, partial\n // notes, private events, etc.\n let logs = message_processing::get_pending_tagged_logs(scope);\n logs.for_each(|_i, pending_tagged_log: PendingTaggedLog| {\n if pending_tagged_log.log.len() == 0 {\n aztecnr_warn_log_format!(\"Skipping empty log from tx {0}\")([pending_tagged_log.context.tx_hash]);\n } else {\n aztecnr_debug_log_format!(\"Processing log with tag {0}\")([pending_tagged_log.log.get(0)]);\n\n // We remove the tag from the pending tagged log and process the message ciphertext contained in it.\n let message_ciphertext = array::subbvec(pending_tagged_log.log, 1);\n\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_ciphertext,\n pending_tagged_log.context,\n scope,\n );\n }\n });\n\n if offchain_inbox_sync.is_some() {\n let msgs = offchain_inbox_sync.unwrap()(contract_address, scope);\n msgs.for_each(|_i, msg: OffchainMessageWithContext| {\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n msg.message_ciphertext,\n msg.message_context,\n scope,\n );\n });\n }\n\n // Then we process all pending partial notes, regardless of whether they were found in the current or previous\n // executions.\n partial_notes::fetch_and_process_partial_note_completion_logs(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n scope,\n );\n\n // Finally we validate all notes and events that were found as part of the previous processes, resulting in them\n // being added to PXE's database and retrievable via oracles (get_notes) and our TS API (PXE::getPrivateEvents).\n validate_and_store_enqueued_notes_and_events(scope);\n}\n\nmod test {\n use crate::ephemeral::EphemeralArray;\n use crate::messages::{\n discovery::{CustomMessageHandler, do_sync_state},\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{offchain::OffchainInboxSync, pending_tagged_log::PendingTaggedLog},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n\n #[test]\n unconstrained fn do_sync_state_does_not_panic_on_empty_logs() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n\n let contract_address = AztecAddress { inner: 0xdeadbeef };\n\n env.utility_context_at(contract_address, |_| {\n // Mock the oracle call to return a known base slot, then populate an ephemeral\n // array at that slot so do_sync_state processes a non-empty log list.\n let base_slot = 42;\n let mock = std::test::OracleMock::mock(\"aztec_utl_getPendingTaggedLogs_v2\");\n let _ = mock.returns(base_slot);\n\n let logs: EphemeralArray = EphemeralArray::at(base_slot);\n logs.push(PendingTaggedLog { log: BoundedVec::new(), context: std::mem::zeroed() });\n assert_eq(logs.len(), 1);\n\n let no_handler: Option> = Option::none();\n let no_inbox_sync: Option> = Option::none();\n do_sync_state(\n contract_address,\n dummy_compute_note_hash,\n dummy_compute_note_nullifier,\n no_handler,\n no_inbox_sync,\n scope,\n );\n });\n }\n\n unconstrained fn dummy_compute_note_hash(\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n\n unconstrained fn dummy_compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr","function_locations":[{"start":6465,"name":"do_sync_state"},{"start":9175,"name":"test::do_sync_state_does_not_panic_on_empty_logs"},{"start":10673,"name":"test::dummy_compute_note_hash"},{"start":11034,"name":"test::dummy_compute_note_nullifier"}]},"127":{"source":"use crate::messages::{discovery::{ComputeNoteHash, ComputeNoteNullifier}, logs::note::MAX_NOTE_PACKED_LEN};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{\n address::AztecAddress,\n constants::MAX_NOTE_HASHES_PER_TX,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::ToField,\n};\n\n/// A struct with the discovered information of a complete note, required for delivery to PXE. Note that this is *not*\n/// the complete note information, since it does not include content, storage slot, etc.\npub(crate) struct DiscoveredNoteInfo {\n pub(crate) note_nonce: Field,\n pub(crate) note_hash: Field,\n pub(crate) inner_nullifier: Field,\n}\n\n/// Searches for note nonces that will result in a note that was emitted in a transaction. While rare, it is possible\n/// for multiple notes to have the exact same packed content and storage slot but different nonces, resulting in\n/// different unique note hashes. Because of this this function returns a *vector* of discovered notes, though in most\n/// cases it will contain a single element.\n///\n/// Due to how nonces are computed, this function requires knowledge of the transaction in which the note was created,\n/// more specifically the list of all unique note hashes in it plus the value of its first nullifier.\npub(crate) unconstrained fn attempt_note_nonce_discovery(\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) -> BoundedVec {\n let discovered_notes = &mut BoundedVec::new();\n\n aztecnr_debug_log_format!(\n \"Attempting nonce discovery on {0} potential notes on contract {1} for storage slot {2}\",\n )(\n [unique_note_hashes_in_tx.len() as Field, contract_address.to_field(), storage_slot],\n );\n\n let maybe_note_hash = compute_note_hash(\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_note_hash.is_none() {\n aztecnr_warn_log_format!(\n \"Unable to compute note hash for note of id {0} with packed length {1}, skipping nonce discovery\",\n )(\n [note_type_id, packed_note.len() as Field],\n );\n } else {\n let note_hash = maybe_note_hash.unwrap();\n let siloed_note_hash = compute_siloed_note_hash(contract_address, note_hash);\n\n // We need to find nonces (typically just one) that result in the siloed note hash that being uniqued into one\n // of the transaction's effects.\n // The nonce is meant to be derived from the index of the note hash in the transaction effects array. However,\n // due to an issue in the kernels the nonce might actually use any of the possible note hash indices - not\n // necessarily the one that corresponds to the note hash. Hence, we need to try them all.\n for i in 0..MAX_NOTE_HASHES_PER_TX {\n let nonce_for_i = compute_note_hash_nonce(first_nullifier_in_tx, i);\n let unique_note_hash_for_i = compute_unique_note_hash(nonce_for_i, siloed_note_hash);\n\n let matching_notes = bvec_filter(\n unique_note_hashes_in_tx,\n |unique_note_hash_in_tx| unique_note_hash_in_tx == unique_note_hash_for_i,\n );\n if matching_notes.len() > 1 {\n let identical_note_hashes = matching_notes.len();\n // Note that we don't actually check that the note hashes array contains unique values, only that the\n // note we found is unique. We don't expect for this to ever happen (it'd indicate a malicious node or\n // PXE, which are both assumed to be cooperative) so testing for it just in case is unnecessary, but we\n // _do_ need to handle it if we find a duplicate.\n panic(\n f\"Received {identical_note_hashes} identical note hashes for a transaction - these should all be unique\",\n )\n } else if matching_notes.len() == 1 {\n let maybe_inner_nullifier_for_i = compute_note_nullifier(\n unique_note_hash_for_i,\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_inner_nullifier_for_i.is_none() {\n // TODO: down the line we want to be able to store notes for which we don't know their nullifier,\n // e.g. notes that belong to someone that is not us (and for which we therefore don't know their\n // associated app-siloed nullifer hiding secret key).\n // https://linear.app/aztec-labs/issue/F-265/store-external-notes\n aztecnr_warn_log_format!(\n \"Unable to compute nullifier of unique note {0} with note type id {1} and owner {2}, skipping PXE insertion\",\n )(\n [unique_note_hash_for_i, note_type_id, owner.to_field()],\n );\n } else {\n // Note that while we did check that the note hash is the preimage of a unique note hash, we\n // perform no validations on the nullifier - we fundamentally cannot, since only the application\n // knows how to compute nullifiers. We simply trust it to have provided the correct one: if it\n // hasn't, then PXE may fail to realize that a given note has been nullified already, and calls to\n // the application could result in invalid transactions (with duplicate nullifiers). This is not a\n // concern because an application already has more direct means of making a call to it fail the\n // transaction.\n discovered_notes.push(\n DiscoveredNoteInfo {\n note_nonce: nonce_for_i,\n note_hash,\n inner_nullifier: maybe_inner_nullifier_for_i.unwrap(),\n },\n );\n }\n // We don't exit the loop - it is possible (though rare) for the exact same note content to be present\n // multiple times in the same transaction with different nonces. This typically doesn't happen due to\n // notes containing random values in order to hide their contents.\n }\n }\n }\n\n *discovered_notes\n}\n\n// There is no BoundedVec::filter in the stdlib, so we use this until that is implemented.\nunconstrained fn bvec_filter(\n bvec: BoundedVec,\n filter: fn[Env](T) -> bool,\n) -> BoundedVec {\n let filtered = &mut BoundedVec::new();\n\n bvec.for_each(|value| {\n if filter(value) {\n filtered.push(value);\n }\n });\n\n *filtered\n}\n\nmod test {\n use crate::{\n messages::logs::note::MAX_NOTE_PACKED_LEN,\n note::{\n note_interface::{NoteHash, NoteType},\n note_metadata::SettledNoteMetadata,\n utils::compute_note_hash_for_nullification,\n },\n oracle::random::random,\n test::mocks::mock_note::MockNote,\n utils::array,\n };\n\n use crate::protocol::{\n address::AztecAddress,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::{FromField, Packable},\n };\n\n use super::attempt_note_nonce_discovery;\n\n // This implementation could be simpler, but this serves as a nice example of the expected flow in a real\n // implementation, and as a sanity check that the interface is sufficient.\n\n unconstrained fn compute_note_hash(\n packed_note: BoundedVec,\n owner: AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n } else {\n Option::none()\n }\n }\n\n unconstrained fn compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n note.compute_nullifier_unconstrained(owner, unique_note_hash)\n } else {\n Option::none()\n }\n }\n\n global VALUE: Field = 7;\n global FIRST_NULLIFIER_IN_TX: Field = 47;\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress::from_field(13);\n global OWNER: AztecAddress = AztecAddress::from_field(14);\n global STORAGE_SLOT: Field = 99;\n global RANDOMNESS: Field = 99;\n\n #[test]\n unconstrained fn no_note_hashes() {\n let unique_note_hashes_in_tx = BoundedVec::new();\n let packed_note = BoundedVec::new();\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n packed_note,\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_hash_computation_is_ignored() {\n let unique_note_hashes_in_tx = BoundedVec::from_array([random()]);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n |_, _, _, _, _, _| Option::none(),\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::new(),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_nullifier_computation_is_ignored() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n |_, _, _, _, _, _, _| Option::none(),\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n struct NoteAndData {\n note: MockNote,\n note_nonce: Field,\n note_hash: Field,\n unique_note_hash: Field,\n inner_nullifier: Field,\n }\n\n unconstrained fn construct_note(value: Field, note_index_in_tx: u32) -> NoteAndData {\n let note_nonce = compute_note_hash_nonce(FIRST_NULLIFIER_IN_TX, note_index_in_tx);\n\n let hinted_note = MockNote::new(value)\n .contract_address(CONTRACT_ADDRESS)\n .owner(OWNER)\n .randomness(RANDOMNESS)\n .storage_slot(STORAGE_SLOT)\n .note_metadata(SettledNoteMetadata::new(note_nonce).into())\n .build_hinted_note();\n let note = hinted_note.note;\n\n let note_hash = note.compute_note_hash(OWNER, STORAGE_SLOT, RANDOMNESS);\n let unique_note_hash = compute_unique_note_hash(\n note_nonce,\n compute_siloed_note_hash(CONTRACT_ADDRESS, note_hash),\n );\n let inner_nullifier = note\n .compute_nullifier_unconstrained(OWNER, compute_note_hash_for_nullification(hinted_note))\n .expect(f\"Could not compute nullifier for note owned by {OWNER}\");\n\n NoteAndData { note, note_nonce, note_hash, unique_note_hash, inner_nullifier }\n }\n\n #[test]\n unconstrained fn single_note() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn multiple_notes_same_preimage() {\n let first_note_index_in_tx = 3;\n let first_note_and_data = construct_note(VALUE, first_note_index_in_tx);\n\n let second_note_index_in_tx = 5;\n let second_note_and_data = construct_note(VALUE, second_note_index_in_tx);\n\n // Both notes have the same preimage (and therefore packed representation), so both should be found in the same\n // call.\n assert_eq(first_note_and_data.note, second_note_and_data.note);\n let packed_note = first_note_and_data.note.pack();\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(first_note_index_in_tx, first_note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(second_note_index_in_tx, second_note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(packed_note),\n );\n\n assert_eq(discovered_notes.len(), 2);\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == first_note_and_data.note_nonce)\n & (discovered_note.note_hash == first_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == first_note_and_data.inner_nullifier)\n }));\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == second_note_and_data.note_nonce)\n & (discovered_note.note_hash == second_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == second_note_and_data.inner_nullifier)\n }));\n }\n\n #[test]\n unconstrained fn single_note_misaligned_nonce() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The note is not at the correct index\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn single_note_nonce_with_index_past_note_hashes_in_tx() {\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The nonce is computed with an index that does not exist in the tx\n let note_index_in_tx = unique_note_hashes_in_tx.len() + 5;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n // The note is inserted at an arbitrary index - its true index is out of the array's bounds\n unique_note_hashes_in_tx.set(2, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test(should_fail_with = \"identical note hashes for a transaction\")]\n unconstrained fn duplicate_unique_note_hashes() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The same unique note hash is present in two indices in the array, which is not allowed. Note that we don't\n // test all note hashes for uniqueness, only those that we actually find.\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let _ = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/nonce_discovery.nr","function_locations":[{"start":1866,"name":"attempt_note_nonce_discovery"},{"start":7210,"name":"bvec_filter"},{"start":8458,"name":"test::compute_note_hash"},{"start":9107,"name":"test::compute_note_nullifier"},{"start":9764,"name":"test::no_note_hashes"},{"start":10362,"name":"test::failed_hash_computation_is_ignored"},{"start":10959,"name":"test::failed_nullifier_computation_is_ignored"},{"start":12052,"name":"test::construct_note"},{"start":13085,"name":"test::single_note"},{"start":14249,"name":"test::multiple_notes_same_preimage"},{"start":16275,"name":"test::single_note_misaligned_nonce"},{"start":17515,"name":"test::single_note_nonce_with_index_past_note_hashes_in_tx"},{"start":18937,"name":"test::duplicate_unique_note_hashes"}]},"128":{"source":"use crate::{\n capsules::CapsuleArray,\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::partial_note::{decode_partial_note_private_message, MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN},\n processing::{\n enqueue_note_for_validation,\n get_pending_partial_notes_completion_logs,\n log_retrieval_response::{LogRetrievalResponse, MAX_LOG_CONTENT_LEN},\n },\n },\n utils::array,\n};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{address::AztecAddress, hash::sha256_to_field, traits::{Deserialize, Serialize}};\n\n/// The slot in the PXE capsules where we store a `CapsuleArray` of `DeliveredPendingPartialNote`.\npub(crate) global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT\".as_bytes(),\n);\n\n/// A partial note that was delivered but is still pending completion. Contains the information necessary to find the\n/// log that will complete it and lead to a note being discovered and delivered.\n#[derive(Serialize, Deserialize)]\npub(crate) struct DeliveredPendingPartialNote {\n pub(crate) owner: AztecAddress,\n pub(crate) randomness: Field,\n pub(crate) note_completion_log_tag: Field,\n pub(crate) note_type_id: Field,\n pub(crate) packed_private_note_content: BoundedVec,\n}\n\npub(crate) unconstrained fn process_partial_note_private_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n scope: AztecAddress,\n) {\n let decoded = decode_partial_note_private_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n // We store the information of the partial note we found in a persistent capsule in PXE, so that we can later\n // search for the public log that will complete it.\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content) = decoded.unwrap();\n\n let pending = DeliveredPendingPartialNote {\n owner,\n randomness,\n note_completion_log_tag,\n note_type_id,\n packed_private_note_content,\n };\n\n CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n )\n .push(pending);\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode partial note private message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Searches for logs that would result in the completion of pending partial notes, ultimately resulting in the notes\n/// being delivered to PXE if completed.\npub(crate) unconstrained fn fetch_and_process_partial_note_completion_logs(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n scope: AztecAddress,\n) {\n let pending_partial_notes = CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n );\n\n aztecnr_debug_log_format!(\"{} pending partial notes\")([pending_partial_notes.len() as Field]);\n\n // Each of the pending partial notes might get completed by a log containing its public values. For performance\n // reasons, we fetch all of these logs concurrently and then process them one by one, minimizing the amount of time\n // waiting for the node roundtrip.\n let maybe_completion_logs = get_pending_partial_notes_completion_logs(contract_address, pending_partial_notes);\n\n // Each entry in the maybe completion logs array corresponds to the entry in the pending partial notes array at the\n // same index. This means we can use the same index as we iterate through the responses to get both the partial\n // note and the log that might complete it.\n assert_eq(maybe_completion_logs.len(), pending_partial_notes.len());\n\n maybe_completion_logs.for_each(|i, maybe_log: Option| {\n let pending_partial_note = pending_partial_notes.get(i);\n\n if maybe_log.is_none() {\n aztecnr_debug_log_format!(\"Found no completion logs for partial note with tag {}\")(\n [pending_partial_note.note_completion_log_tag],\n );\n\n // Note that we're not removing the pending partial note from the capsule array, so we will continue\n // searching for this tagged log when performing message discovery in the future until we either find it or\n // the entry is somehow removed from the array.\n } else {\n aztecnr_debug_log_format!(\"Completion log found for partial note with tag {}\")([\n pending_partial_note.note_completion_log_tag,\n ]);\n let log = maybe_log.unwrap();\n\n // The first field in the completion log payload is the storage slot, followed by the public note\n // content fields.\n let storage_slot = log.log_payload.get(0);\n let public_note_content: BoundedVec = array::subbvec(log.log_payload, 1);\n\n // Public fields are assumed to all be placed at the end of the packed representation, so we combine\n // the private and public packed fields (i.e. the contents of the private message and public log\n // plaintext) to get the complete packed content.\n let complete_packed_note = array::append(\n pending_partial_note.packed_private_note_content,\n public_note_content,\n );\n\n let discovered_notes = attempt_note_nonce_discovery(\n log.unique_note_hashes_in_tx,\n log.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n pending_partial_note.note_type_id,\n complete_packed_note,\n );\n\n // TODO(#11627): is there anything reasonable we can do if we get a log but it doesn't result in a note\n // being found?\n if discovered_notes.len() == 0 {\n panic(\n f\"A partial note's completion log did not result in any notes being found - this should never happen\",\n );\n }\n\n aztecnr_debug_log_format!(\"Discovered {0} notes for partial note with tag {1}\")([\n discovered_notes.len() as Field,\n pending_partial_note.note_completion_log_tag,\n ]);\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n discovered_note.note_nonce,\n complete_packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n log.tx_hash,\n );\n });\n\n // Because there is only a single log for a given tag, once we've processed the tagged log then we simply\n // delete the pending work entry, regardless of whether it was actually completed or not.\n pending_partial_notes.remove(i);\n }\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr","function_locations":[{"start":1784,"name":"process_partial_note_private_msg"},{"start":3162,"name":"fetch_and_process_partial_note_completion_logs"}]},"129":{"source":"use crate::{\n event::event_interface::compute_private_serialized_event_commitment,\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::MAX_MESSAGE_CONTENT_LEN, logs::event::decode_private_event_message,\n processing::enqueue_event_for_validation,\n },\n};\nuse crate::protocol::{address::AztecAddress, traits::ToField};\n\npub(crate) unconstrained fn process_private_event_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n) {\n let decoded = decode_private_event_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (event_type_id, randomness, serialized_event) = decoded.unwrap();\n\n let event_commitment =\n compute_private_serialized_event_commitment(serialized_event, randomness, event_type_id.to_field());\n\n enqueue_event_for_validation(\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private event message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_events.nr","function_locations":[{"start":547,"name":"process_private_event_msg"}]},"130":{"source":"use crate::{\n logging::{aztecnr_debug_log_format, aztecnr_warn_log_format},\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::{decode_private_note_message, MAX_NOTE_PACKED_LEN},\n processing::enqueue_note_for_validation,\n },\n protocol::{address::AztecAddress, constants::MAX_NOTE_HASHES_PER_TX, traits::ToField},\n};\n\npub(crate) unconstrained fn process_private_note_msg(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n msg_metadata: u64,\n msg_content: BoundedVec,\n) {\n let decoded = decode_private_note_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (note_type_id, owner, storage_slot, randomness, packed_note) = decoded.unwrap();\n\n attempt_note_discovery(\n contract_address,\n tx_hash,\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private note message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Attempts discovery of a note given information about its contents and the transaction in which it is suspected the\n/// note was created.\npub unconstrained fn attempt_note_discovery(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) {\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n\n if discovered_notes.len() == 0 {\n // A private note message that results in no discovered notes means none of the computed note hashes matched\n // any unique note hash in the transaction. This could indicate a malformed or malicious message (e.g. a sender\n // providing bogus note content).\n aztecnr_warn_log_format!(\n \"Discarding private note message from tx {0} for contract {1}: no matching note hash found in the tx\",\n )(\n [tx_hash, contract_address.to_field()],\n );\n } else {\n aztecnr_debug_log_format!(\n \"Discovered {0} notes from a private message for contract {1}\",\n )(\n [discovered_notes.len() as Field, contract_address.to_field()],\n );\n }\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n owner,\n storage_slot,\n randomness,\n discovered_note.note_nonce,\n packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n tx_hash,\n );\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_notes.nr","function_locations":[{"start":861,"name":"process_private_note_msg"},{"start":2185,"name":"attempt_note_discovery"}]},"131":{"source":"use crate::messages::{\n discovery::{\n ComputeNoteHash, ComputeNoteNullifier, CustomMessageHandler, partial_notes::process_partial_note_private_msg,\n private_events::process_private_event_msg, private_notes::process_private_note_msg,\n },\n encoding::{decode_message, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN},\n encryption::{aes128::AES128, message_encryption::MessageEncryption},\n msg_type::{\n MIN_CUSTOM_MSG_TYPE_ID, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID, PRIVATE_EVENT_MSG_TYPE_ID, PRIVATE_NOTE_MSG_TYPE_ID,\n },\n processing::MessageContext,\n};\n\nuse crate::logging::{aztecnr_debug_log, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\n/// Processes a message that can contain notes, partial notes, or events.\n///\n/// Notes result in nonce discovery being performed prior to delivery, which requires knowledge of the transaction hash\n/// in which the notes would've been created (typically the same transaction in which the log was emitted), along with\n/// the list of unique note hashes in said transaction and the `compute_note_hash` and `compute_note_nullifier`\n/// functions. Once discovered, the notes are enqueued for validation.\n///\n/// Partial notes result in a pending partial note entry being stored in a PXE capsule, which will later be retrieved\n/// to search for the note's completion public log.\n///\n/// Events are processed by computing an event commitment from the serialized event data and its randomness field, then\n/// enqueueing the event data and commitment for validation.\npub unconstrained fn process_message_ciphertext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_ciphertext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n let message_plaintext_option = AES128::decrypt(message_ciphertext, recipient, contract_address);\n\n if message_plaintext_option.is_some() {\n process_message_plaintext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_plaintext_option.unwrap(),\n message_context,\n recipient,\n );\n } else {\n aztecnr_warn_log_format!(\"Could not decrypt message ciphertext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n\npub(crate) unconstrained fn process_message_plaintext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_plaintext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n // The first thing to do after decrypting the message is to determine what type of message we're processing. We\n // have 3 message types: private notes, partial notes and events.\n\n // We decode the message to obtain the message type id, metadata and content.\n let decoded = decode_message(message_plaintext);\n\n if decoded.is_some() {\n let (msg_type_id, msg_metadata, msg_content) = decoded.unwrap();\n\n if msg_type_id == PRIVATE_NOTE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private note msg\");\n\n process_private_note_msg(\n contract_address,\n message_context.tx_hash,\n message_context.unique_note_hashes_in_tx,\n message_context.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n msg_metadata,\n msg_content,\n );\n } else if msg_type_id == PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing partial note private msg\");\n\n process_partial_note_private_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n recipient,\n );\n } else if msg_type_id == PRIVATE_EVENT_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private event msg\");\n\n process_private_event_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n );\n } else if msg_type_id < MIN_CUSTOM_MSG_TYPE_ID {\n // The message type ID falls in the range reserved for aztec.nr built-in types but wasn't matched above.\n // This most likely means the message is malformed or a custom message was incorrectly assigned a reserved\n // ID. Custom message types must use IDs allocated via `custom_msg_type_id`.\n aztecnr_warn_log_format!(\n \"Message type ID {0} is in the reserved range but is not recognized, ignoring. See https://docs.aztec.network/errors/3\",\n )(\n [msg_type_id as Field],\n );\n } else if process_custom_message.is_some() {\n process_custom_message.unwrap()(\n contract_address,\n msg_type_id,\n msg_metadata,\n msg_content,\n message_context,\n recipient,\n );\n } else {\n // A custom message was received but no handler is configured. This likely means the contract emits custom\n // messages but forgot to register a handler via `AztecConfig::custom_message_handler`.\n aztecnr_warn_log_format!(\n \"Received custom message with type id {0} but no handler is configured, ignoring. See https://docs.aztec.network/errors/2\",\n )(\n [msg_type_id as Field],\n );\n }\n } else {\n aztecnr_warn_log_format!(\"Could not decode message plaintext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/process_message.nr","function_locations":[{"start":1975,"name":"process_message_ciphertext"},{"start":2968,"name":"process_message_plaintext"}]},"132":{"source":"// TODO(#12750): don't make these values assume we're using AES.\nuse crate::protocol::constants::PRIVATE_LOG_CIPHERTEXT_LEN;\nuse crate::utils::array;\n\n// We reassign to the constant here to communicate the distinction between a log and a message. In Aztec.nr, unlike in\n// protocol circuits, we have a concept of a message that can be emitted either as a private log or as an offchain\n// message. Message is a piece of data that is to be eventually delivered to a contract via the `process_message(...)`\n// utility function function that is injected by the #[aztec] macro. Note: PRIVATE_LOG_CIPHERTEXT_LEN is an amount of\n// fields, so MESSAGE_CIPHERTEXT_LEN is the size of the message in fields.\npub global MESSAGE_CIPHERTEXT_LEN: u32 = PRIVATE_LOG_CIPHERTEXT_LEN;\n\n// TODO(#12750): The global variables below should not be here as they are AES128 specific.\n// The header plaintext is 2 bytes (ciphertext length), padded to the 16-byte AES block size by PKCS#7.\npub(crate) global HEADER_CIPHERTEXT_SIZE_IN_BYTES: u32 = 16;\n// AES PKCS#7 always adds at least one byte of padding. Since each plaintext field is 32 bytes (a multiple of the\n// 16-byte AES block size), a full 16-byte padding block is always appended.\npub(crate) global AES128_PKCS7_EXPANSION_IN_BYTES: u32 = 16;\n\npub global EPH_PK_X_SIZE_IN_FIELDS: u32 = 1;\n\n// (15 - 1) * 31 - 16 - 16 = 402. Note: We multiply by 31 because ciphertext bytes are stored in fields using\n// encode_bytes_as_fields, which packs 31 bytes per field (since a Field is ~254 bits and can safely store 31 whole\n// bytes).\npub(crate) global MESSAGE_PLAINTEXT_SIZE_IN_BYTES: u32 = (MESSAGE_CIPHERTEXT_LEN - EPH_PK_X_SIZE_IN_FIELDS) * 31\n - HEADER_CIPHERTEXT_SIZE_IN_BYTES\n - AES128_PKCS7_EXPANSION_IN_BYTES;\n// The plaintext bytes represent Field values that were originally serialized using encode_fields_as_bytes, which\n// converts each Field to 32 bytes. To convert the plaintext bytes back to fields, we divide by 32. 402 / 32 = 12\npub global MESSAGE_PLAINTEXT_LEN: u32 = MESSAGE_PLAINTEXT_SIZE_IN_BYTES / 32;\n\npub global MESSAGE_EXPANDED_METADATA_LEN: u32 = 1;\n\n// The standard message layout is composed of:\n// - an initial field called the 'expanded metadata'\n// - an arbitrary number of fields following that called the 'message content'\n//\n// ```\n// message: [ msg_expanded_metadata, ...msg_content ]\n// ```\n//\n// The expanded metadata itself is interpreted as a u128, of which:\n// - the upper 64 bits are the message type id\n// - the lower 64 bits are called the 'message metadata'\n//\n// ```\n// msg_expanded_metadata: [ msg_type_id | msg_metadata ]\n// <--- 64 bits --->|<--- 64 bits --->\n// ```\n//\n// The meaning of the message metadata and message content depend on the value of the message type id. Note that there\n// is nothing special about the message metadata, it _can_ be considered part of the content. It just has a different\n// name to make it distinct from the message content given that it is not a full field.\n\n/// The maximum length of a message's content, i.e. not including the expanded message metadata.\npub global MAX_MESSAGE_CONTENT_LEN: u32 = MESSAGE_PLAINTEXT_LEN - MESSAGE_EXPANDED_METADATA_LEN;\n\n/// Encodes a message following aztec-nr's standard message encoding. This message can later be decoded with\n/// `decode_message` to retrieve the original values.\n///\n/// - The `msg_type` is an identifier that groups types of messages that are all processed the same way, e.g. private\n/// notes or events. Possible values are defined in `aztec::messages::msg_type`.\n/// - The `msg_metadata` and `msg_content` are the values stored in the message, whose meaning depends on the\n/// `msg_type`. The only special thing about `msg_metadata` that separates it from `msg_content` is that it is a u64\n/// instead of a full Field (due to details of how messages are encoded), allowing applications that can fit values\n/// into this smaller variable to achieve higher data efficiency.\npub fn encode_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; N],\n) -> [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] {\n std::static_assert(\n msg_content.len() <= MAX_MESSAGE_CONTENT_LEN,\n \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\",\n );\n\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n let mut message: [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] = std::mem::zeroed();\n\n message[0] = to_expanded_metadata(msg_type, msg_metadata);\n for i in 0..msg_content.len() {\n message[MESSAGE_EXPANDED_METADATA_LEN + i] = msg_content[i];\n }\n\n message\n}\n\n/// Decodes a standard aztec-nr message, i.e. one created via `encode_message`, returning the original encoded values.\n///\n/// Returns `None` if the message is empty or has invalid (>128 bit) expanded metadata.\n///\n/// Note that `encode_message` returns a fixed size array while this function takes a `BoundedVec`: this is because\n/// prior to decoding the message type is unknown, and consequentially not known at compile time. If working with\n/// fixed-size messages, consider using `BoundedVec::from_array` to convert them.\npub unconstrained fn decode_message(\n message: BoundedVec,\n) -> Option<(u64, u64, BoundedVec)> {\n Option::some(message)\n .and_then(|message| {\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring\n // of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n if message.len() < MESSAGE_EXPANDED_METADATA_LEN {\n Option::none()\n } else {\n Option::some(message.get(0))\n }\n })\n .and_then(|msg_expanded_metadata| from_expanded_metadata(msg_expanded_metadata))\n .map(|(msg_type_id, msg_metadata)| {\n let msg_content = array::subbvec(message, MESSAGE_EXPANDED_METADATA_LEN);\n (msg_type_id, msg_metadata, msg_content)\n })\n}\n\nglobal U64_SHIFT_MULTIPLIER: Field = 2.pow_32(64);\n\nfn to_expanded_metadata(msg_type: u64, msg_metadata: u64) -> Field {\n // We use multiplication instead of bit shifting operations to shift the type bits as bit shift operations are\n // expensive in circuits.\n let type_field: Field = (msg_type as Field) * U64_SHIFT_MULTIPLIER;\n let msg_metadata_field = msg_metadata as Field;\n\n type_field + msg_metadata_field\n}\n\nglobal TWO_POW_128: Field = 2.pow_32(128);\n\n/// Unpacks expanded metadata into (msg_type, msg_metadata). Returns `None` if `input >= 2^128`.\nfn from_expanded_metadata(input: Field) -> Option<(u64, u64)> {\n if input.lt(TWO_POW_128) {\n let msg_metadata = (input as u64);\n let msg_type = ((input - (msg_metadata as Field)) / U64_SHIFT_MULTIPLIER) as u64;\n // Use division instead of bit shift since bit shifts are expensive in circuits\n Option::some((msg_type, msg_metadata))\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray::subarray;\n use super::{\n decode_message, encode_message, from_expanded_metadata, MAX_MESSAGE_CONTENT_LEN, to_expanded_metadata,\n TWO_POW_128,\n };\n\n global U64_MAX: u64 = (2.pow_32(64) - 1) as u64;\n global U128_MAX: Field = (2.pow_32(128) - 1);\n\n #[test]\n unconstrained fn encode_decode_empty_message(msg_type: u64, msg_metadata: u64) {\n let encoded = encode_message(msg_type, msg_metadata, []);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), 0);\n }\n\n #[test]\n unconstrained fn encode_decode_short_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN / 2],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn encode_decode_full_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn to_expanded_metadata_packing() {\n // Test case 1: All bits set\n let packed = to_expanded_metadata(U64_MAX, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let packed = to_expanded_metadata(U64_MAX, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let packed = to_expanded_metadata(0, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let packed = to_expanded_metadata(0, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn from_expanded_metadata_packing() {\n // Test case 1: All bits set\n let input = U128_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let input = (U128_MAX - U64_MAX as Field);\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let input = U64_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let input = 0;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn to_from_expanded_metadata(original_msg_type: u64, original_msg_metadata: u64) {\n let packed = to_expanded_metadata(original_msg_type, original_msg_metadata);\n let (unpacked_msg_type, unpacked_msg_metadata) = from_expanded_metadata(packed).unwrap();\n\n assert_eq(original_msg_type, unpacked_msg_type);\n assert_eq(original_msg_metadata, unpacked_msg_metadata);\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_message() {\n let msg_type_id: u64 = 42;\n let msg_metadata: u64 = 99;\n let mut msg_content = [0; MAX_MESSAGE_CONTENT_LEN];\n for i in 0..MAX_MESSAGE_CONTENT_LEN {\n msg_content[i] = i as Field;\n }\n\n let encoded = encode_message(msg_type_id, msg_metadata, msg_content);\n let (decoded_type_id, decoded_metadata, decoded_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_type_id, msg_type_id);\n assert_eq(decoded_metadata, msg_metadata);\n assert_eq(decoded_content, BoundedVec::from_array(msg_content));\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_message_fails() {\n let msg_content = [0; MAX_MESSAGE_CONTENT_LEN + 1];\n let _ = encode_message(0, 0, msg_content);\n }\n\n #[test]\n unconstrained fn decode_empty_message_returns_none() {\n assert(decode_message(BoundedVec::new()).is_none());\n }\n\n #[test]\n unconstrained fn decode_message_with_oversized_metadata_returns_none() {\n let message = BoundedVec::from_array([TWO_POW_128]);\n assert(decode_message(message).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encoding.nr","function_locations":[{"start":4136,"name":"encode_message"},{"start":5594,"name":"decode_message"},{"start":6617,"name":"to_expanded_metadata"},{"start":7131,"name":"from_expanded_metadata"},{"start":7894,"name":"tests::encode_decode_empty_message"},{"start":8444,"name":"tests::encode_decode_short_message"},{"start":9090,"name":"tests::encode_decode_full_message"},{"start":9628,"name":"tests::to_expanded_metadata_packing"},{"start":10713,"name":"tests::from_expanded_metadata_packing"},{"start":11770,"name":"tests::to_from_expanded_metadata"},{"start":12151,"name":"tests::encode_decode_max_size_message"},{"start":12934,"name":"tests::encode_oversized_message_fails"},{"start":13123,"name":"tests::decode_empty_message_returns_none"},{"start":13280,"name":"tests::decode_message_with_oversized_metadata_returns_none"}]},"133":{"source":"use crate::protocol::{address::AztecAddress, public_keys::AddressPoint, traits::ToField};\n\nuse crate::{\n keys::{\n ecdh_shared_secret::{\n compute_app_siloed_shared_secret, derive_ecdh_shared_secret, derive_shared_secret_field_mask,\n derive_shared_secret_subkey,\n },\n ephemeral::generate_positive_ephemeral_key_pair,\n },\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::{\n EPH_PK_X_SIZE_IN_FIELDS, HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN,\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES,\n },\n encryption::message_encryption::MessageEncryption,\n logs::arithmetic_generics_utils::{\n get_arr_of_size__message_bytes__from_PT, get_arr_of_size__message_bytes_padding__from_PT,\n },\n },\n oracle::{aes128_decrypt::try_aes128_decrypt, random::random, shared_secret::get_shared_secret},\n utils::{\n array,\n conversion::{\n bytes_as_fields::{decode_bytes_from_fields, encode_bytes_as_fields},\n fields_as_bytes::{encode_fields_as_bytes, try_decode_fields_from_bytes},\n },\n point::point_from_x_coord_and_sign,\n },\n};\n\nuse std::aes128::aes128_encrypt;\n\n/// Computes N close-to-uniformly-random 256 bits from a given app-siloed shared secret.\n///\n/// NEVER re-use the same iv and sym_key. DO NOT call this function more than once with the same s_app.\n///\n/// This function is only known to be safe if s_app is derived from combining a random ephemeral key with an\n/// address point and a contract address. See big comment within the body of the function.\nfn extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app: Field) -> [[u8; 32]; N] {\n /*\n * Unsafe because of https://eprint.iacr.org/2010/264.pdf Page 13, Lemma 2 (and the two paragraphs below it).\n *\n * If you call this function, you need to be careful and aware of how the arg `s_app` has been derived.\n *\n * The paper says that the way you derive aes keys and IVs should be fine with poseidon2 (modelled as a RO),\n * as long as you _don't_ use Poseidon2 as a PRG to generate the two exponents x & y which multiply to the\n * shared secret S:\n *\n * S = [x*y]*G.\n *\n * (Otherwise, you would have to \"key\" poseidon2, i.e. generate a uniformly string K which can be public and\n * compute Hash(x) as poseidon(K,x)).\n * In that lemma, k would be 2*254=508, and m would be the number of points on the grumpkin curve (which is\n * close to r according to the Hasse bound).\n *\n * Our shared secret S is [esk * address_sk] * G, and the question is: Can we compute hash(S) using poseidon2\n * instead of sha256?\n *\n * Well, esk is random and not generated with poseidon2, so that's good.\n * What about address_sk?\n * Well, address_sk = poseidon2(stuff) + ivsk, so there was some discussion about whether address_sk is\n * independent of poseidon2. Given that ivsk is random and independent of poseidon2, the address_sk is also\n * independent of poseidon2.\n *\n * Tl;dr: we believe it's safe to hash S = [esk * address_sk] * G using poseidon2, in order to derive a\n * symmetric key.\n *\n * If you're calling this function for a differently-derived `s_app`, be careful.\n */\n \n\n /* The output of this function needs to be 32 random bytes.\n * A single field won't give us 32 bytes of entropy. So we compute two \"random\" fields, by poseidon-hashing\n * with two different indices. We then extract the last 16 (big endian) bytes of each \"random\" field.\n * Note: we use to_be_bytes because it's slightly more efficient. But we have to be careful not to take bytes\n * from the \"big end\", because the \"big\" byte is not uniformly random over the byte: it only has < 6 bits of\n * randomness, because it's the big end of a 254-bit field element.\n */\n\n let mut all_bytes: [[u8; 32]; N] = std::mem::zeroed();\n std::static_assert(N < 256, \"N too large\");\n for k in 0..N {\n let rand1: Field = derive_shared_secret_subkey(s_app, 2 * k);\n let rand2: Field = derive_shared_secret_subkey(s_app, 2 * k + 1);\n\n let rand1_bytes: [u8; 32] = rand1.to_be_bytes();\n let rand2_bytes: [u8; 32] = rand2.to_be_bytes();\n\n let mut bytes: [u8; 32] = [0; 32];\n for i in 0..16 {\n // We take bytes from the \"little end\" of the be-bytes arrays:\n let j = 32 - i - 1;\n bytes[i] = rand1_bytes[j];\n bytes[16 + i] = rand2_bytes[j];\n }\n\n all_bytes[k] = bytes;\n }\n\n all_bytes\n}\n\nfn derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(\n many_random_256_bits: [[u8; 32]; N],\n) -> [([u8; 16], [u8; 16]); N] {\n // Many (sym_key, iv) pairs:\n let mut many_pairs: [([u8; 16], [u8; 16]); N] = std::mem::zeroed();\n for k in 0..N {\n let random_256_bits = many_random_256_bits[k];\n let mut sym_key = [0; 16];\n let mut iv = [0; 16];\n for i in 0..16 {\n sym_key[i] = random_256_bits[i];\n iv[i] = random_256_bits[i + 16];\n }\n many_pairs[k] = (sym_key, iv);\n }\n\n many_pairs\n}\n\npub fn derive_aes_symmetric_key_and_iv_from_shared_secret(s_app: Field) -> [([u8; 16], [u8; 16]); N] {\n let many_random_256_bits: [[u8; 32]; N] = extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app);\n\n derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(many_random_256_bits)\n}\n\npub struct AES128 {}\n\nimpl MessageEncryption for AES128 {\n\n /// AES128-CBC encryption for Aztec protocol messages.\n ///\n /// ## Overview\n ///\n /// The plaintext is an array of up to `MESSAGE_PLAINTEXT_LEN` (12) fields. The output is always exactly\n /// `MESSAGE_CIPHERTEXT_LEN` (15) fields, regardless of plaintext size. All output fields except the\n /// ephemeral public key are uniformly random `Field` values to any observer without knowledge of the\n /// shared secret, making all encrypted messages indistinguishable by size or content.\n ///\n /// ## PKCS#7 Padding\n ///\n /// AES operates on 16-byte blocks, so the plaintext must be padded to a multiple of 16. PKCS#7 padding always\n /// adds at least 1 byte (so the receiver can always detect and strip it), which means:\n /// - 1 B plaintext -> 15 B padding -> 16 B total\n /// - 15 B plaintext -> 1 B padding -> 16 B total\n /// - 16 B plaintext -> 16 B padding -> 32 B total (full extra block)\n ///\n /// In general: if the plaintext is already a multiple of 16, a full 16-byte padding block is appended.\n ///\n /// ## Encryption Steps\n ///\n /// **1. Body encryption.** The plaintext fields are serialized to bytes (32 bytes per field) and AES-128-CBC\n /// encrypted. Since 32 is a multiple of 16, PKCS#7 always adds a full 16-byte padding block (see above):\n ///\n /// ```text\n /// +---------------------------------------------+\n /// | body ct |\n /// | PlaintextLen*32 + 16 B |\n /// +-------------------------------+--------------+\n /// | encrypted plaintext fields | PKCS#7 (16B) |\n /// | (serialized at 32 B each) | |\n /// +-------------------------------+--------------+\n /// ```\n ///\n /// **2. Header encryption.** The byte length of `body_ct` is stored as a 2-byte big-endian integer. This 2-byte\n /// header plaintext is then AES-encrypted; PKCS#7 pads the remaining 14 bytes to fill one 16-byte AES block,\n /// producing a 16-byte header ciphertext:\n ///\n /// ```text\n /// +---------------------------+\n /// | header ct |\n /// | 16 B |\n /// +--------+------------------+\n /// | body ct| PKCS#7 (14B) |\n /// | length | |\n /// | (2 B) | |\n /// +--------+------------------+\n /// ```\n ///\n /// ## Wire Format\n ///\n /// Messages are transmitted as fields, not bytes. A field is ~254 bits and can safely store 31 whole bytes, so\n /// we need to pack our byte data into 31-byte chunks. This packing drives the wire format.\n ///\n /// **Step 1 -- Assemble bytes.** The ciphertexts are laid out in a byte array, padded with zero bytes to a\n /// multiple of 31 so it divides evenly into fields:\n ///\n /// ```text\n /// +------------+-------------------------+---------+\n /// | header ct | body ct | byte pad|\n /// | 16 B | PlaintextLen*32 + 16 B | (zeros) |\n /// +------------+-------------------------+---------+\n /// |<-------- padded to a multiple of 31 B -------->|\n /// ```\n ///\n /// **Step 2 -- Pack and mask.** The byte array is split into 31-byte chunks, each stored in one field. A\n /// Poseidon2-derived mask (see `derive_shared_secret_field_mask`) is added to each so that the resulting\n /// fields appear as uniformly random `Field` values to any observer without knowledge of the shared secret,\n /// hiding the fact that the underlying ciphertext consists of 128-bit AES blocks.\n ///\n /// **Step 3 -- Assemble ciphertext.** The ephemeral public key x-coordinate is prepended and random field padding\n /// is appended to fill to 15 fields:\n ///\n /// ```text\n /// +----------+-------------------------+-------------------+\n /// | eph_pk.x | masked message fields | random field pad |\n /// | | (packed 31 B per field) | (fills to 15) |\n /// +----------+-------------------------+-------------------+\n /// |<---------- MESSAGE_CIPHERTEXT_LEN = 15 fields -------->|\n /// ```\n ///\n /// ## Key Derivation\n ///\n /// The raw ECDH shared secret point is first app-siloed into a scalar `s_app` by hashing with the contract\n /// address (see\n /// [`compute_app_siloed_shared_secret`](crate::keys::ecdh_shared_secret::compute_app_siloed_shared_secret)).\n /// Two (key, IV) pairs are then derived from `s_app` via indexed Poseidon2 hashing: one pair for the body\n /// ciphertext and one for the header ciphertext.\n fn encrypt(\n plaintext: [Field; PlaintextLen],\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> [Field; MESSAGE_CIPHERTEXT_LEN] {\n std::static_assert(\n PlaintextLen <= MESSAGE_PLAINTEXT_LEN,\n \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\",\n );\n\n // AES 128 operates on bytes, not fields, so we need to convert the fields to bytes. (This process is then\n // reversed when processing the message in `process_message_ciphertext`)\n let plaintext_bytes = encode_fields_as_bytes(plaintext);\n\n // Derive ECDH shared secret with recipient using a fresh ephemeral keypair.\n let (eph_sk, eph_pk) = generate_positive_ephemeral_key_pair();\n\n let raw_shared_secret = derive_ecdh_shared_secret(\n eph_sk,\n recipient\n .to_address_point()\n .unwrap_or_else(|| {\n aztecnr_warn_log_format!(\n \"Attempted to encrypt message for an invalid recipient ({0})\",\n )(\n [recipient.to_field()],\n );\n\n // Safety: if the recipient is an invalid address, then it is not possible to encrypt a message for\n // them because we cannot establish a shared secret. This is never expected to occur during normal\n // operation. However, it is technically possible for us to receive an invalid address, and we must\n // therefore handle it. We could simply fail, but that'd introduce a potential security issue in\n // which an attacker forces a contract to encrypt a message for an invalid address, resulting in an\n // impossible transaction - this is sometimes called a 'king of the hill' attack. We choose instead\n // to not fail and encrypt the plaintext regardless using the shared secret that results from a\n // random valid address. The sender is free to choose this address and hence shared secret, but\n // this has no security implications as they already know not only the full plaintext but also the\n // ephemeral private key anyway.\n unsafe {\n random_address_point()\n }\n })\n .inner,\n );\n\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n // It is safe to derive AES keys from `s_app` using Poseidon2 because `s_app` was derived from an ECDH shared\n // secret using an AztecAddress (the recipient). See the block comment in\n // `extract_many_close_to_uniformly_random_256_bits_using_poseidon2` for more info.\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n let ciphertext_bytes = aes128_encrypt(plaintext_bytes, body_iv, body_sym_key);\n\n // Each plaintext field is 32 bytes (a multiple of the 16-byte AES block\n // size), so PKCS#7 always appends a full 16-byte padding block:\n // |ciphertext| = PlaintextLen*32 + 16 = 16 * (1 + PlaintextLen*32 / 16)\n std::static_assert(\n ciphertext_bytes.len() == 16 * (1 + (PlaintextLen * 32) / 16),\n \"unexpected ciphertext length\",\n );\n\n // Encrypt a 2-byte header containing the body ciphertext length.\n let header_plaintext = encode_header(ciphertext_bytes.len());\n\n // Note: the aes128_encrypt builtin fn automatically appends bytes to the input, according to pkcs#7; hence why\n // the output `header_ciphertext_bytes` is 16 bytes larger than the input in this case.\n let header_ciphertext_bytes = aes128_encrypt(header_plaintext, header_iv, header_sym_key);\n // Verify expected header ciphertext size at compile time.\n std::static_assert(\n header_ciphertext_bytes.len() == HEADER_CIPHERTEXT_SIZE_IN_BYTES,\n \"unexpected ciphertext header length\",\n );\n\n // Assemble the message byte array:\n // [header_ct (16B)] [body_ct] [padding to mult of 31]\n let message_bytes_padding_to_mult_31 = get_arr_of_size__message_bytes_padding__from_PT::();\n\n let mut message_bytes = get_arr_of_size__message_bytes__from_PT::();\n\n std::static_assert(\n message_bytes.len() % 31 == 0,\n \"Unexpected error: message_bytes.len() should be divisible by 31, by construction.\",\n );\n\n let mut offset = 0;\n for i in 0..header_ciphertext_bytes.len() {\n message_bytes[offset + i] = header_ciphertext_bytes[i];\n }\n offset += header_ciphertext_bytes.len();\n\n for i in 0..ciphertext_bytes.len() {\n message_bytes[offset + i] = ciphertext_bytes[i];\n }\n offset += ciphertext_bytes.len();\n\n for i in 0..message_bytes_padding_to_mult_31.len() {\n message_bytes[offset + i] = message_bytes_padding_to_mult_31[i];\n }\n offset += message_bytes_padding_to_mult_31.len();\n\n // Ideally we would be able to have a static assert where we check that the offset would be such that we've\n // written to the entire log_bytes array, but we cannot since Noir does not treat the offset as a comptime\n // value (despite the values that it goes through being known at each stage). We instead check that the\n // computation used to obtain the offset computes the expected value (which we _can_ do in a static check), and\n // then add a cheap runtime check to also validate that the offset matches this.\n std::static_assert(\n header_ciphertext_bytes.len() + ciphertext_bytes.len() + message_bytes_padding_to_mult_31.len()\n == message_bytes.len(),\n \"unexpected message length\",\n );\n assert(offset == message_bytes.len(), \"unexpected encrypted message length\");\n\n // Pack message bytes into fields (31 bytes per field) and prepend eph_pk.x.\n let message_bytes_as_fields = encode_bytes_as_fields(message_bytes);\n\n let mut ciphertext: [Field; MESSAGE_CIPHERTEXT_LEN] = [0; MESSAGE_CIPHERTEXT_LEN];\n\n ciphertext[0] = eph_pk.x;\n\n // Mask each content field with a Poseidon2-derived value, so that they appear as uniformly random `Field`\n // values\n let mut offset = 1;\n for i in 0..message_bytes_as_fields.len() {\n let mask = derive_shared_secret_field_mask(s_app, i as u32);\n ciphertext[offset + i] = message_bytes_as_fields[i] + mask;\n }\n offset += message_bytes_as_fields.len();\n\n // Pad with random fields so that padding is indistinguishable from masked data fields.\n for i in offset..MESSAGE_CIPHERTEXT_LEN {\n // Safety: we assume that the sender wants for the message to be private - a malicious one could simply\n // reveal its contents publicly. It is therefore fine to trust the sender to provide random padding.\n ciphertext[i] = unsafe { random() };\n }\n\n ciphertext\n }\n\n unconstrained fn decrypt(\n ciphertext: BoundedVec,\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> Option> {\n // Extract the ephemeral public key x-coordinate and masked fields, returning None for empty ciphertext.\n if ciphertext.len() > 0 {\n let masked_fields: BoundedVec =\n array::subbvec(ciphertext, EPH_PK_X_SIZE_IN_FIELDS);\n Option::some((ciphertext.get(0), masked_fields))\n } else {\n Option::none()\n }\n .and_then(|(eph_pk_x, masked_fields)| {\n // With the x-coordinate of the ephemeral public key we can reconstruct the point as we know that the\n // y-coordinate must be positive. This may fail however, as not all x-coordinates are on the curve. In\n // that case, we simply return `Option::none`.\n point_from_x_coord_and_sign(eph_pk_x, true).and_then(|eph_pk| {\n let s_app = get_shared_secret(recipient, eph_pk, contract_address);\n\n let unmasked_fields = masked_fields.mapi(|i, field| {\n let unmasked = unmask_field(s_app, i, field);\n // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it\n // later, so we can simply set it to 0\n unmasked.unwrap_or(0)\n });\n let ciphertext_without_eph_pk_x = decode_bytes_from_fields(unmasked_fields);\n\n // Derive symmetric keys:\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n // Extract the header ciphertext\n let header_start = 0;\n let header_ciphertext: [u8; HEADER_CIPHERTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), header_start);\n // We need to convert the array to a BoundedVec because the oracle expects a BoundedVec as it's\n // designed to work with messages with unknown length at compile time. This would not be necessary\n // here as the header ciphertext length is fixed. But we do it anyway to not have to have duplicate\n // oracles.\n let header_ciphertext_bvec =\n BoundedVec::::from_array(header_ciphertext);\n\n try_aes128_decrypt(header_ciphertext_bvec, header_iv, header_sym_key)\n // Extract ciphertext length from header (2 bytes, big-endian)\n .and_then(|header_plaintext| extract_ciphertext_length(header_plaintext))\n .filter(|ciphertext_length| ciphertext_length <= MESSAGE_PLAINTEXT_SIZE_IN_BYTES)\n .map(|ciphertext_length| {\n // Extract and decrypt main ciphertext\n let ciphertext_start = header_start + HEADER_CIPHERTEXT_SIZE_IN_BYTES;\n let ciphertext_with_padding: [u8; MESSAGE_PLAINTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), ciphertext_start);\n BoundedVec::from_parts(ciphertext_with_padding, ciphertext_length)\n })\n // Decrypt main ciphertext and return it\n .and_then(|ciphertext| try_aes128_decrypt(ciphertext, body_iv, body_sym_key))\n // Convert bytes back to fields (32 bytes per field). Returns None if the actual bytes are\n // not valid.\n .and_then(|plaintext_bytes| try_decode_fields_from_bytes(plaintext_bytes))\n })\n })\n }\n}\n\n/// Encodes the body ciphertext length into a 2-byte big-endian header.\nfn encode_header(ciphertext_length: u32) -> [u8; 2] {\n [(ciphertext_length >> 8) as u8, ciphertext_length as u8]\n}\n\n/// Extracts the body ciphertext length from a decrypted header as a 2-byte big-endian integer.\n///\n/// Returns `Option::none()` if the header has fewer than 2 bytes.\nunconstrained fn extract_ciphertext_length(header: BoundedVec) -> Option {\n if header.len() >= 2 {\n Option::some(((header.get(0) as u32) << 8) | (header.get(1) as u32))\n } else {\n Option::none()\n }\n}\n\n/// 2^248: upper bound for values that fit in 31 bytes\nglobal TWO_POW_248: Field = 2.pow_32(248);\n\n/// Removes the Poseidon2-derived mask from a ciphertext field. Returns the unmasked value if it fits in 31 bytes\n/// (a content field), or `None` if it doesn't (random padding). Unconstrained to prevent accidental use in\n/// constrained context.\nunconstrained fn unmask_field(s_app: Field, index: u32, masked: Field) -> Option {\n let unmasked = masked - derive_shared_secret_field_mask(s_app, index);\n if unmasked.lt(TWO_POW_248) {\n Option::some(unmasked)\n } else {\n Option::none()\n }\n}\n\n/// Produces a random valid address point, i.e. one that is on the curve. This is equivalent to calling\n/// [`AztecAddress::to_address_point`] on a random valid address.\nunconstrained fn random_address_point() -> AddressPoint {\n let mut result = std::mem::zeroed();\n\n loop {\n // We simply produce random x coordinates until we find one that is on the curve. About half of the x\n // coordinates fulfill this condition, so this should only take a few iterations at most.\n let x_coord = random();\n let point = point_from_x_coord_and_sign(x_coord, true);\n if point.is_some() {\n result = AddressPoint { inner: point.unwrap() };\n break;\n }\n }\n\n result\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::{compute_app_siloed_shared_secret, derive_ecdh_shared_secret},\n messages::{\n encoding::{HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_PLAINTEXT_LEN, MESSAGE_PLAINTEXT_SIZE_IN_BYTES},\n encryption::message_encryption::MessageEncryption,\n },\n test::helpers::test_environment::TestEnvironment,\n };\n use crate::protocol::{address::AztecAddress, traits::FromField};\n use super::{AES128, encode_header, random_address_point};\n use std::{embedded_curve_ops::EmbeddedCurveScalar, test::OracleMock};\n\n #[test]\n unconstrained fn encrypt_decrypt_deterministic() {\n let env = TestEnvironment::new();\n\n // Message decryption requires oracles that are only available during private execution\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n\n let recipient = AztecAddress::from_field(\n 0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70c,\n );\n\n // Mock random values for deterministic test\n let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(eph_sk).times(1);\n\n let randomness = 0x0101010101010101010101010101010101010101010101010101010101010101;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(randomness).times(1000000);\n\n let _ = OracleMock::mock(\"aztec_prv_getNextAppTagAsSender\").returns(42);\n\n // Encrypt the message\n let encrypted_message = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n // Compute the same app-siloed shared secret that the oracle would return\n let raw_shared_secret = derive_ecdh_shared_secret(\n EmbeddedCurveScalar::from_field(eph_sk),\n recipient.to_address_point().unwrap().inner,\n );\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n let _ = OracleMock::mock(\"aztec_utl_getSharedSecret\").returns(s_app);\n\n // Decrypt the message\n let decrypted = AES128::decrypt(encrypted_message, recipient, contract_address).unwrap();\n\n // The decryption function spits out a BoundedVec because it's designed to work with messages with unknown\n // length at compile time. For this reason we need to convert the original input to a BoundedVec.\n let plaintext_bvec = BoundedVec::::from_array(plaintext);\n\n // Verify decryption matches original plaintext\n assert_eq(decrypted, plaintext_bvec, \"Decrypted bytes should match original plaintext\");\n\n // The following is a workaround of \"struct is never constructed\" Noir compilation error (we only ever use\n // static methods of the struct).\n let _ = AES128 {};\n });\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_random() {\n // Same as `encrypt_decrypt_deterministic`, except we don't mock any of the oracles and rely on\n // `TestEnvironment` instead.\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test]\n unconstrained fn encrypt_to_invalid_address() {\n // x = 3 is a non-residue for this curve, resulting in an invalid address\n let invalid_address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n\n let _ = AES128::encrypt([1, 2, 3, 4], invalid_address, contract_address);\n }\n\n // Documents the PKCS#7 padding behavior that `encrypt` relies on (see its static_assert).\n #[test]\n fn pkcs7_padding_always_adds_at_least_one_byte() {\n let key = [0 as u8; 16];\n let iv = [0 as u8; 16];\n\n // 1 byte input + 15 bytes padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 1], iv, key).len(), 16);\n\n // 15 bytes input + 1 byte padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 15], iv, key).len(), 16);\n\n // 16 bytes input (block-aligned) + full 16-byte padding block = 32 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 16], iv, key).len(), 32);\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_max_size_plaintext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let mut plaintext = [0; MESSAGE_PLAINTEXT_LEN];\n for i in 0..MESSAGE_PLAINTEXT_LEN {\n plaintext[i] = i as Field;\n }\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test(should_fail_with = \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\")]\n unconstrained fn encrypt_oversized_plaintext() {\n let address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n let plaintext: [Field; MESSAGE_PLAINTEXT_LEN + 1] = [0; MESSAGE_PLAINTEXT_LEN + 1];\n let _ = AES128::encrypt(plaintext, address, contract_address);\n }\n\n #[test]\n unconstrained fn random_address_point_produces_valid_points() {\n // About half of random addresses are invalid, so testing just a couple gives us high confidence that\n // `random_address_point` is indeed producing valid addresses.\n for _ in 0..10 {\n let random_address = AztecAddress { inner: random_address_point().inner.x };\n assert(random_address.to_address_point().is_some());\n }\n }\n\n #[test]\n unconstrained fn decrypt_invalid_ephemeral_public_key() {\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3, 4];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n // The first field of the ciphertext is the x-coordinate of the ephemeral public key. We set it to a known\n // non-residue (3), causing `decrypt` to fail to produce a decryption shared secret.\n let mut bad_ciphertext = BoundedVec::from_array(ciphertext);\n bad_ciphertext.set(0, 3);\n\n assert(AES128::decrypt(bad_ciphertext, recipient, contract_address).is_none());\n });\n }\n\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_ciphertext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n assert(AES128::decrypt(BoundedVec::new(), recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header AES decrypt oracle to return an empty result. The TS oracle never throws on invalid\n // input: it decrypts to garbage bytes or returns empty\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_header() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let empty_header = BoundedVec::::new();\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(empty_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header oracle to return a 2-byte header that decodes to a ciphertext_length one past the maximum\n // allowed value, verifying the edge case is handled correctly.\n #[test]\n unconstrained fn decrypt_returns_none_on_oversized_ciphertext_length() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let bad_header = BoundedVec::::from_array(encode_header(\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES + 1,\n ));\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(bad_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr","function_locations":[{"start":1764,"name":"extract_many_close_to_uniformly_random_256_bits_using_poseidon2"},{"start":4783,"name":"derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits"},{"start":5332,"name":"derive_aes_symmetric_key_and_iv_from_shared_secret"},{"start":10365,"name":"::encrypt"},{"start":17702,"name":"::decrypt"},{"start":21732,"name":"encode_header"},{"start":22063,"name":"extract_ciphertext_length"},{"start":22648,"name":"unmask_field"},{"start":23061,"name":"random_address_point"},{"start":24228,"name":"test::encrypt_decrypt_deterministic"},{"start":26706,"name":"test::encrypt_decrypt_random"},{"start":27552,"name":"test::encrypt_to_invalid_address"},{"start":28002,"name":"test::pkcs7_padding_always_adds_at_least_one_byte"},{"start":28566,"name":"test::encrypt_decrypt_max_size_plaintext"},{"start":29465,"name":"test::encrypt_oversized_plaintext"},{"start":29823,"name":"test::random_address_point_produces_valid_points"},{"start":30274,"name":"test::decrypt_invalid_ephemeral_public_key"},{"start":31119,"name":"test::decrypt_returns_none_on_empty_ciphertext"},{"start":31673,"name":"test::decrypt_returns_none_on_empty_header"},{"start":32599,"name":"test::decrypt_returns_none_on_oversized_ciphertext_length"}]},"138":{"source":"use crate::{\n event::{event_interface::EventInterface, EventSelector},\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n utils::array,\n};\nuse crate::protocol::traits::{FromField, Serialize, ToField};\n\n/// The number of fields in a private event message content that are not the event's serialized representation (1 field\n/// for randomness).\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 1;\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 0;\n\n/// The maximum length of the packed representation of an event's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, randomness, etc.).\npub global MAX_EVENT_SERIALIZED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_event_message`].\npub fn encode_private_event_message(\n event: Event,\n randomness: Field,\n) -> [Field; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Event: EventInterface + Serialize,\n{\n std::static_assert(\n ::N <= MAX_EVENT_SERIALIZED_LEN,\n \"event's serialized length exceeds the maximum allowed for private events\",\n );\n\n // We use `Serialize` because we want for events to be processable by off-chain actors, e.g. block explorers,\n // wallets and apps, without having to rely on contract invocation. If we used `Packable` we'd need to call utility\n // functions in order to unpack events, which would introduce a level of complexity we don't currently think is\n // worth the savings in DA (for public events) and proving time (when encrypting private event messages).\n let serialized_event = event.serialize();\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_plaintext = [0; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n\n for i in 0..serialized_event.len() {\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = serialized_event[i];\n }\n\n // The event type id is stored in the message metadata\n encode_message(\n PRIVATE_EVENT_MSG_TYPE_ID,\n Event::get_event_type_id().to_field() as u64,\n msg_plaintext,\n )\n}\n\n/// Decodes the plaintext from a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_event_message`].\n///\n/// Note that while [`encode_private_event_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_event_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(EventSelector, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let event_type_id = EventSelector::from_field(msg_metadata as Field);\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // destructuring of the private event message encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let randomness = msg_content.get(PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let serialized_event = array::subbvec(msg_content, PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((event_type_id, randomness, serialized_event))\n }\n}\n\nmod test {\n use crate::{\n event::event_interface::EventInterface,\n messages::{\n encoding::decode_message,\n logs::event::{decode_private_event_message, encode_private_event_message},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n };\n use crate::protocol::traits::Serialize;\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let event = MockEvent::new(VALUE).build_event();\n\n let message_plaintext = encode_private_event_message(event, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_EVENT_MSG_TYPE_ID);\n\n let (event_type_id, randomness, serialized_event) =\n decode_private_event_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(event_type_id, MockEvent::get_event_type_id());\n assert_eq(randomness, RANDOMNESS);\n assert_eq(serialized_event, BoundedVec::from_array(event.serialize()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_event_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0]);\n assert(decode_private_event_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/event.nr","function_locations":[{"start":1377,"name":"encode_private_event_message"},{"start":3755,"name":"decode_private_event_message"},{"start":5127,"name":"test::encode_decode"},{"start":5869,"name":"test::decode_empty_content_returns_none"},{"start":6064,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"140":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\n\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX: u32 = 1;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 2;\n\n/// The maximum length of the packed representation of a note's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, storage slot, randomness, etc.).\npub global MAX_NOTE_PACKED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_note_message`].\npub fn encode_private_note_message(\n note: Note,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n) -> [Field; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Note: NoteType + Packable,\n{\n let packed_note = note.pack();\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_content = [0; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX] = storage_slot;\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n for i in 0..packed_note.len() {\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_note[i];\n }\n\n // Notes use the note type id for metadata\n encode_message(PRIVATE_NOTE_MSG_TYPE_ID, Note::get_id() as u64, msg_content)\n}\n\n/// Decodes the plaintext from a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_note_message`].\n///\n/// Note that while [`encode_private_note_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_note_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(Field, AztecAddress, Field, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // decoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let owner = AztecAddress::from_field(msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX));\n let storage_slot = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX);\n let randomness = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let packed_note = array::subbvec(msg_content, PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((note_type_id, owner, storage_slot, randomness, packed_note))\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::note::{decode_private_note_message, encode_private_note_message, MAX_NOTE_PACKED_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global STORAGE_SLOT: Field = 9;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[derive(Packable)]\n struct MaxSizeNote {\n data: [Field; MAX_NOTE_PACKED_LEN],\n }\n\n impl NoteType for MaxSizeNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_note() {\n let mut data = [0; MAX_NOTE_PACKED_LEN];\n for i in 0..MAX_NOTE_PACKED_LEN {\n data[i] = i as Field;\n }\n let note = MaxSizeNote { data };\n\n let encoded = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n let (msg_type_id, msg_metadata, msg_content) = decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MaxSizeNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(data));\n }\n\n #[derive(Packable)]\n struct OversizedNote {\n data: [Field; MAX_NOTE_PACKED_LEN + 1],\n }\n\n impl NoteType for OversizedNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_note_fails() {\n let note = OversizedNote { data: [0; MAX_NOTE_PACKED_LEN + 1] };\n let _ = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_note_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0, 0, 0]);\n assert(decode_private_note_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/note.nr","function_locations":[{"start":1518,"name":"encode_private_note_message"},{"start":3312,"name":"decode_private_note_message"},{"start":5000,"name":"test::encode_decode"},{"start":5923,"name":"test::::get_id"},{"start":6019,"name":"test::encode_decode_max_size_note"},{"start":7035,"name":"test::::get_id"},{"start":7221,"name":"test::encode_oversized_note_fails"},{"start":7456,"name":"test::decode_empty_content_returns_none"},{"start":7650,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"141":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 1;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX: u32 = 2;\n\n/// Partial notes have a maximum packed length of their private fields bound by extra content in their private message\n/// (e.g. the storage slot, note completion log tag, etc.).\npub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 =\n MAX_MESSAGE_CONTENT_LEN - PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a partial note private message (i.e. one of type [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_partial_note_private_message`].\npub fn encode_partial_note_private_message(\n partial_note_private_content: PartialNotePrivateContent,\n owner: AztecAddress,\n randomness: Field,\n note_completion_log_tag: Field,\n ) -> [Field; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n PartialNotePrivateContent: NoteType + Packable,\n{\n let packed_private_content = partial_note_private_content.pack();\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail, then\n // the encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n let mut msg_content =\n [0; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX] = note_completion_log_tag;\n\n for i in 0..packed_private_content.len() {\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_private_content[i];\n }\n\n encode_message(\n PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n // Notes use the note type id for metadata\n PartialNotePrivateContent::get_id() as u64,\n msg_content,\n )\n}\n\n/// Decodes the plaintext from a partial note private message (i.e. one of type\n/// [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_partial_note_private_message`].\n///\n/// Note that while [`encode_partial_note_private_message`] returns a fixed-size array, this function takes a\n/// [`BoundedVec`] instead. This is because when decoding we're typically processing runtime-sized plaintexts, more\n/// specifically, those that originate from\n/// [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_partial_note_private_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(AztecAddress, Field, Field, Field, BoundedVec)> {\n if msg_content.len() < PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id: Field = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail,\n // then the destructuring of the partial note private message encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n // We currently have three fields that are not the partial note's packed representation, which are the owner,\n // the randomness, and the note completion log tag.\n let owner = AztecAddress::from_field(\n msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX),\n );\n let randomness = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let note_completion_log_tag = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX);\n\n let packed_private_note_content: BoundedVec = array::subbvec(\n msg_content,\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN,\n );\n\n Option::some(\n (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content),\n )\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::partial_note::{decode_partial_note_private_message, encode_partial_note_private_message},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global RANDOMNESS: Field = 10;\n global NOTE_COMPLETION_LOG_TAG: Field = 11;\n\n #[test]\n unconstrained fn encode_decode() {\n // Note that here we use MockNote as the private fields of a partial note\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_partial_note_private_message(note, OWNER, RANDOMNESS, NOTE_COMPLETION_LOG_TAG);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID);\n\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_note) =\n decode_partial_note_private_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(note_completion_log_tag, NOTE_COMPLETION_LOG_TAG);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_partial_note_private_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_succeeds_with_only_reserved_fields() {\n let content = BoundedVec::from_array([0, 0, 0]);\n let (_, _, _, _, packed_note) = decode_partial_note_private_message(0, content).unwrap();\n assert_eq(packed_note.len(), 0);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/partial_note.nr","function_locations":[{"start":1715,"name":"encode_partial_note_private_message"},{"start":3810,"name":"decode_partial_note_private_message"},{"start":6022,"name":"test::encode_decode"},{"start":6999,"name":"test::decode_empty_content_returns_none"},{"start":7197,"name":"test::decode_succeeds_with_only_reserved_fields"}]},"151":{"source":"pub(crate) mod event_validation_request;\npub mod offchain;\n\nmod message_context;\npub use message_context::MessageContext;\n\npub(crate) mod note_validation_request;\npub(crate) mod log_retrieval_request;\npub(crate) mod log_retrieval_response;\npub(crate) mod pending_tagged_log;\n\nuse crate::{\n capsules::CapsuleArray,\n ephemeral::EphemeralArray,\n event::EventSelector,\n messages::{\n discovery::partial_notes::DeliveredPendingPartialNote,\n encoding::MESSAGE_CIPHERTEXT_LEN,\n logs::{event::MAX_EVENT_SERIALIZED_LEN, note::MAX_NOTE_PACKED_LEN},\n processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse,\n note_validation_request::NoteValidationRequest,\n },\n },\n oracle::message_processing,\n};\nuse crate::protocol::{\n address::AztecAddress,\n constants::DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n hash::{compute_log_tag, sha256_to_field},\n traits::{Deserialize, Serialize},\n};\nuse event_validation_request::EventValidationRequest;\n\nglobal NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\n/// An offchain-delivered message with resolved context, ready for processing during sync.\n#[derive(Serialize, Deserialize)]\npub struct OffchainMessageWithContext {\n pub message_ciphertext: BoundedVec,\n pub message_context: MessageContext,\n}\n\n/// Enqueues a note for validation and storage by PXE.\n///\n/// Once validated, the note becomes retrievable via the `get_notes` oracle. The note will be scoped to\n/// `contract_address`, meaning other contracts will not be able to access it unless authorized.\n///\n/// In order for the note validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many note validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// The `packed_note` is what `getNotes` will later return. PXE indexes notes by `storage_slot`, so this value is\n/// typically used to filter notes that correspond to different state variables. `note_hash` and `nullifier` are the\n/// inner hashes, i.e. the raw hashes returned by `NoteHash::compute_note_hash` and `NoteHash::compute_nullifier`. PXE\n/// will verify that the siloed unique note hash was inserted into the tree at `tx_hash`, and will store the nullifier\n/// to later check for nullification.\n///\n/// `owner` is the address used in note hash and nullifier computation, often requiring knowledge of their nullifier\n/// secret key.\n///\n/// `scope` is the account to which the note message was delivered (i.e. the address the message was encrypted to).\n/// This determines which PXE account can see the note - other accounts will not be able to access it (e.g. other\n/// accounts will not be able to see one another's token balance notes, even in the same PXE) unless authorized. In\n/// most cases `recipient` equals `owner`, but they can differ in scenarios like delegated discovery.\npub unconstrained fn enqueue_note_for_validation(\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_nonce: Field,\n packed_note: BoundedVec,\n note_hash: Field,\n nullifier: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n NoteValidationRequest {\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_nonce,\n packed_note,\n note_hash,\n nullifier,\n tx_hash,\n },\n )\n}\n\n/// Enqueues an event for validation and storage by PXE.\n///\n/// This is the primary way for custom message handlers (registered via\n/// [`crate::macros::AztecConfig::custom_message_handler`]) to deliver reassembled events back to PXE after processing\n/// application-specific message formats.\n///\n/// In order for the event validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many event validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// Note that `validate_and_store_enqueued_notes_and_events` is called by Aztec.nr after processing messages, so custom\n/// message processors do not need to be concerned with this.\npub unconstrained fn enqueue_event_for_validation(\n contract_address: AztecAddress,\n event_type_id: EventSelector,\n randomness: Field,\n serialized_event: BoundedVec,\n event_commitment: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n EventValidationRequest {\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n },\n )\n}\n\n/// Validates and stores all enqueued notes and events.\n///\n/// Processes all requests enqueued via [`enqueue_note_for_validation`] and [`enqueue_event_for_validation`], inserting\n/// them into the note database and event store respectively, making them queryable via `get_notes` oracle and our TS\n/// API (PXE::getPrivateEvents).\npub unconstrained fn validate_and_store_enqueued_notes_and_events(scope: AztecAddress) {\n message_processing::validate_and_store_enqueued_notes_and_events(\n NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n MAX_NOTE_PACKED_LEN as Field,\n MAX_EVENT_SERIALIZED_LEN as Field,\n scope,\n );\n\n // Defensive clearing: purge the queues after processing to prevent double-processing if this function is called\n // more than once in the same call frame. It is currently defensive because we only call this once per sync run.\n let _ = EphemeralArray::::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n let _ = EphemeralArray::::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n}\n\n/// Efficiently queries the node for logs that result in the completion of all `DeliveredPendingPartialNote`s stored in\n/// a `CapsuleArray` by performing all node communication concurrently. Returns an `EphemeralArray` with Options\n/// for the responses that correspond to the pending partial notes at the same index.\n///\n/// For example, given an array with pending partial notes `[ p1, p2, p3 ]`, where `p1` and `p3` have corresponding\n/// completion logs but `p2` does not, the returned `EphemeralArray` will have contents `[some(p1_log), none(),\n/// some(p3_log)]`.\npub(crate) unconstrained fn get_pending_partial_notes_completion_logs(\n contract_address: AztecAddress,\n pending_partial_notes: CapsuleArray,\n) -> EphemeralArray> {\n let log_retrieval_requests = EphemeralArray::at(LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT);\n\n // We create a LogRetrievalRequest for each PendingPartialNote in the EphemeralArray. Because we need the indices in\n // the request array to match the indices in the partial note array, we can't use EphemeralArray::for_each, as that\n // function has arbitrary iteration order. Instead, we manually iterate the array from the beginning and push into\n // the requests array, which we expect to be empty.\n let mut i = 0;\n let pending_partial_notes_count = pending_partial_notes.len();\n while i < pending_partial_notes_count {\n let pending_partial_note = pending_partial_notes.get(i);\n // Partial note completion logs are emitted with a domain-separated tag. To find matching logs, we apply the\n // same domain separation to the stored raw tag.\n let log_tag = compute_log_tag(\n pending_partial_note.note_completion_log_tag,\n DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n );\n log_retrieval_requests.push(LogRetrievalRequest { contract_address, unsiloed_tag: log_tag });\n i += 1;\n }\n\n let responses = message_processing::get_logs_by_tag(log_retrieval_requests);\n\n // Defensive clearing: prevent stale requests if this function is called more than once in the same call frame.\n let _ = log_retrieval_requests.clear();\n\n responses\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/mod.nr","function_locations":[{"start":3763,"name":"enqueue_note_for_validation"},{"start":5177,"name":"enqueue_event_for_validation"},{"start":5884,"name":"validate_and_store_enqueued_notes_and_events"},{"start":7412,"name":"get_pending_partial_notes_completion_logs"}]},"153":{"source":"use crate::{\n capsules::CapsuleArray,\n context::UtilityContext,\n ephemeral::EphemeralArray,\n messages::{encoding::MESSAGE_CIPHERTEXT_LEN, processing::OffchainMessageWithContext},\n oracle::contract_sync::set_contract_sync_cache_invalid,\n protocol::{\n address::AztecAddress,\n constants::MAX_TX_LIFETIME,\n hash::sha256_to_field,\n traits::{Deserialize, Serialize},\n },\n};\n\n/// Base capsule slot for the persistent inbox of [`PendingOffchainMsg`] entries.\n///\n/// This is the slot where we accumulate messages received through [`receive`].\nglobal OFFCHAIN_INBOX_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_INBOX_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to pass tx hash resolution requests to PXE.\nglobal OFFCHAIN_CONTEXT_REQUESTS_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_CONTEXT_REQUESTS_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to collect messages ready for processing.\nglobal OFFCHAIN_READY_MESSAGES_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_READY_MESSAGES_SLOT\".as_bytes());\n\n/// Maximum number of offchain messages accepted by `offchain_receive` in a single call.\npub global MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL: u32 = 16;\n\n/// Tolerance added to the `MAX_TX_LIFETIME` cap for message expiration.\nglobal TX_EXPIRATION_TOLERANCE: u64 = 7200; // 2 hours\n\n/// Maximum time-to-live for a tx-bound offchain message.\n///\n/// After `anchor_block_timestamp + MAX_MSG_TTL`, the message is evicted from the inbox.\nglobal MAX_MSG_TTL: u64 = MAX_TX_LIFETIME + TX_EXPIRATION_TOLERANCE;\n\n/// A function that manages offchain-delivered messages for processing during sync.\n///\n/// Offchain messages are messages that are not broadcasted via onchain logs. They are instead delivered to the\n/// recipient by calling the `offchain_receive` utility function (injected by the `#[aztec]` macro). Message transport\n/// is the app's responsibility. Typical examples of transport methods are: messaging apps, email, QR codes, etc.\n///\n/// Once offchain messages are delivered to the recipient's private environment via `offchain_receive`, messages are\n/// locally stored in a persistent inbox.\n///\n/// This function determines when each message in said inbox is ready for processing, when it can be safely disposed\n/// of, etc.\n///\n/// The only current implementation of an `OffchainInboxSync` is [`sync_inbox`], which manages an inbox with expiration\n/// based eviction and automatic transaction context resolution.\npub(crate) type OffchainInboxSync = unconstrained fn[Env](\n/* contract_address */AztecAddress, /* scope */ AztecAddress) -> EphemeralArray;\n\n/// A message delivered via the `offchain_receive` utility function.\npub struct OffchainMessage {\n /// The encrypted message payload.\n pub ciphertext: BoundedVec,\n /// The intended recipient of the message.\n pub recipient: AztecAddress,\n /// The hash of the transaction that produced this message. `Option::none` indicates a tx-less message.\n pub tx_hash: Option,\n /// Anchor block timestamp at message emission.\n pub anchor_block_timestamp: u64,\n}\n\n/// An offchain message awaiting processing (or re-processing) in the inbox.\n///\n/// Messages remain in the inbox until they expire, even if they have already been processed. This is necessary to\n/// handle reorgs: a processed message may need to be re-processed if the transaction that provided its context is\n/// reverted. On each sync, resolved messages are promoted to [`OffchainMessageWithContext`] for processing.\n#[derive(Serialize, Deserialize)]\nstruct PendingOffchainMsg {\n /// The encrypted message payload.\n ciphertext: BoundedVec,\n /// The intended recipient of the message.\n recipient: AztecAddress,\n /// The hash of the transaction that produced this message. A value of 0 indicates a tx-less message.\n tx_hash: Field,\n /// Anchor block timestamp at message emission. Used to compute the effective expiration: messages are evicted\n /// after `anchor_block_timestamp + MAX_MSG_TTL`.\n anchor_block_timestamp: u64,\n}\n\n/// Delivers offchain messages to the given contract's offchain inbox for subsequent processing.\n///\n/// Offchain messages are transaction effects that are not broadcasted via onchain logs. Instead, the sender shares the\n/// message to the recipient through an external channel (e.g. a URL accessible by the recipient). The recipient then\n/// calls this function to hand the messages to the contract so they can be processed through the same mechanisms as\n/// onchain messages.\n///\n/// Each message is routed to the inbox scoped to its `recipient` field, so messages for different accounts are\n/// automatically isolated.\n///\n/// Messages are processed when their originating transaction is found onchain (providing the context needed to\n/// validate resulting notes and events).\n///\n/// Messages are kept in the inbox until they expire. The effective expiration is\n/// `anchor_block_timestamp + MAX_MSG_TTL`.\n///\n/// Processing order is not guaranteed.\npub unconstrained fn receive(\n contract_address: AztecAddress,\n messages: BoundedVec,\n) {\n // May contain duplicates if multiple messages target the same recipient. This is harmless since\n // cache invalidation on the TS side is idempotent (deleting an already-deleted key is a no-op).\n let mut scopes: BoundedVec = BoundedVec::new();\n let mut i = 0;\n let messages_len = messages.len();\n while i < messages_len {\n let msg = messages.get(i);\n let tx_hash = if msg.tx_hash.is_some() {\n msg.tx_hash.unwrap()\n } else {\n 0\n };\n let inbox: CapsuleArray =\n CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, msg.recipient);\n inbox.push(\n PendingOffchainMsg {\n ciphertext: msg.ciphertext,\n recipient: msg.recipient,\n tx_hash,\n anchor_block_timestamp: msg.anchor_block_timestamp,\n },\n );\n scopes.push(msg.recipient);\n i += 1;\n }\n\n set_contract_sync_cache_invalid(contract_address, scopes);\n}\n\n/// Returns offchain-delivered messages to process during sync.\n///\n/// Messages remain in the inbox and are reprocessed on each sync until their originating transaction is no longer at\n/// risk of being dropped by a reorg.\npub unconstrained fn sync_inbox(\n contract_address: AztecAddress,\n scope: AztecAddress,\n) -> EphemeralArray {\n let inbox: CapsuleArray = CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, scope);\n let context_resolution_requests: EphemeralArray = EphemeralArray::at(OFFCHAIN_CONTEXT_REQUESTS_SLOT).clear();\n let ready_to_process: EphemeralArray =\n EphemeralArray::at(OFFCHAIN_READY_MESSAGES_SLOT).clear();\n\n // Build a request list aligned with the inbox indices.\n let mut i = 0;\n let inbox_len = inbox.len();\n while i < inbox_len {\n let msg = inbox.get(i);\n context_resolution_requests.push(msg.tx_hash);\n i += 1;\n }\n\n // Ask PXE to resolve contexts for all requested tx hashes. The oracle returns responses in a new\n // ephemeral array.\n let resolved_contexts =\n crate::oracle::message_processing::get_message_contexts_by_tx_hash(context_resolution_requests);\n\n assert_eq(resolved_contexts.len(), inbox_len);\n\n let now = UtilityContext::new().timestamp();\n\n let mut j = inbox_len;\n while j > 0 {\n // This loop decides what to do with each message in the offchain message inbox. We need to handle 3\n // different scenarios for each message.\n //\n // 1. The TX that emitted this message is still not known to PXE: in this case we can't yet process this\n // message, as any notes or events discovered will fail to be validated. So we leave the message in the inbox,\n // awaiting for future syncs to detect that the TX became available.\n //\n // 2. The message is not associated to a TX to begin with. The current version of offchain message processing\n // does not support this case, but in the future it will. Right now, a message without an associated TX will\n // sit in the inbox until it expires.\n //\n // 3. The TX that emitted this message has been found by PXE. That gives us all the information needed to\n // process the message. We add the message to the `ready_to_process` EphemeralArray so that the `sync_state`\n // loop\n // processes it.\n //\n // In all cases, if the message has expired (i.e. `now > anchor_block_timestamp + MAX_MSG_TTL`), we remove it\n // from the inbox.\n //\n // Note: the loop runs backwards because it might call `inbox.remove(j)` to purge expired messages and we also\n // need to align it with `resolved_contexts.get(j)`. Going from last to first simplifies the algorithm as\n // not yet visited element indexes remain stable.\n j -= 1;\n let maybe_ctx = resolved_contexts.get(j);\n let msg = inbox.get(j);\n\n // Compute the message's effective expiration timestamp to determine if we can purge it from the inbox.\n let effective_expiration = msg.anchor_block_timestamp + MAX_MSG_TTL;\n\n // Message expired. We remove it from the inbox.\n if now > effective_expiration {\n inbox.remove(j);\n }\n\n // Scenario 1: associated TX not yet available. We keep the message in the inbox, as it might become\n // processable as new blocks get mined.\n // Scenario 2: no TX associated to message. The message will sit in the inbox until it expires.\n if maybe_ctx.is_none() {\n continue;\n }\n\n // Scenario 3: Message is ready to process, add to result array. Note we still keep it in the inbox unless we\n // consider it has expired: this is because we need to account for reorgs. If reorg occurs after we processed\n // a message, the effects of processing the message get rewind. However, the associated TX can be included in\n // a subsequent block. Should that happen, the message must be re-processed to ensure consistency.\n let message_context = maybe_ctx.unwrap();\n ready_to_process.push(OffchainMessageWithContext { message_ciphertext: msg.ciphertext, message_context });\n }\n\n ready_to_process\n}\n\nmod test {\n use crate::{\n capsules::CapsuleArray, oracle::random::random, protocol::address::AztecAddress,\n test::helpers::test_environment::TestEnvironment,\n };\n use super::{\n MAX_MSG_TTL, MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL, OFFCHAIN_INBOX_SLOT, OffchainMessage, PendingOffchainMsg,\n receive, sync_inbox,\n };\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n /// Creates an `OffchainMessage` with dummy ciphertext and the given scope as recipient.\n fn make_msg(recipient: AztecAddress, tx_hash: Option, anchor_block_timestamp: u64) -> OffchainMessage {\n OffchainMessage { ciphertext: BoundedVec::new(), recipient, tx_hash, anchor_block_timestamp }\n }\n\n /// Advances the TXE block timestamp by `offset` seconds and returns the resulting timestamp.\n unconstrained fn advance_by(env: TestEnvironment, offset: u64) -> u64 {\n env.advance_next_block_timestamp_by(offset);\n env.mine_block();\n env.last_block_timestamp()\n }\n\n #[test]\n unconstrained fn empty_inbox_returns_empty_result() {\n let (env, scope) = setup();\n env.utility_context(|context| {\n let result = sync_inbox(context.this_address(), scope);\n let inbox: CapsuleArray =\n CapsuleArray::at(context.this_address(), OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0);\n assert_eq(inbox.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_not_expired_before_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance, but not past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn tx_less_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::none(), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn unresolved_tx_stays_in_inbox() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // not resolved, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn multiple_messages_mixed_expiration() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n let survivor_tx_hash = random();\n\n env.utility_context(|context| {\n let address = context.this_address();\n let mut msgs: BoundedVec = BoundedVec::new();\n // Message 0: tx-bound, anchor_ts in the past so it expires at\n // anchor_ts + MAX_MSG_TTL. We set anchor to 0 so it expires quickly.\n msgs.push(make_msg(scope, Option::some(random()), 0));\n // Message 1: tx-bound, anchor_ts is recent so it survives.\n msgs.push(make_msg(scope, Option::some(survivor_tx_hash), anchor_ts));\n // Message 2: tx-less, anchor_ts=0 so it also expires.\n msgs.push(make_msg(scope, Option::none(), 0));\n receive(address, msgs);\n });\n\n // Advance past MAX_MSG_TTL for anchor_ts=0, but not for anchor_ts=anchor_ts.\n let _now = advance_by(env, MAX_MSG_TTL);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // all contexts are None\n // Message 0 expired (anchor=0), message 1 survived (anchor=anchor_ts),\n // Message 2 expired (anchor=0).\n assert_eq(inbox.len(), 1);\n assert_eq(inbox.get(0).tx_hash, survivor_tx_hash);\n });\n }\n\n // -- Resolved context (ready to process) ------------------------------\n\n #[test]\n unconstrained fn resolved_msg_is_ready_to_process() {\n let (env, scope) = setup();\n // TestEnvironment::new() deploys protocol contracts, creating blocks with tx effects.\n // In TXE, tx hashes equal Fr(blockNumber), so Fr(1) is the tx effect from block 1.\n // We use this as a \"known resolvable\" tx hash.\n let known_tx_hash: Field = 1;\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(known_tx_hash), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n // The message should be ready to process since its tx context was resolved.\n assert_eq(result.len(), 1);\n\n let ctx = result.get(0).message_context;\n assert_eq(ctx.tx_hash, known_tx_hash);\n assert(ctx.first_nullifier_in_tx != 0, \"resolved context must have a first nullifier\");\n\n // Message stays in inbox (not expired) for potential reorg reprocessing.\n assert_eq(inbox.len(), 1);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/offchain.nr","function_locations":[{"start":5298,"name":"receive"},{"start":6741,"name":"sync_inbox"},{"start":11111,"name":"test::setup"},{"start":11441,"name":"test::make_msg"},{"start":11724,"name":"test::advance_by"},{"start":11915,"name":"test::empty_inbox_returns_empty_result"},{"start":12378,"name":"test::tx_bound_msg_expires_after_max_msg_ttl"},{"start":13343,"name":"test::tx_bound_msg_not_expired_before_max_msg_ttl"},{"start":14301,"name":"test::tx_less_msg_expires_after_max_msg_ttl"},{"start":15243,"name":"test::unresolved_tx_stays_in_inbox"},{"start":16137,"name":"test::multiple_messages_mixed_expiration"},{"start":17876,"name":"test::resolved_msg_is_ready_to_process"}]},"171":{"source":"#[oracle(aztec_utl_decryptAes128)]\nunconstrained fn aes128_decrypt_oracle(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {}\n\n/// Attempts to decrypt a ciphertext using AES128.\n///\n/// Returns `Option::some(plaintext)` on success, or `Option::none()` if decryption fails (e.g. due to malformed\n/// ciphertext or invalid PKCS#7 padding). Note that decryption with the wrong key will almost always return `None`\n/// because the decrypted garbage data will have invalid PKCS#7 padding.\n///\n/// Note that we accept ciphertext as a BoundedVec, not as an array. This is because this function is typically used\n/// when processing logs and at that point we don't have comptime information about the length of the ciphertext as\n/// the log is not specific to any individual note.\n// TODO(F-498): review naming consistency\npub unconstrained fn try_aes128_decrypt(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {\n aes128_decrypt_oracle(ciphertext, iv, sym_key)\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::compute_app_siloed_shared_secret,\n messages::encryption::aes128::derive_aes_symmetric_key_and_iv_from_shared_secret,\n utils::{array::subarray::subarray, point::point_from_x_coord},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::try_aes128_decrypt;\n use std::aes128::aes128_encrypt;\n\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress { inner: 42 };\n global TEST_PLAINTEXT_LENGTH: u32 = 10;\n global TEST_CIPHERTEXT_LENGTH: u32 = 16;\n global TEST_PADDING_LENGTH: u32 = TEST_CIPHERTEXT_LENGTH - TEST_PLAINTEXT_LENGTH;\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n\n let received_plaintext = try_aes128_decrypt(ciphertext_bvec, iv, sym_key).unwrap();\n assert_eq(received_plaintext.len(), TEST_PLAINTEXT_LENGTH);\n assert_eq(received_plaintext.max_len(), TEST_CIPHERTEXT_LENGTH);\n assert_eq(subarray::<_, _, TEST_PLAINTEXT_LENGTH>(received_plaintext.storage(), 0), plaintext);\n assert_eq(\n subarray::<_, _, TEST_PADDING_LENGTH>(received_plaintext.storage(), TEST_PLAINTEXT_LENGTH),\n [0 as u8; TEST_PADDING_LENGTH],\n );\n })\n }\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt_with_bad_sym_key_is_caught() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n // Decrypting with the wrong key results in garbage data with invalid PKCS#7 padding,\n // so the oracle returns None.\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let mut bad_sym_key = sym_key;\n bad_sym_key[0] = 0;\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n // Decryption with wrong key returns None because the garbage output has invalid PKCS#7 padding.\n let result = try_aes128_decrypt(ciphertext_bvec, iv, bad_sym_key);\n assert(result.is_none(), \"decryption with bad key should return None\");\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/aes128_decrypt.nr","function_locations":[{"start":194,"name":"aes128_decrypt_oracle"},{"start":1046,"name":"try_aes128_decrypt"},{"start":1860,"name":"test::aes_encrypt_then_decrypt"},{"start":3150,"name":"test::aes_encrypt_then_decrypt_with_bad_sym_key_is_caught"}]},"173":{"source":"//! AVM oracles.\n//!\n//! There are only available during public execution. Calling any of them from a private or utility function will\n//! result in runtime errors.\n\nuse crate::protocol::address::{AztecAddress, EthAddress};\n\npub unconstrained fn address() -> AztecAddress {\n address_opcode()\n}\npub unconstrained fn sender() -> AztecAddress {\n sender_opcode()\n}\npub unconstrained fn transaction_fee() -> Field {\n transaction_fee_opcode()\n}\npub unconstrained fn chain_id() -> Field {\n chain_id_opcode()\n}\npub unconstrained fn version() -> Field {\n version_opcode()\n}\npub unconstrained fn block_number() -> u32 {\n block_number_opcode()\n}\npub unconstrained fn timestamp() -> u64 {\n timestamp_opcode()\n}\npub unconstrained fn min_fee_per_l2_gas() -> u128 {\n min_fee_per_l2_gas_opcode()\n}\npub unconstrained fn min_fee_per_da_gas() -> u128 {\n min_fee_per_da_gas_opcode()\n}\npub unconstrained fn l2_gas_left() -> u32 {\n l2_gas_left_opcode()\n}\npub unconstrained fn da_gas_left() -> u32 {\n da_gas_left_opcode()\n}\npub unconstrained fn is_static_call() -> bool {\n is_static_call_opcode()\n}\npub unconstrained fn note_hash_exists(note_hash: Field, leaf_index: u64) -> bool {\n note_hash_exists_opcode(note_hash, leaf_index)\n}\npub unconstrained fn emit_note_hash(note_hash: Field) {\n emit_note_hash_opcode(note_hash)\n}\npub unconstrained fn nullifier_exists(siloed_nullifier: Field) -> bool {\n nullifier_exists_opcode(siloed_nullifier)\n}\npub unconstrained fn emit_nullifier(nullifier: Field) {\n emit_nullifier_opcode(nullifier)\n}\npub unconstrained fn emit_public_log(message: [Field]) {\n emit_public_log_opcode(message)\n}\npub unconstrained fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: u64) -> bool {\n l1_to_l2_msg_exists_opcode(msg_hash, msg_leaf_index)\n}\npub unconstrained fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {\n send_l2_to_l1_msg_opcode(recipient, content)\n}\n\npub unconstrained fn call(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn call_static(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_static_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn calldata_copy(cdoffset: u32, copy_size: u32) -> [Field; N] {\n calldata_copy_opcode(cdoffset, copy_size)\n}\n\n/// `success_copy` is placed immediately after the CALL opcode to get the success value\npub unconstrained fn success_copy() -> bool {\n success_copy_opcode()\n}\n\npub unconstrained fn returndata_size() -> u32 {\n returndata_size_opcode()\n}\n\npub unconstrained fn returndata_copy(rdoffset: u32, copy_size: u32) -> [Field] {\n returndata_copy_opcode(rdoffset, copy_size)\n}\n\n/// The additional prefix is to avoid clashing with the `return` Noir keyword.\npub unconstrained fn avm_return(returndata: [Field]) {\n return_opcode(returndata)\n}\n\n/// This opcode reverts using the exact data given. In general it should only be used to do rethrows, where the revert\n/// data is the same as the original revert data. For normal reverts, use Noir's `assert` which, on top of reverting,\n/// will also add an error selector to the revert data.\npub unconstrained fn revert(revertdata: [Field]) {\n revert_opcode(revertdata)\n}\n\npub unconstrained fn storage_read(storage_slot: Field, contract_address: Field) -> Field {\n storage_read_opcode(storage_slot, contract_address)\n}\n\npub unconstrained fn storage_write(storage_slot: Field, value: Field) {\n storage_write_opcode(storage_slot, value);\n}\n\n#[oracle(aztec_avm_address)]\nunconstrained fn address_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_sender)]\nunconstrained fn sender_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_transactionFee)]\nunconstrained fn transaction_fee_opcode() -> Field {}\n\n#[oracle(aztec_avm_chainId)]\nunconstrained fn chain_id_opcode() -> Field {}\n\n#[oracle(aztec_avm_version)]\nunconstrained fn version_opcode() -> Field {}\n\n#[oracle(aztec_avm_blockNumber)]\nunconstrained fn block_number_opcode() -> u32 {}\n\n#[oracle(aztec_avm_timestamp)]\nunconstrained fn timestamp_opcode() -> u64 {}\n\n#[oracle(aztec_avm_minFeePerL2Gas)]\nunconstrained fn min_fee_per_l2_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_minFeePerDaGas)]\nunconstrained fn min_fee_per_da_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_l2GasLeft)]\nunconstrained fn l2_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_daGasLeft)]\nunconstrained fn da_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_isStaticCall)]\nunconstrained fn is_static_call_opcode() -> bool {}\n\n#[oracle(aztec_avm_noteHashExists)]\nunconstrained fn note_hash_exists_opcode(note_hash: Field, leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_emitNoteHash)]\nunconstrained fn emit_note_hash_opcode(note_hash: Field) {}\n\n#[oracle(aztec_avm_nullifierExists)]\nunconstrained fn nullifier_exists_opcode(siloed_nullifier: Field) -> bool {}\n\n#[oracle(aztec_avm_emitNullifier)]\nunconstrained fn emit_nullifier_opcode(nullifier: Field) {}\n\n#[oracle(aztec_avm_emitPublicLog)]\nunconstrained fn emit_public_log_opcode(message: [Field]) {}\n\n#[oracle(aztec_avm_l1ToL2MsgExists)]\nunconstrained fn l1_to_l2_msg_exists_opcode(msg_hash: Field, msg_leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_sendL2ToL1Msg)]\nunconstrained fn send_l2_to_l1_msg_opcode(recipient: EthAddress, content: Field) {}\n\n#[oracle(aztec_avm_calldataCopy)]\nunconstrained fn calldata_copy_opcode(cdoffset: u32, copy_size: u32) -> [Field; N] {}\n\n#[oracle(aztec_avm_returndataSize)]\nunconstrained fn returndata_size_opcode() -> u32 {}\n\n#[oracle(aztec_avm_returndataCopy)]\nunconstrained fn returndata_copy_opcode(rdoffset: u32, copy_size: u32) -> [Field] {}\n\n#[oracle(aztec_avm_return)]\nunconstrained fn return_opcode(returndata: [Field]) {}\n\n#[oracle(aztec_avm_revert)]\nunconstrained fn revert_opcode(revertdata: [Field]) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_call)]\nunconstrained fn call_opcode(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_staticCall)]\nunconstrained fn call_static_opcode(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n#[oracle(aztec_avm_successCopy)]\nunconstrained fn success_copy_opcode() -> bool {}\n\n#[oracle(aztec_avm_storageRead)]\nunconstrained fn storage_read_opcode(storage_slot: Field, contract_address: Field) -> Field {}\n\n#[oracle(aztec_avm_storageWrite)]\nunconstrained fn storage_write_opcode(storage_slot: Field, value: Field) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/avm.nr","function_locations":[{"start":272,"name":"address"},{"start":343,"name":"sender"},{"start":415,"name":"transaction_fee"},{"start":489,"name":"chain_id"},{"start":555,"name":"version"},{"start":623,"name":"block_number"},{"start":693,"name":"timestamp"},{"start":770,"name":"min_fee_per_l2_gas"},{"start":856,"name":"min_fee_per_da_gas"},{"start":934,"name":"l2_gas_left"},{"start":1005,"name":"da_gas_left"},{"start":1080,"name":"is_static_call"},{"start":1193,"name":"note_hash_exists"},{"start":1302,"name":"emit_note_hash"},{"start":1414,"name":"nullifier_exists"},{"start":1518,"name":"emit_nullifier"},{"start":1614,"name":"emit_public_log"},{"start":1741,"name":"l1_to_l2_msg_exists"},{"start":1880,"name":"send_l2_to_l1_msg"},{"start":2080,"name":"call"},{"start":2310,"name":"call_static"},{"start":2486,"name":"calldata_copy"},{"start":2669,"name":"success_copy"},{"start":2746,"name":"returndata_size"},{"start":2859,"name":"returndata_copy"},{"start":3044,"name":"avm_return"},{"start":3421,"name":"revert"},{"start":3545,"name":"storage_read"},{"start":3676,"name":"storage_write"},{"start":3807,"name":"address_opcode"},{"start":3888,"name":"sender_opcode"},{"start":3979,"name":"transaction_fee_opcode"},{"start":4056,"name":"chain_id_opcode"},{"start":4132,"name":"version_opcode"},{"start":4215,"name":"block_number_opcode"},{"start":4293,"name":"timestamp_opcode"},{"start":4386,"name":"min_fee_per_l2_gas_opcode"},{"start":4479,"name":"min_fee_per_da_gas_opcode"},{"start":4559,"name":"l2_gas_left_opcode"},{"start":4639,"name":"da_gas_left_opcode"},{"start":4726,"name":"is_static_call_opcode"},{"start":4850,"name":"note_hash_exists_opcode"},{"start":4945,"name":"emit_note_hash_opcode"},{"start":5060,"name":"nullifier_exists_opcode"},{"start":5156,"name":"emit_nullifier_opcode"},{"start":5253,"name":"emit_public_log_opcode"},{"start":5384,"name":"l1_to_l2_msg_exists_opcode"},{"start":5504,"name":"send_l2_to_l1_msg_opcode"},{"start":5637,"name":"calldata_copy_opcode"},{"start":5726,"name":"returndata_size_opcode"},{"start":5848,"name":"returndata_copy_opcode"},{"start":5932,"name":"return_opcode"},{"start":6016,"name":"revert_opcode"},{"start":6463,"name":"call_opcode"},{"start":6923,"name":"call_static_opcode"},{"start":7007,"name":"success_copy_opcode"},{"start":7136,"name":"storage_read_opcode"},{"start":7247,"name":"storage_write_opcode"}]},"176":{"source":"use crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Stores arbitrary information in a per-contract non-volatile database, which can later be retrieved with `load`. If\n/// data was already stored at this slot, it is overwritten.\n// TODO(F-498): review naming consistency\npub unconstrained fn store(contract_address: AztecAddress, slot: Field, value: T, scope: AztecAddress)\nwhere\n T: Serialize,\n{\n let serialized = value.serialize();\n set_capsule_oracle(contract_address, slot, serialized, scope);\n}\n\n/// Returns data previously stored via `storeCapsule` in the per-contract non-volatile database. Returns\n/// Option::none() if nothing was stored at the given slot.\n// TODO(F-498): review naming consistency\npub unconstrained fn load(contract_address: AztecAddress, slot: Field, scope: AztecAddress) -> Option\nwhere\n T: Deserialize,\n{\n let serialized_option = get_capsule_oracle(contract_address, slot, ::N, scope);\n serialized_option.map(|arr| Deserialize::deserialize(arr))\n}\n\n/// Deletes data in the per-contract non-volatile database. Does nothing if no data was present.\npub unconstrained fn delete(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {\n delete_oracle(contract_address, slot, scope);\n}\n\n/// Copies a number of contiguous entries in the per-contract non-volatile database. This allows for efficient data\n/// structures by avoiding repeated calls to `loadCapsule` and `storeCapsule`. Supports overlapping source and\n/// destination regions (which will result in the overlapped source values being overwritten). All copied slots must\n/// exist in the database (i.e. have been stored and not deleted)\npub unconstrained fn copy(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {\n copy_oracle(contract_address, src_slot, dst_slot, num_entries, scope);\n}\n\n#[oracle(aztec_utl_setCapsule)]\nunconstrained fn set_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n values: [Field; N],\n scope: AztecAddress,\n) {}\n\n/// We need to pass in `array_len` (the value of N) as a parameter to tell the oracle how many fields the response must\n/// have.\n///\n/// Note that the oracle returns an Option<[Field; N]> because we cannot return an Option directly. That would\n/// require for the oracle resolver to know the shape of T (e.g. if T were a struct of 3 u32 values then the expected\n/// response shape would be 3 single items, whereas it were a struct containing `u32, [Field;10], u32` then the\n/// expected shape would be single, array, single.). Instead, we return the serialization and deserialize in Noir.\n#[oracle(aztec_utl_getCapsule)]\nunconstrained fn get_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n array_len: u32,\n scope: AztecAddress,\n) -> Option<[Field; N]> {}\n\n#[oracle(aztec_utl_deleteCapsule)]\nunconstrained fn delete_oracle(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {}\n\n#[oracle(aztec_utl_copyCapsule)]\nunconstrained fn copy_oracle(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {}\n\nmod test {\n // These tests are sort of redundant since we already test the oracle implementation directly in TypeScript, but\n // they are cheap regardless and help ensure both that the TXE implementation works accordingly and that the Noir\n // oracles are hooked up correctly.\n\n use crate::{\n oracle::capsules::{copy, delete, load, store},\n test::{helpers::test_environment::TestEnvironment, mocks::MockStruct},\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, ToField}};\n\n global SLOT: Field = 1;\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n #[test]\n unconstrained fn stores_and_loads() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), value);\n });\n }\n\n #[test]\n unconstrained fn store_overwrites() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n let new_value = MockStruct::new(7, 8);\n store(contract_address, SLOT, new_value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), new_value);\n });\n }\n\n #[test]\n unconstrained fn loads_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_stored_value() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n delete(contract_address, SLOT, scope);\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n delete(contract_address, SLOT, scope);\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn copies_non_overlapping_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 5;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 10;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_src_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 1;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 2;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[1] and src[2] should have been overwritten since they are also dst[0] and dst[1]\n assert_eq(load(contract_address, src, scope).unwrap(), values[0]); // src[0] (unchanged)\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[0]); // dst[0]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[1]); // dst[1]\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_dst_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 2;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 1;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[0] and src[1] should have been overwritten since they are also dst[1] and dst[2]\n assert_eq(load(contract_address, src, scope).unwrap(), values[1]); // dst[1]\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[2]); // dst[2]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[2]); // src[2] (unchanged)\n });\n }\n\n #[test(should_fail_with = \"copy empty slot\")]\n unconstrained fn cannot_copy_empty_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n copy(contract_address, SLOT, SLOT, 1, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_store_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let value = MockStruct::new(5, 6);\n store(other_contract_address, SLOT, value, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_load_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let _: Option = load(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_delete_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n delete(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_copy_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n copy(other_contract_address, SLOT, SLOT, 0, scope);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/capsules.nr","function_locations":[{"start":433,"name":"store"},{"start":886,"name":"load"},{"start":1247,"name":"delete"},{"start":1866,"name":"copy"},{"start":2131,"name":"set_capsule_oracle"},{"start":2931,"name":"get_capsule_oracle"},{"start":3067,"name":"delete_oracle"},{"start":3261,"name":"copy_oracle"},{"start":3884,"name":"test::setup"},{"start":4060,"name":"test::stores_and_loads"},{"start":4450,"name":"test::store_overwrites"},{"start":4957,"name":"test::loads_empty_slot"},{"start":5311,"name":"test::deletes_stored_value"},{"start":5819,"name":"test::deletes_empty_slot"},{"start":6233,"name":"test::copies_non_overlapping_values"},{"start":7106,"name":"test::copies_overlapping_values_with_src_ahead"},{"start":8366,"name":"test::copies_overlapping_values_with_dst_ahead"},{"start":9648,"name":"test::cannot_copy_empty_values"},{"start":9970,"name":"test::cannot_store_other_contract"},{"start":10443,"name":"test::cannot_load_other_contract"},{"start":10891,"name":"test::cannot_delete_other_contract"},{"start":11311,"name":"test::cannot_copy_other_contract"}]},"177":{"source":"use crate::protocol::address::AztecAddress;\n\n#[oracle(aztec_utl_setContractSyncCacheInvalid)]\nunconstrained fn set_contract_sync_cache_invalid_oracle(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {}\n\n/// Forces the PXE to re-sync the given contract for a set of scopes on the next query.\n///\n/// Call this after writing data (e.g. offchain messages) that the contract's `sync_state` function needs to discover.\n/// Without invalidation, the sync cache would skip re-running `sync_state` until the next block.\npub unconstrained fn set_contract_sync_cache_invalid(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {\n set_contract_sync_cache_invalid_oracle(contract_address, scopes);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/contract_sync.nr","function_locations":[{"start":242,"name":"set_contract_sync_cache_invalid_oracle"},{"start":700,"name":"set_contract_sync_cache_invalid"}]},"179":{"source":"use crate::context::UtilityContext;\n\n#[oracle(aztec_utl_getUtilityContext)]\nunconstrained fn get_utility_context_oracle() -> UtilityContext {}\n\n/// Returns a utility context built from the global variables of anchor block and the contract address of the function\n/// being executed.\npub unconstrained fn get_utility_context() -> UtilityContext {\n get_utility_context_oracle()\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/execution.nr","function_locations":[{"start":140,"name":"get_utility_context_oracle"},{"start":344,"name":"get_utility_context"}]},"189":{"source":"use crate::ephemeral::EphemeralArray;\nuse crate::messages::processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse, MessageContext,\n pending_tagged_log::PendingTaggedLog,\n};\nuse crate::protocol::address::AztecAddress;\n\n/// Finds new private logs that may have been sent to all registered accounts in PXE in the current contract and\n/// returns them in an ephemeral array with an oracle-allocated base slot.\npub(crate) unconstrained fn get_pending_tagged_logs(scope: AztecAddress) -> EphemeralArray {\n let result_slot = get_pending_tagged_logs_oracle(scope);\n EphemeralArray::at(result_slot)\n}\n\n#[oracle(aztec_utl_getPendingTaggedLogs_v2)]\nunconstrained fn get_pending_tagged_logs_oracle(scope: AztecAddress) -> Field {}\n\n/// Validates note/event requests stored in ephemeral arrays.\npub(crate) unconstrained fn validate_and_store_enqueued_notes_and_events(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {\n validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot,\n event_validation_requests_array_slot,\n max_note_packed_len,\n max_event_serialized_len,\n scope,\n );\n}\n\n#[oracle(aztec_utl_validateAndStoreEnqueuedNotesAndEvents_v2)]\nunconstrained fn validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {}\n\n/// Fetches logs by tag from an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_logs_by_tag(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_logs_by_tag_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getLogsByTag_v2)]\nunconstrained fn get_logs_by_tag_v2_oracle(request_array_slot: Field) -> Field {}\n\n/// Resolves message contexts for tx hashes in an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_message_contexts_by_tx_hash(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_message_contexts_by_tx_hash_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getMessageContextsByTxHash_v2)]\nunconstrained fn get_message_contexts_by_tx_hash_v2_oracle(request_array_slot: Field) -> Field {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/message_processing.nr","function_locations":[{"start":570,"name":"get_pending_tagged_logs"},{"start":795,"name":"get_pending_tagged_logs_oracle"},{"start":1128,"name":"validate_and_store_enqueued_notes_and_events"},{"start":1692,"name":"validate_and_store_enqueued_notes_and_events_oracle"},{"start":1938,"name":"get_logs_by_tag"},{"start":2163,"name":"get_logs_by_tag_v2_oracle"},{"start":2423,"name":"get_message_contexts_by_tx_hash"},{"start":2694,"name":"get_message_contexts_by_tx_hash_v2_oracle"}]},"196":{"source":"use crate::protocol::address::aztec_address::AztecAddress;\nuse crate::protocol::point::Point;\n\n#[oracle(aztec_utl_getSharedSecret)]\nunconstrained fn get_shared_secret_oracle(\n address: AztecAddress,\n ephPk: Point,\n contract_address: AztecAddress,\n) -> Field {}\n\n/// Returns an app-siloed shared secret between `address` and someone who knows the secret key behind an ephemeral\n/// public key `ephPk`.\n///\n/// The returned value is a Field `s_app`, computed as:\n///\n/// ```text\n/// S = address_secret * ephPk (raw ECDH point)\n/// s_app = h(DOM_SEP, S.x, S.y, contract) (app-siloed scalar)\n/// ```\n///\n/// where `contract` is the address of the calling contract. The oracle host validates this matches its execution\n/// context.\n///\n/// Without app-siloing, a malicious contract could call this oracle with public information (address, ephPk) and\n/// obtain the same raw secret as the legitimate contract, enabling cross-contract decryption. By including the\n/// contract address in the hash, each contract receives a different `s_app`, preventing this attack.\n///\n/// Callers derive indexed subkeys from `s_app` via\n/// [`derive_shared_secret_subkey`](crate::keys::ecdh_shared_secret::derive_shared_secret_subkey).\npub unconstrained fn get_shared_secret(address: AztecAddress, ephPk: Point, contract_address: AztecAddress) -> Field {\n get_shared_secret_oracle(address, ephPk, contract_address)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr","function_locations":[{"start":267,"name":"get_shared_secret_oracle"},{"start":1354,"name":"get_shared_secret"}]},"245":{"source":"/// Appends the elements of the second `BoundedVec` to the end of the first one. The resulting `BoundedVec` can have\n/// any arbitrary maximum length, but it must be large enough to fit all of the elements of both the first and second\n/// vectors.\npub fn append(\n a: BoundedVec,\n b: BoundedVec,\n) -> BoundedVec {\n let mut dst = BoundedVec::new();\n\n dst.extend_from_bounded_vec(a);\n dst.extend_from_bounded_vec(b);\n\n dst\n}\n\nmod test {\n use super::append;\n\n #[test]\n unconstrained fn append_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::new();\n let b: BoundedVec<_, 14> = BoundedVec::new();\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 0);\n assert_eq(result.storage(), std::mem::zeroed());\n }\n\n #[test]\n unconstrained fn append_non_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 6);\n assert_eq(result.storage(), [1, 2, 3, 4, 5, 6, std::mem::zeroed(), std::mem::zeroed()]);\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn append_non_empty_vecs_insufficient_max_len() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let _: BoundedVec = append(a, b);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/append.nr","function_locations":[{"start":396,"name":"append"},{"start":608,"name":"test::append_empty_vecs"},{"start":933,"name":"test::append_non_empty_vecs"},{"start":1387,"name":"test::append_non_empty_vecs_insufficient_max_len"}]},"248":{"source":"/// Returns `DstLen` elements from a source array, starting at `offset`. `DstLen` must not be larger than the number of\n/// elements past `offset`.\n///\n/// Examples:\n/// ```\n/// let foo: [Field; 2] = subarray([1, 2, 3, 4, 5], 2);\n/// assert_eq(foo, [3, 4]);\n///\n/// let bar: [Field; 5] = subarray([1, 2, 3, 4, 5], 2); // fails - we can't return 5 elements since only 3 remain\n/// ```\npub fn subarray(src: [T; SrcLen], offset: u32) -> [T; DstLen] {\n assert(offset + DstLen <= SrcLen, \"DstLen too large for offset\");\n\n let mut dst: [T; DstLen] = std::mem::zeroed();\n for i in 0..DstLen {\n dst[i] = src[i + offset];\n }\n\n dst\n}\n\nmod test {\n use super::subarray;\n\n #[test]\n unconstrained fn subarray_into_empty() {\n // In all of these cases we're setting DstLen to be 0, so we always get back an empty array.\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 2), []);\n }\n\n #[test]\n unconstrained fn subarray_complete() {\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), [1, 2, 3, 4, 5]);\n }\n\n #[test]\n unconstrained fn subarray_different_end_sizes() {\n // We implicitly select how many values to read in the size of the return array\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4, 5]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2]);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subarray_offset_too_large() {\n // With an offset of 1 we can only request up to 4 elements\n let _: [_; 5] = subarray([1, 2, 3, 4, 5], 1);\n }\n\n #[test(should_fail)]\n unconstrained fn subarray_bad_return_value() {\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [3, 3, 4, 5]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr","function_locations":[{"start":483,"name":"subarray"},{"start":776,"name":"test::subarray_into_empty"},{"start":1100,"name":"test::subarray_complete"},{"start":1294,"name":"test::subarray_different_end_sizes"},{"start":1736,"name":"test::subarray_offset_too_large"},{"start":1941,"name":"test::subarray_bad_return_value"}]},"249":{"source":"use crate::utils::array;\n\n/// Returns `DstMaxLen` elements from a source BoundedVec, starting at `offset`. `offset` must not be larger than the\n/// original length, and `DstLen` must not be larger than the total number of elements past `offset` (including the\n/// zeroed elements past `len()`).\n///\n/// Only elements at the beginning of the vector can be removed: it is not possible to also remove elements at the end\n/// of the vector by passing a value for `DstLen` that is smaller than `len() - offset`.\n///\n/// Examples:\n/// ```\n/// let foo = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n/// assert_eq(subbvec(foo, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n///\n/// let bar: BoundedVec<_, 1> = subbvec(foo, 2); // fails - we can't return just 1 element since 3 remain\n/// let baz: BoundedVec<_, 10> = subbvec(foo, 3); // fails - we can't return 10 elements since only 7 remain\n/// ```\npub fn subbvec(\n bvec: BoundedVec,\n offset: u32,\n) -> BoundedVec {\n // from_parts_unchecked does not verify that the elements past len are zeroed, but that is not an issue in our case\n // because we're constructing the new storage array as a subarray of the original one (which should have zeroed\n // storage past len), guaranteeing correctness. This is because `subarray` does not allow extending arrays past\n // their original length.\n BoundedVec::from_parts_unchecked(array::subarray(bvec.storage(), offset), bvec.len() - offset)\n}\n\nmod test {\n use super::subbvec;\n\n #[test]\n unconstrained fn subbvec_empty() {\n let bvec = BoundedVec::::from_array([]);\n assert_eq(subbvec(bvec, 0), bvec);\n }\n\n #[test]\n unconstrained fn subbvec_complete() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), bvec);\n\n let smaller_capacity = BoundedVec::<_, 5>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), smaller_capacity);\n }\n\n #[test]\n unconstrained fn subbvec_partial() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 3>::from_array([3, 4, 5]));\n }\n\n #[test]\n unconstrained fn subbvec_into_empty() {\n let bvec: BoundedVec<_, 10> = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 5), BoundedVec::<_, 5>::from_array([]));\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_offset_past_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n let _: BoundedVec<_, 1> = subbvec(bvec, 6);\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_insufficient_dst_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // We're not providing enough space to hold all of the items inside the original BoundedVec. subbvec can cause\n // for the capacity to reduce, but not the length (other than by len - offset).\n let _: BoundedVec<_, 1> = subbvec(bvec, 2);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_causes_enlarge() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // subbvec does not support capacity increases\n let _: BoundedVec<_, 11> = subbvec(bvec, 0);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_too_large_for_offset() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // This effectively requests a capacity increase, since there'd be just one element plus the 5 empty slots,\n // which is less than 7.\n let _: BoundedVec<_, 7> = subbvec(bvec, 4);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr","function_locations":[{"start":1041,"name":"subbvec"},{"start":1612,"name":"test::subbvec_empty"},{"start":1775,"name":"test::subbvec_complete"},{"start":2083,"name":"test::subbvec_partial"},{"start":2376,"name":"test::subbvec_into_empty"},{"start":2609,"name":"test::subbvec_offset_past_len"},{"start":2816,"name":"test::subbvec_insufficient_dst_len"},{"start":3270,"name":"test::subbvec_dst_len_causes_enlarge"},{"start":3579,"name":"test::subbvec_dst_len_too_large_for_offset"}]},"252":{"source":"use std::static_assert;\n\n/// Encodes an array of bytes as fields.\n///\n/// Use\n/// [`decode_bytes_from_fields`](crate::utils::conversion::bytes_as_fields::decode_bytes_from_fields) to recover\n/// the original bytes.\n///\n/// The `bytes` array length must be a multiple of 31. If padding is added, it will need to be manually removed\n/// after decoding.\n///\n/// ## Encoding\n///\n/// Each 31-byte chunk is interpreted as a big-endian integer and stored in a `Field`. For input `[1, 10, 3, ..., 0]`\n/// (31 bytes), the resulting `Field` is `1 * 256^30 + 10 * 256^29 + 3 * 256^28 + ... + 0`.\npub fn encode_bytes_as_fields(bytes: [u8; N]) -> [Field; N / 31] {\n static_assert(N % 31 == 0, \"N must be a multiple of 31\");\n\n let mut fields = [0; N / 31];\n for i in 0..N / 31 {\n let mut field = 0;\n for j in 0..31 {\n field = field * 256 + bytes[i * 31 + j] as Field;\n }\n fields[i] = field;\n }\n\n fields\n}\n\n/// Decodes fields back into bytes.\n///\n/// Inverse of\n/// [`encode_bytes_as_fields`](crate::utils::conversion::bytes_as_fields::encode_bytes_as_fields).\n/// Each input `Field` must fit in 248 bits; `Field::to_be_bytes::<31>()` fails the proof otherwise.\npub fn decode_bytes_from_fields(fields: BoundedVec) -> BoundedVec {\n let mut bytes = BoundedVec::new();\n for i in 0..fields.len() {\n let chunk: [u8; 31] = fields.get(i).to_be_bytes();\n for j in 0..31 {\n bytes.push(chunk[j]);\n }\n }\n bytes\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_bytes_from_fields, encode_bytes_as_fields};\n\n #[test]\n unconstrained fn round_trips_bytes(input: [u8; 93]) {\n let fields = encode_bytes_as_fields(input);\n\n // In production the fields fly through the system and arrive as a BoundedVec on the other end.\n let fields_bvec = BoundedVec::<_, 6>::from_array(fields);\n let bytes_back = decode_bytes_from_fields(fields_bvec);\n\n assert_eq(bytes_back.len(), input.len());\n assert_eq(subarray(bytes_back.storage(), 0), input);\n }\n\n #[test(should_fail_with = \"N must be a multiple of 31\")]\n unconstrained fn encode_rejects_length_not_multiple_of_31() {\n let _fields = encode_bytes_as_fields([0; 32]);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 31 limbs\")]\n unconstrained fn decode_rejects_oversized_field() {\n // `Field::to_be_bytes::<31>()` fails the proof when a field has any bit above position 247 set.\n let oversized: Field = (1 as Field) * 2.pow_32(249);\n let input = BoundedVec::<_, 1>::from_array([oversized]);\n let _bytes = decode_bytes_from_fields(input);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/bytes_as_fields.nr","function_locations":[{"start":662,"name":"encode_bytes_as_fields"},{"start":1313,"name":"decode_bytes_from_fields"},{"start":1719,"name":"tests::round_trips_bytes"},{"start":2252,"name":"tests::encode_rejects_length_not_multiple_of_31"},{"start":2454,"name":"tests::decode_rejects_oversized_field"}]},"253":{"source":"/// Encodes an array of fields as bytes.\n///\n/// Losslessly preserves any field value; use\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes) to\n/// recover the original fields.\n///\n/// ## Encoding\n///\n/// Each field is written as 32 big-endian bytes and the chunks are concatenated. The field array `[5, 42]` becomes:\n///\n/// ```text\n/// [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, // First field (32 bytes)\n/// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42] // Second field (32 bytes)\n/// ```\n///\n/// ## Privacy\n///\n/// The BN254 modulus is `< 2^254`, so every 32-byte chunk has its top bit at zero and the next bit biased. The output\n/// is therefore distinguishable from uniform random bytes; take this into account when feeding it into anything that\n/// assumes uniform randomness (e.g. ciphertexts meant to look random).\npub fn encode_fields_as_bytes(fields: [Field; N]) -> [u8; 32 * N] {\n let mut bytes = [0; 32 * N];\n for i in 0..N {\n let chunk: [u8; 32] = fields[i].to_be_bytes();\n for j in 0..32 {\n bytes[i * 32 + j] = chunk[j];\n }\n }\n bytes\n}\n\n/// Decodes bytes back into fields.\n///\n/// Panics if the input length is not a multiple of 32 or if any chunk exceeds the BN254 field modulus. See\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes)\n/// for a non-panicking variant.\npub fn decode_fields_from_bytes(bytes: BoundedVec) -> BoundedVec {\n assert(bytes.len() % 32 == 0, \"Input length must be a multiple of 32\");\n try_decode_fields_from_bytes(bytes).expect(f\"Value does not fit in field\")\n}\n\n/// Decodes bytes back into fields, returning None on failure.\n///\n/// Inverse of\n/// [`encode_fields_as_bytes`](crate::utils::conversion::fields_as_bytes::encode_fields_as_bytes).\n/// Returns `Option::none()` if the input length is not a multiple of 32, or if any 32-byte chunk is `>=` the BN254\n/// field modulus.\npub fn try_decode_fields_from_bytes(bytes: BoundedVec) -> Option> {\n if bytes.len() % 32 == 0 {\n let num_chunks = bytes.len() / 32;\n let mut fields: BoundedVec = BoundedVec::new();\n for i in 0..num_chunks {\n let maybe_field = try_decode_field_from_bytes(bytes, i * 32);\n if maybe_field.is_some() {\n fields.push(maybe_field.unwrap());\n }\n }\n if fields.len() == num_chunks {\n Option::some(fields)\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n}\n\nfn try_decode_field_from_bytes(bytes: BoundedVec, offset: u32) -> Option {\n // Field arithmetic silently wraps values >= the modulus, so we compare each chunk against the modulus\n // byte-by-byte (big-endian) while building `field`. cmp: 0 = equal so far, 1 = less than modulus, 2 = exceeds.\n let p = std::field::modulus_be_bytes();\n let mut field = 0;\n let mut cmp: u8 = 0;\n for j in 0..32 {\n let byte = bytes.get(offset + j);\n field = field * 256 + byte as Field;\n if cmp == 0 {\n if byte < p[j] {\n cmp = 1;\n } else if byte > p[j] {\n cmp = 2;\n }\n }\n }\n\n if cmp == 1 {\n Option::some(field)\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_fields_from_bytes, encode_fields_as_bytes, try_decode_fields_from_bytes};\n\n #[test]\n unconstrained fn round_trips_fields(input: [Field; 3]) {\n let bytes = encode_fields_as_bytes(input);\n\n // In production the bytes fly through the system and arrive as a BoundedVec on the other end. 113 is an\n // arbitrary max length larger than the input length of 96.\n let bytes_bvec = BoundedVec::<_, 113>::from_array(bytes);\n let fields_back = try_decode_fields_from_bytes(bytes_bvec).unwrap();\n\n assert_eq(fields_back.len(), input.len());\n assert_eq(subarray(fields_back.storage(), 0), input);\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_length_not_multiple_of_32() {\n let input = BoundedVec::<_, 64>::from_parts([0 as u8; 64], 33);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test]\n unconstrained fn try_decode_accepts_max_field() {\n // -1 in field arithmetic wraps to `modulus - 1`, the largest valid field value.\n let max_field_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let input = BoundedVec::<_, 32>::from_array(max_field_as_bytes);\n\n let fields = try_decode_fields_from_bytes(input).unwrap();\n\n assert_eq(fields.get(0), -1);\n }\n\n // Verifies the overflow check: take the max allowed value, bump a random byte, feed it in.\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n // Skip if the selected byte is already 255. Acceptable under fuzz testing.\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_equal_to_modulus() {\n // The field modulus itself is not a valid field value (it wraps to 0).\n let p: [u8; 32] = std::field::modulus_be_bytes().as_array();\n let input = BoundedVec::::from_array(p);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test(should_fail_with = \"Input length must be a multiple of 32\")]\n unconstrained fn decode_asserts_length_multiple_of_32() {\n let input = BoundedVec::<_, 143>::from_array([\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n 30, 31, 32, 33,\n ]);\n let _fields = decode_fields_from_bytes(input);\n }\n\n #[test(should_fail_with = \"Value does not fit in field\")]\n unconstrained fn decode_panics_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n let _fields = decode_fields_from_bytes(input);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/fields_as_bytes.nr","function_locations":[{"start":1007,"name":"encode_fields_as_bytes"},{"start":1603,"name":"decode_fields_from_bytes"},{"start":2190,"name":"try_decode_fields_from_bytes"},{"start":2829,"name":"try_decode_field_from_bytes"},{"start":3733,"name":"tests::round_trips_fields"},{"start":4320,"name":"tests::try_decode_returns_none_on_length_not_multiple_of_32"},{"start":4528,"name":"tests::try_decode_accepts_max_field"},{"start":5063,"name":"tests::try_decode_returns_none_on_chunk_above_modulus"},{"start":5718,"name":"tests::try_decode_returns_none_on_chunk_equal_to_modulus"},{"start":6128,"name":"tests::decode_asserts_length_multiple_of_32"},{"start":6544,"name":"tests::decode_panics_on_chunk_above_modulus"}]},"256":{"source":"use crate::protocol::{point::Point, utils::field::sqrt};\n\n// I am storing the modulus minus 1 divided by 2 here because full modulus would throw \"String literal too large\" error\n// Full modulus is 21888242871839275222246405745257275088548364400416034343698204186575808495617\nglobal BN254_FR_MODULUS_DIV_2: Field = 10944121435919637611123202872628637544274182200208017171849102093287904247808;\n\n/// Returns: true if p.y <= MOD_DIV_2, else false.\npub fn get_sign_of_point(p: Point) -> bool {\n // We store only a \"sign\" of the y coordinate because the rest can be derived from the x coordinate. To get the\n // sign we check if the y coordinate is less or equal than the field's modulus minus 1 divided by 2. Ideally we'd\n // do `y <= MOD_DIV_2`, but there's no `lte` function, so instead we do `!(y > MOD_DIV_2)`, which is equivalent,\n // and then rewrite that as `!(MOD_DIV_2 < y)`, since we also have no `gt` function.\n !BN254_FR_MODULUS_DIV_2.lt(p.y)\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\npub fn point_from_x_coord(x: Field) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n sqrt(rhs).map(|y| Point { x, y, is_infinite: false })\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate and sign for the y coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\n///\n/// @param x - The x coordinate of the point @param sign - The \"sign\" of the y coordinate - determines whether y <=\n/// (Fr.MODULUS - 1) / 2\npub fn point_from_x_coord_and_sign(x: Field, sign: bool) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n\n sqrt(rhs).map(|y| {\n // If there is a square root, we need to ensure it has the correct \"sign\"\n let y_is_positive = !BN254_FR_MODULUS_DIV_2.lt(y);\n let final_y = if y_is_positive == sign { y } else { -y };\n Point { x, y: final_y, is_infinite: false }\n })\n}\n\nmod test {\n use crate::protocol::point::Point;\n use crate::utils::point::{\n BN254_FR_MODULUS_DIV_2, get_sign_of_point, point_from_x_coord, point_from_x_coord_and_sign,\n };\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign() {\n // Test positive y coordinate\n let x = 0x1af41f5de96446dc3776a1eb2d98bb956b7acd9979a67854bec6fa7c2973bd73;\n let sign = true;\n let p = point_from_x_coord_and_sign(x, sign).unwrap();\n\n assert_eq(p.x, x);\n assert_eq(p.y, 0x07fc22c7f2c7057571f137fe46ea9c95114282bc95d37d71ec4bfb88de457d4a);\n assert_eq(p.is_infinite, false);\n\n // Test negative y coordinate\n let x2 = 0x247371652e55dd74c9af8dbe9fb44931ba29a9229994384bd7077796c14ee2b5;\n let sign2 = false;\n let p2 = point_from_x_coord_and_sign(x2, sign2).unwrap();\n\n assert_eq(p2.x, x2);\n assert_eq(p2.y, 0x26441aec112e1ae4cee374f42556932001507ad46e255ffb27369c7e3766e5c0);\n assert_eq(p2.is_infinite, false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_valid() {\n // x = 8 is a known quadratic residue - should give a valid point\n let result = point_from_x_coord(Field::from(8));\n assert(result.is_some());\n\n let point = result.unwrap();\n assert_eq(point.x, Field::from(8));\n // Check curve equation y^2 = x^3 - 17\n assert_eq(point.y * point.y, point.x * point.x * point.x - 17);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_invalid() {\n // x = 3 is a non-residue for this curve - should give None\n let x = Field::from(3);\n let maybe_point = point_from_x_coord(x);\n assert(maybe_point.is_none());\n }\n\n #[test]\n unconstrained fn test_both_roots_satisfy_curve() {\n // Derive a point from x = 8 (known to be valid from test_point_from_x_coord_valid)\n let x: Field = 8;\n let point = point_from_x_coord(x).unwrap();\n\n // Check y satisfies curve equation\n assert_eq(point.y * point.y, x * x * x - 17);\n\n // Check -y also satisfies curve equation\n let neg_y = 0 - point.y;\n assert_eq(neg_y * neg_y, x * x * x - 17);\n\n // Verify they are different (unless y = 0)\n assert(point.y != neg_y);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign_invalid() {\n // x = 3 has no valid point on the curve (from test_point_from_x_coord_invalid)\n let x = Field::from(3);\n let result_positive = point_from_x_coord_and_sign(x, true);\n let result_negative = point_from_x_coord_and_sign(x, false);\n\n assert(result_positive.is_none());\n assert(result_negative.is_none());\n }\n\n #[test]\n unconstrained fn test_get_sign_of_point() {\n // Derive a point from x = 8, then test both possible y values\n let point = point_from_x_coord(8).unwrap();\n let neg_point = Point { x: point.x, y: 0 - point.y, is_infinite: false };\n\n // One should be \"positive\" (y <= MOD_DIV_2) and one \"negative\"\n let sign1 = get_sign_of_point(point);\n let sign2 = get_sign_of_point(neg_point);\n assert(sign1 != sign2);\n\n // y = 0 should return true (0 <= MOD_DIV_2)\n let zero_y_point = Point { x: 0, y: 0, is_infinite: false };\n assert(get_sign_of_point(zero_y_point) == true);\n\n // y = MOD_DIV_2 should return true (exactly at boundary)\n let boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2, is_infinite: false };\n assert(get_sign_of_point(boundary_point) == true);\n\n // y = MOD_DIV_2 + 1 should return false (just over boundary)\n let over_boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2 + 1, is_infinite: false };\n assert(get_sign_of_point(over_boundary_point) == false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_zero() {\n // x = 0: y^2 = 0^3 - 17 = -17, which is not a quadratic residue in BN254 scalar field\n let result = point_from_x_coord(0);\n assert(result.is_none());\n }\n\n #[test]\n unconstrained fn test_bn254_fr_modulus_div_2() {\n // Verify that BN254_FR_MODULUS_DIV_2 == (p - 1) / 2 This means: 2 * BN254_FR_MODULUS_DIV_2 + 1 == p == 0 (in\n // the field)\n assert_eq(2 * BN254_FR_MODULUS_DIV_2 + 1, 0);\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/point.nr","function_locations":[{"start":488,"name":"get_sign_of_point"},{"start":1371,"name":"point_from_x_coord"},{"start":2088,"name":"point_from_x_coord_and_sign"},{"start":2697,"name":"test::test_point_from_x_coord_and_sign"},{"start":3524,"name":"test::test_point_from_x_coord_valid"},{"start":3966,"name":"test::test_point_from_x_coord_invalid"},{"start":4228,"name":"test::test_both_roots_satisfy_curve"},{"start":4803,"name":"test::test_point_from_x_coord_and_sign_invalid"},{"start":5214,"name":"test::test_get_sign_of_point"},{"start":6328,"name":"test::test_point_from_x_coord_zero"},{"start":6573,"name":"test::test_bn254_fr_modulus_div_2"}]},"266":{"source":"use std::default::Default;\nuse std::hash::Hasher;\n\nglobal RATE: u32 = 3;\n\npub struct Poseidon2 {\n cache: [Field; 3],\n state: [Field; 4],\n cache_size: u32,\n squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2 {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2::hash_internal(input, message_size)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2 {\n let mut result =\n Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n self.state[0] += self.cache[0];\n self.state[1] += self.cache[1];\n self.state[2] += self.cache[2];\n self.state = crate::poseidon2_permutation(self.state);\n }\n\n fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(input: [Field; N], in_len: u32) -> Field {\n let two_pow_64 = 18446744073709551616;\n let iv: Field = (in_len as Field) * two_pow_64;\n let mut state = [0; 4];\n state[RATE] = iv;\n\n if std::runtime::is_unconstrained() {\n for i in 0..(in_len / RATE) {\n state[0] += input[i * RATE];\n state[1] += input[i * RATE + 1];\n state[2] += input[i * RATE + 2];\n state = crate::poseidon2_permutation(state);\n }\n\n // handle remaining elements after last full RATE-sized chunk\n let num_extra_fields = in_len % RATE;\n if num_extra_fields != 0 {\n let remainder_start = in_len - num_extra_fields;\n state[0] += input[remainder_start];\n if num_extra_fields > 1 {\n state[1] += input[remainder_start + 1];\n }\n }\n } else {\n let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];\n states[0] = state;\n\n // process all full RATE-sized chunks, storing state after each permutation\n for chunk_idx in 0..(N / RATE) {\n for i in 0..RATE {\n state[i] += input[chunk_idx * RATE + i];\n }\n state = crate::poseidon2_permutation(state);\n states[chunk_idx + 1] = state;\n }\n\n // get state at the last full block before in_len\n let first_partially_filled_chunk = in_len / RATE;\n state = states[first_partially_filled_chunk];\n\n // handle remaining elements after last full RATE-sized chunk\n let remainder_start = (in_len / RATE) * RATE;\n for j in 0..RATE {\n let idx = remainder_start + j;\n if idx < in_len {\n state[j] += input[idx];\n }\n }\n }\n\n // always run final permutation unless we just completed a full chunk\n // still need to permute once if in_len is 0\n if (in_len == 0) | (in_len % RATE != 0) {\n state = crate::poseidon2_permutation(state);\n };\n\n state[0]\n }\n}\n\npub struct Poseidon2Hasher {\n _state: [Field],\n}\n\nimpl Hasher for Poseidon2Hasher {\n fn finish(self) -> Field {\n let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)\n let mut sponge = Poseidon2::new(iv);\n for i in 0..self._state.len() {\n sponge.absorb(self._state[i]);\n }\n sponge.squeeze()\n }\n\n fn write(&mut self, input: Field) {\n self._state = self._state.push_back(input);\n }\n}\n\nimpl Default for Poseidon2Hasher {\n fn default() -> Self {\n Poseidon2Hasher { _state: @[] }\n }\n}\n","path":"/Users/maximvezenov/nargo/github.com/noir-lang/poseidon/v0.3.0/src/poseidon2.nr","function_locations":[{"start":333,"name":"Poseidon2::hash"},{"start":442,"name":"Poseidon2::new"},{"start":649,"name":"Poseidon2::perform_duplex"},{"start":923,"name":"Poseidon2::absorb"},{"start":1453,"name":"Poseidon2::squeeze"},{"start":1814,"name":"Poseidon2::hash_internal"},{"start":4105,"name":"::finish"},{"start":4426,"name":"::write"},{"start":4549,"name":"::default"}]},"286":{"source":"use crate::traits::{Deserialize, Empty, FromField, Serialize, ToField};\nuse std::meta::derive;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct FunctionSelector {\n // Low 32 bits of the poseidon2 hash of the function signature.\n pub inner: u32,\n}\n\nimpl FromField for FunctionSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for FunctionSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for FunctionSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl FunctionSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = crate::hash::poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n FunctionSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n\n#[test]\nfn test_is_valid_selector() {\n let selector = FunctionSelector::from_signature(\"IS_VALID()\");\n assert_eq(selector.to_field(), 0x73cdda47);\n}\n\n#[test]\nfn test_long_selector() {\n let selector =\n FunctionSelector::from_signature(\"foo_and_bar_and_baz_and_foo_bar_baz_and_bar_foo\");\n assert_eq(selector.to_field(), 0x7590a997);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr","function_locations":[{"start":333,"name":"::from_field"},{"start":448,"name":"::to_field"},{"start":544,"name":"::empty"},{"start":652,"name":"FunctionSelector::from_u32"},{"start":756,"name":"FunctionSelector::from_signature"},{"start":1006,"name":"FunctionSelector::zero"},{"start":1079,"name":"test_is_valid_selector"},{"start":1231,"name":"test_long_selector"}]},"355":{"source":"mod poseidon2_chunks;\n\nuse crate::{\n abis::{\n contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage,\n function_selector::FunctionSelector, nullifier::Nullifier, private_log::PrivateLog,\n transaction::tx_request::TxRequest,\n },\n address::{AztecAddress, EthAddress},\n constants::{\n CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, DOM_SEP__NOTE_HASH_NONCE,\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__SILOED_NOTE_HASH, DOM_SEP__SILOED_NULLIFIER,\n DOM_SEP__UNIQUE_NOTE_HASH, FUNCTION_TREE_HEIGHT, NULL_MSG_SENDER_CONTRACT_ADDRESS,\n TWO_POW_64,\n },\n merkle_tree::root_from_sibling_path,\n messaging::l2_to_l1_message::L2ToL1Message,\n poseidon2::Poseidon2Sponge,\n side_effect::{Counted, Scoped},\n traits::{FromField, Hash, ToField},\n utils::field::{field_from_bytes, field_from_bytes_32_trunc},\n};\n\npub use poseidon2_chunks::poseidon2_absorb_in_chunks_existing_sponge;\nuse poseidon2_chunks::poseidon2_absorb_in_chunks;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\n// TODO: refactor these into their own files: sha256, poseidon2, some protocol-specific hash computations, some merkle computations.\n\npub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field {\n let sha256_hashed = sha256::digest(bytes_to_hash);\n let hash_in_a_field = field_from_bytes_32_trunc(sha256_hashed);\n\n hash_in_a_field\n}\n\npub fn private_functions_root_from_siblings(\n selector: FunctionSelector,\n vk_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT],\n) -> Field {\n let function_leaf_preimage = ContractClassFunctionLeafPreimage { selector, vk_hash };\n let function_leaf = function_leaf_preimage.hash();\n root_from_sibling_path(\n function_leaf,\n function_leaf_index,\n function_leaf_sibling_path,\n )\n}\n\n/// Siloing in the context of Aztec refers to the process of hashing a note hash with a contract address (this way\n/// the note hash is scoped to a specific contract). This is used to prevent intermingling of notes between contracts.\npub fn compute_siloed_note_hash(contract_address: AztecAddress, note_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), note_hash],\n DOM_SEP__SILOED_NOTE_HASH,\n )\n}\n\n/// Computes unique, siloed note hashes from siloed note hashes.\n///\n/// The protocol injects uniqueness into every note_hash, so that every single note_hash in the\n/// tree is unique. This prevents faerie gold attacks, where a malicious sender could create\n/// two identical note_hashes for a recipient (meaning only one would be nullifiable in future).\n///\n/// Most privacy protocols will inject the note's leaf_index (its position in the Note Hashes Tree)\n/// into the note, but this requires the creator of a note to wait until their tx is included in\n/// a block to know the note's final note hash (the unique, siloed note hash), because inserting\n/// leaves into trees is the job of a block producer.\n///\n/// We took a different approach so that the creator of a note will know each note's unique, siloed\n/// note hash before broadcasting their tx to the network.\n/// (There was also a historical requirement relating to \"chained transactions\" -- a feature that\n/// Aztec Connect had to enable notes to be spent from distinct txs earlier in the same block,\n/// and hence before an archive block root had been established for that block -- but that feature\n/// was abandoned for the Aztec Network for having too many bad tradeoffs).\n///\n/// (\n/// Edit: it is no longer true that all final note_hashes will be known by the creator of a tx\n/// before they send it to the network. If a tx makes public function calls, then _revertible_\n/// note_hashes that are created in private will not be made unique in private by the Reset circuit,\n/// but will instead be made unique by the AVM, because the `note_index_in_tx` will not be known\n/// until the AVM has executed the public functions of the tx. (See an explanation in\n/// reset_output_composer.nr for why).\n/// For some such txs, the `note_index_in_tx` might still be predictable through simulation, but\n/// for txs whose public functions create a varying number of non-revertible notes (determined at\n/// runtime), the `note_index_in_tx` will not be deterministically derivable before submitting the\n/// tx to the network.\n/// )\n///\n/// We use the `first_nullifier` of a tx as a seed of uniqueness. We have a guarantee that there will\n/// always be at least one nullifier per tx, because the init circuit will create one if one isn't\n/// created naturally by any functions of the tx. (Search \"protocol_nullifier\").\n/// We combine the `first_nullifier` with the note's index (its position within this tx's new\n/// note_hashes array) (`note_index_in_tx`) to get a truly unique value to inject into a note, which\n/// we call a `note_nonce`.\npub fn compute_unique_note_hash(note_nonce: Field, siloed_note_hash: Field) -> Field {\n let inputs = [note_nonce, siloed_note_hash];\n poseidon2_hash_with_separator(inputs, DOM_SEP__UNIQUE_NOTE_HASH)\n}\n\npub fn compute_note_hash_nonce(first_nullifier_in_tx: Field, note_index_in_tx: u32) -> Field {\n // Hashing the first nullifier with note index in tx is guaranteed to be unique (because all nullifiers are also\n // unique).\n poseidon2_hash_with_separator(\n [first_nullifier_in_tx, note_index_in_tx as Field],\n DOM_SEP__NOTE_HASH_NONCE,\n )\n}\n\npub fn compute_note_nonce_and_unique_note_hash(\n siloed_note_hash: Field,\n first_nullifier: Field,\n note_index_in_tx: u32,\n) -> Field {\n let note_nonce = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n compute_unique_note_hash(note_nonce, siloed_note_hash)\n}\n\npub fn compute_siloed_nullifier(contract_address: AztecAddress, nullifier: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), nullifier],\n DOM_SEP__SILOED_NULLIFIER,\n )\n}\n\npub fn create_protocol_nullifier(tx_request: TxRequest) -> Scoped> {\n // The protocol nullifier is ascribed a special side-effect counter of 1. No other side-effect\n // can have counter 1 (see `validate_as_first_call` for that assertion).\n Nullifier { value: tx_request.hash(), note_hash: 0 }.count(1).scope(\n NULL_MSG_SENDER_CONTRACT_ADDRESS,\n )\n}\n\npub fn compute_log_tag(raw_tag: Field, dom_sep: u32) -> Field {\n poseidon2_hash_with_separator([raw_tag], dom_sep)\n}\n\npub fn compute_siloed_private_log_first_field(\n contract_address: AztecAddress,\n field: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), field],\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD,\n )\n}\n\npub fn compute_siloed_private_log(contract_address: AztecAddress, log: PrivateLog) -> PrivateLog {\n let mut fields = log.fields;\n fields[0] = compute_siloed_private_log_first_field(contract_address, fields[0]);\n PrivateLog::new(fields, log.length)\n}\n\npub fn compute_contract_class_log_hash(log: [Field; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS]) -> Field {\n poseidon2_hash(log)\n}\n\npub fn compute_app_siloed_secret_key(\n master_secret_key: EmbeddedCurveScalar,\n app_address: AztecAddress,\n key_type_domain_separator: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [master_secret_key.hi, master_secret_key.lo, app_address.to_field()],\n key_type_domain_separator,\n )\n}\n\npub fn compute_l2_to_l1_message_hash(\n message: Scoped,\n rollup_version_id: Field,\n chain_id: Field,\n) -> Field {\n let contract_address_bytes: [u8; 32] = message.contract_address.to_field().to_be_bytes();\n let recipient_bytes: [u8; 20] = message.inner.recipient.to_be_bytes();\n let content_bytes: [u8; 32] = message.inner.content.to_be_bytes();\n let rollup_version_id_bytes: [u8; 32] = rollup_version_id.to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n\n let mut bytes: [u8; 148] = std::mem::zeroed();\n for i in 0..32 {\n bytes[i] = contract_address_bytes[i];\n bytes[i + 32] = rollup_version_id_bytes[i];\n // 64 - 84 are for recipient.\n bytes[i + 84] = chain_id_bytes[i];\n bytes[i + 116] = content_bytes[i];\n }\n\n for i in 0..20 {\n bytes[64 + i] = recipient_bytes[i];\n }\n\n sha256_to_field(bytes)\n}\n\n// TODO: consider a variant that enables domain separation with a u32 (we seem to have standardised u32s for domain separators)\n/// Computes sha256 hash of 2 input fields.\n///\n/// @returns A truncated field (i.e., the first byte is always 0).\npub fn accumulate_sha256(v0: Field, v1: Field) -> Field {\n // Concatenate two fields into 32 x 2 = 64 bytes\n let v0_as_bytes: [u8; 32] = v0.to_be_bytes();\n let v1_as_bytes: [u8; 32] = v1.to_be_bytes();\n let hash_input_flattened = v0_as_bytes.concat(v1_as_bytes);\n\n sha256_to_field(hash_input_flattened)\n}\n\npub fn poseidon2_hash(inputs: [Field; N]) -> Field {\n poseidon::poseidon2::Poseidon2::hash(inputs, N)\n}\n\n#[no_predicates]\npub fn poseidon2_hash_with_separator(inputs: [Field; N], separator: T) -> Field\nwhere\n T: ToField,\n{\n let inputs_with_separator = [separator.to_field()].concat(inputs);\n poseidon2_hash(inputs_with_separator)\n}\n\n/// Computes a Poseidon2 hash over a dynamic-length subarray of the given input.\n/// Only the first `in_len` fields of `input` are absorbed; any remaining fields are ignored.\n/// The caller is responsible for ensuring that the input is padded with zeros if required.\n#[no_predicates]\npub fn poseidon2_hash_subarray(input: [Field; N], in_len: u32) -> Field {\n let mut sponge = poseidon2_absorb_in_chunks(input, in_len);\n sponge.squeeze()\n}\n\n// This function is unconstrained because it is intended to be used in unconstrained context only as\n// in constrained contexts it would be too inefficient.\npub unconstrained fn poseidon2_hash_with_separator_bounded_vec(\n inputs: BoundedVec,\n separator: T,\n) -> Field\nwhere\n T: ToField,\n{\n let in_len = inputs.len() + 1;\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n sponge.absorb(separator.to_field());\n\n for i in 0..inputs.len() {\n sponge.absorb(inputs.get(i));\n }\n\n sponge.squeeze()\n}\n\n#[no_predicates]\npub fn poseidon2_hash_bytes(inputs: [u8; N]) -> Field {\n let mut fields = [0; (N + 30) / 31];\n let mut field_index = 0;\n let mut current_field = [0; 31];\n for i in 0..inputs.len() {\n let index = i % 31;\n current_field[index] = inputs[i];\n if index == 30 {\n fields[field_index] = field_from_bytes(current_field, false);\n current_field = [0; 31];\n field_index += 1;\n }\n }\n if field_index != fields.len() {\n fields[field_index] = field_from_bytes(current_field, false);\n }\n poseidon2_hash(fields)\n}\n\n#[test]\nfn subarray_hash_matches_fixed() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash the entire values_to_hash.\n let fixed_len_hash = poseidon::poseidon2::Poseidon2::hash(values_to_hash, values_to_hash.len());\n\n assert_eq(subarray_hash, fixed_len_hash);\n}\n\n#[test]\nfn subarray_hash_matches_variable() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash up to values_to_hash.len() fields of the padded array.\n let variable_len_hash = poseidon::poseidon2::Poseidon2::hash(padded, values_to_hash.len());\n\n assert_eq(subarray_hash, variable_len_hash);\n}\n\n#[test]\nfn smoke_sha256_to_field() {\n let full_buffer = [\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\n 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,\n 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,\n 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,\n 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,\n 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,\n 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\n ];\n let result = sha256_to_field(full_buffer);\n\n assert(result == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184c7);\n\n // to show correctness of the current ver (truncate one byte) vs old ver (mod full bytes):\n let result_bytes = sha256::digest(full_buffer);\n let truncated_field = crate::utils::field::field_from_bytes_32_trunc(result_bytes);\n assert(truncated_field == result);\n let mod_res = result + (result_bytes[31] as Field);\n assert(mod_res == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184e0);\n}\n\n#[test]\nfn unique_siloed_note_hash_matches_typescript() {\n let inner_note_hash = 1;\n let contract_address = AztecAddress::from_field(2);\n let first_nullifier = 3;\n let note_index_in_tx = 4;\n\n let siloed_note_hash = compute_siloed_note_hash(contract_address, inner_note_hash);\n let siloed_note_hash_from_ts =\n 0x1986a4bea3eddb1fff917d629a13e10f63f514f401bdd61838c6b475db949169;\n assert_eq(siloed_note_hash, siloed_note_hash_from_ts);\n\n let nonce: Field = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n let note_hash_nonce_from_ts =\n 0x28e7799791bf066a57bb51fdd0fbcaf3f0926414314c7db515ea343f44f5d58b;\n assert_eq(nonce, note_hash_nonce_from_ts);\n\n let unique_siloed_note_hash_from_nonce = compute_unique_note_hash(nonce, siloed_note_hash);\n let unique_siloed_note_hash = compute_note_nonce_and_unique_note_hash(\n siloed_note_hash,\n first_nullifier,\n note_index_in_tx,\n );\n assert_eq(unique_siloed_note_hash_from_nonce, unique_siloed_note_hash);\n\n let unique_siloed_note_hash_from_ts =\n 0x29949aef207b715303b24639737c17fbfeb375c1d965ecfa85c7e4f0febb7d16;\n assert_eq(unique_siloed_note_hash, unique_siloed_note_hash_from_ts);\n}\n\n#[test]\nfn siloed_nullifier_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let nullifier = 456;\n\n let res = compute_siloed_nullifier(contract_address, nullifier);\n\n let siloed_nullifier_from_ts =\n 0x169b50336c1f29afdb8a03d955a81e485f5ac7d5f0b8065673d1e407e5877813;\n\n assert_eq(res, siloed_nullifier_from_ts);\n}\n\n#[test]\nfn siloed_private_log_first_field_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let field = 456;\n let res = compute_siloed_private_log_first_field(contract_address, field);\n\n let siloed_private_log_first_field_from_ts =\n 0x29480984f7b9257fded523d50addbcfc8d1d33adcf2db73ef3390a8fd5cdffaa;\n\n assert_eq(res, siloed_private_log_first_field_from_ts);\n}\n\n#[test]\nfn empty_l2_to_l1_message_hash_matches_typescript() {\n // All zeroes\n let res = compute_l2_to_l1_message_hash(\n L2ToL1Message { recipient: EthAddress::zero(), content: 0 }.scope(AztecAddress::from_field(\n 0,\n )),\n 0,\n 0,\n );\n\n let empty_l2_to_l1_msg_hash_from_ts =\n 0x003b18c58c739716e76429634a61375c45b3b5cd470c22ab6d3e14cee23dd992;\n\n assert_eq(res, empty_l2_to_l1_msg_hash_from_ts);\n}\n\n#[test]\nfn l2_to_l1_message_hash_matches_typescript() {\n let message = L2ToL1Message { recipient: EthAddress::from_field(1), content: 2 }.scope(\n AztecAddress::from_field(3),\n );\n let version = 4;\n let chainId = 5;\n\n let hash = compute_l2_to_l1_message_hash(message, version, chainId);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let l2_to_l1_message_hash_from_ts =\n 0x0081edf209e087ad31b3fd24263698723d57190bd1d6e9fe056fc0c0a68ee661;\n\n assert_eq(hash, l2_to_l1_message_hash_from_ts);\n}\n\n#[test]\nunconstrained fn poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version() {\n let inputs = BoundedVec::::from_array([1, 2, 3]);\n let separator = 42;\n\n // Hash using bounded vec version\n let bounded_result = poseidon2_hash_with_separator_bounded_vec(inputs, separator);\n\n // Hash using regular version\n let regular_result = poseidon2_hash_with_separator([1, 2, 3], separator);\n\n // Results should match\n assert_eq(bounded_result, regular_result);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr","function_locations":[{"start":1253,"name":"sha256_to_field"},{"start":1605,"name":"private_functions_root_from_siblings"},{"start":2202,"name":"compute_siloed_note_hash"},{"start":5031,"name":"compute_unique_note_hash"},{"start":5247,"name":"compute_note_hash_nonce"},{"start":5663,"name":"compute_note_nonce_and_unique_note_hash"},{"start":5899,"name":"compute_siloed_nullifier"},{"start":6116,"name":"create_protocol_nullifier"},{"start":6480,"name":"compute_log_tag"},{"start":6651,"name":"compute_siloed_private_log_first_field"},{"start":6882,"name":"compute_siloed_private_log"},{"start":7142,"name":"compute_contract_class_log_hash"},{"start":7333,"name":"compute_app_siloed_secret_key"},{"start":7628,"name":"compute_l2_to_l1_message_hash"},{"start":8709,"name":"accumulate_sha256"},{"start":9037,"name":"poseidon2_hash"},{"start":9228,"name":"poseidon2_hash_with_separator"},{"start":9714,"name":"poseidon2_hash_subarray"},{"start":10126,"name":"poseidon2_hash_with_separator_bounded_vec"},{"start":10487,"name":"poseidon2_hash_bytes"},{"start":11063,"name":"subarray_hash_matches_fixed"},{"start":11462,"name":"subarray_hash_matches_variable"},{"start":11878,"name":"smoke_sha256_to_field"},{"start":13280,"name":"unique_siloed_note_hash_matches_typescript"},{"start":14502,"name":"siloed_nullifier_matches_typescript"},{"start":14882,"name":"siloed_private_log_first_field_matches_typescript"},{"start":15292,"name":"empty_l2_to_l1_message_hash_matches_typescript"},{"start":15743,"name":"l2_to_l1_message_hash_matches_typescript"},{"start":16359,"name":"poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version"}]},"357":{"source":"// Log levels matching the JS logger:\n\n// global SILENT_LOG_LEVEL: u8 = 0;\nglobal FATAL_LOG_LEVEL: u8 = 1;\nglobal ERROR_LOG_LEVEL: u8 = 2;\nglobal WARN_LOG_LEVEL: u8 = 3;\nglobal INFO_LOG_LEVEL: u8 = 4;\nglobal VERBOSE_LOG_LEVEL: u8 = 5;\nglobal DEBUG_LOG_LEVEL: u8 = 6;\nglobal TRACE_LOG_LEVEL: u8 = 7;\n\n// --- Per-level log functions (no format args) ---\n\npub fn fatal_log(msg: str) {\n fatal_log_format(msg, []);\n}\n\npub fn error_log(msg: str) {\n error_log_format(msg, []);\n}\n\npub fn warn_log(msg: str) {\n warn_log_format(msg, []);\n}\n\npub fn info_log(msg: str) {\n info_log_format(msg, []);\n}\n\npub fn verbose_log(msg: str) {\n verbose_log_format(msg, []);\n}\n\npub fn debug_log(msg: str) {\n debug_log_format(msg, []);\n}\n\npub fn trace_log(msg: str) {\n trace_log_format(msg, []);\n}\n\n// --- Per-level log functions (with format args) ---\n\npub fn fatal_log_format(msg: str, args: [Field; N]) {\n log_format(FATAL_LOG_LEVEL, msg, args);\n}\n\npub fn error_log_format(msg: str, args: [Field; N]) {\n log_format(ERROR_LOG_LEVEL, msg, args);\n}\n\npub fn warn_log_format(msg: str, args: [Field; N]) {\n log_format(WARN_LOG_LEVEL, msg, args);\n}\n\npub fn info_log_format(msg: str, args: [Field; N]) {\n log_format(INFO_LOG_LEVEL, msg, args);\n}\n\npub fn verbose_log_format(msg: str, args: [Field; N]) {\n log_format(VERBOSE_LOG_LEVEL, msg, args);\n}\n\npub fn debug_log_format(msg: str, args: [Field; N]) {\n log_format(DEBUG_LOG_LEVEL, msg, args);\n}\n\npub fn trace_log_format(msg: str, args: [Field; N]) {\n log_format(TRACE_LOG_LEVEL, msg, args);\n}\n\nfn log_format(log_level: u8, msg: str, args: [Field; N]) {\n // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe\n // to call.\n unsafe { log_oracle_wrapper(log_level, msg, args) };\n}\n\nunconstrained fn log_oracle_wrapper(\n log_level: u8,\n msg: str,\n args: [Field; N],\n) {\n log_oracle(log_level, msg, N, args);\n}\n\n// While the length parameter might seem unnecessary given that we have N, we keep it around because at the AVM\n// bytecode level we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally\n// take that route. The AVM transpiler maps this oracle to the DEBUGLOG opcode, which reads the fields size from memory.\n#[oracle(aztec_utl_log)]\nunconstrained fn log_oracle(\n log_level: u8,\n msg: str,\n length: u32,\n args: [Field; N],\n) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/logging.nr","function_locations":[{"start":395,"name":"fatal_log"},{"start":473,"name":"error_log"},{"start":550,"name":"warn_log"},{"start":626,"name":"info_log"},{"start":705,"name":"verbose_log"},{"start":785,"name":"debug_log"},{"start":863,"name":"trace_log"},{"start":1033,"name":"fatal_log_format"},{"start":1161,"name":"error_log_format"},{"start":1288,"name":"warn_log_format"},{"start":1414,"name":"info_log_format"},{"start":1543,"name":"verbose_log_format"},{"start":1673,"name":"debug_log_format"},{"start":1801,"name":"trace_log_format"},{"start":1934,"name":"log_format"},{"start":2248,"name":"log_oracle_wrapper"},{"start":2801,"name":"log_oracle"}]},"376":{"source":"use crate::constants::TWO_POW_64;\nuse crate::traits::{Deserialize, Serialize};\nuse std::meta::derive;\n// NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr\n// It exists as we sometimes need to perform custom absorption, but the stdlib version\n// has a private absorb() method (it's also designed to just be a hasher)\n// Can be removed when standalone noir poseidon lib exists: See noir#6679\n// TODO: Poseidon is stand-alone now\n\nglobal RATE: u32 = 3;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct Poseidon2Sponge {\n pub cache: [Field; 3],\n pub state: [Field; 4],\n pub cache_size: u32,\n pub squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2Sponge {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2Sponge::hash_internal(input, message_size, message_size != N)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2Sponge {\n let mut result =\n Poseidon2Sponge { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n for i in 0..RATE {\n // We effectively zero-pad the cache by only adding to the state\n // cache that is less than the specified `cache_size`\n if i < self.cache_size {\n self.state[i] += self.cache[i];\n }\n }\n self.state = std::hash::poseidon2_permutation(self.state);\n }\n\n pub fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n pub fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(\n input: [Field; N],\n in_len: u32,\n is_variable_length: bool,\n ) -> Field {\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n for i in 0..input.len() {\n if i < in_len {\n sponge.absorb(input[i]);\n }\n }\n\n sponge.squeeze()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr","function_locations":[{"start":798,"name":"Poseidon2Sponge::hash"},{"start":938,"name":"Poseidon2Sponge::new"},{"start":1151,"name":"Poseidon2Sponge::perform_duplex"},{"start":1592,"name":"Poseidon2Sponge::absorb"},{"start":2126,"name":"Poseidon2Sponge::squeeze"},{"start":2544,"name":"Poseidon2Sponge::hash_internal"}]},"395":{"source":"use crate::utils::field::field_from_bytes;\n\npub trait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n #[inline_always]\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for bool {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u8 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u16 {\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u32 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u64 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u128 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for str {\n #[inline_always]\n fn to_field(self) -> Field {\n assert(N < 32, \"String doesn't fit in a field, consider using Serialize instead\");\n field_from_bytes(self.as_bytes(), true)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/traits/to_field.nr","function_locations":[{"start":176,"name":"::to_field"},{"start":276,"name":"::to_field"},{"start":382,"name":"::to_field"},{"start":468,"name":"::to_field"},{"start":575,"name":"::to_field"},{"start":682,"name":"::to_field"},{"start":790,"name":"::to_field"},{"start":912,"name":">::to_field"}]},"403":{"source":"pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n\n// Convert a 32 byte array to a field element by truncating the final byte\npub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..15 {\n // covers bytes 16..30 (31 is truncated and ignored)\n low = low + (bytes32[15 + 15 - i] as Field) * v;\n v = v * 256;\n // covers bytes 0..14\n high = high + (bytes32[14 - i] as Field) * v;\n }\n // covers byte 15\n low = low + (bytes32[15] as Field) * v;\n\n low + high * v\n}\n\npub fn min(f1: Field, f2: Field) -> Field {\n if f1.lt(f2) {\n f1\n } else {\n f2\n }\n}\n\n// TODO: write doc-comments and tests for these magic constants.\n\nglobal KNOWN_NON_RESIDUE: Field = 5; // This is a non-residue in Noir's native Field.\nglobal C1: u32 = 28;\nglobal C3: Field = 40770029410420498293352137776570907027550720424234931066070132305055;\nglobal C5: Field = 19103219067921713944291392827692070036145651957329286315305642004821462161904;\n\n// @dev: only use this for _huge_ exponents y, when writing a constrained function.\n// If you're only exponentiating by a small value, first consider writing-out the multiplications by hand.\n// Only after you've measured the gates of that approach, consider using the native Field::pow_32 function.\n// Only if your exponent is larger than 32 bits, resort to using this function.\npub fn pow(x: Field, y: Field) -> Field {\n let mut r = 1 as Field;\n let b: [bool; 254] = y.to_le_bits();\n\n for i in 0..254 {\n r *= r;\n r *= (b[254 - 1 - i] as Field) * x + (1 - b[254 - 1 - i] as Field);\n }\n\n r\n}\n\n/// Returns Option::some(sqrt) if there is a square root, and Option::none() if there isn't.\npub fn sqrt(x: Field) -> Option {\n // Safety: if the hint returns the square root of x, then we simply square it\n // check the result equals x. If x is not square, we return a value that\n // enables us to prove that fact (see the `else` clause below).\n let (is_sq, maybe_sqrt) = unsafe { __sqrt(x) };\n\n if is_sq {\n let sqrt = maybe_sqrt;\n validate_sqrt_hint(x, sqrt);\n Option::some(sqrt)\n } else {\n let not_sqrt_hint = maybe_sqrt;\n validate_not_sqrt_hint(x, not_sqrt_hint);\n Option::none()\n }\n}\n\n// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.\nunconstrained fn is_square(x: Field) -> bool {\n let v = pow(x, -1 / 2);\n v * (v - 1) == 0\n}\n\n// Tonelli-Shanks algorithm for computing the square root of a Field element.\n// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field\n// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),\n// and C5 = ZETA^C2, where ZETA is a non-square element of Field.\n// These are pre-computed above as globals.\nunconstrained fn tonelli_shanks_sqrt(x: Field) -> Field {\n let mut z = pow(x, C3);\n let mut t = z * z * x;\n z *= x;\n let mut b = t;\n let mut c = C5;\n\n for i in 0..(C1 - 1) {\n for _j in 1..(C1 - i - 1) {\n b *= b;\n }\n\n z *= if b == 1 { 1 } else { c };\n\n c *= c;\n\n t *= if b == 1 { 1 } else { c };\n\n b = t;\n }\n\n z\n}\n\n// NB: this doesn't return an option, because in the case of there _not_ being a square root, we still want to return a field element that allows us to then assert in the _constrained_ sqrt function that there is no sqrt.\nunconstrained fn __sqrt(x: Field) -> (bool, Field) {\n let is_sq = is_square(x);\n if is_sq {\n let sqrt = tonelli_shanks_sqrt(x);\n (true, sqrt)\n } else {\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // sq * sq = sq // 1 * 1 = 1\n // non-sq * non-sq = sq // -1 * -1 = 1\n // sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n let not_sqrt = tonelli_shanks_sqrt(demo_x_not_square);\n (false, not_sqrt)\n }\n}\n\nfn validate_sqrt_hint(x: Field, hint: Field) {\n assert(hint * hint == x, f\"The claimed_sqrt {hint} is not the sqrt of x {x}\");\n}\n\nfn validate_not_sqrt_hint(x: Field, hint: Field) {\n // We need this assertion, because x = 0 would pass the other assertions in this\n // function, and we don't want people to be able to prove that 0 is not square!\n assert(x != 0, \"0 has a square root; you cannot claim it is not square\");\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n //\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // 1. sq * sq = sq // 1 * 1 = 1\n // 2. non-sq * non-sq = sq // -1 * -1 = 1\n // 3. sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n //\n // We want to demonstrate that this below multiplication falls under bullet-point (2):\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n // I.e. we want to demonstrate that `demo_x_not_square` has Legendre symbol 1\n // (i.e. that it is a square), so we prove that it is square below.\n // Why do we want to prove that it has LS 1?\n // Well, since it was computed with a known-non-residue, its squareness implies we're\n // in case 2 (something multiplied by a known-non-residue yielding a result which\n // has a LS of 1), which implies that x must be a non-square. The unconstrained\n // function gave us the sqrt of demo_x_not_square, so all we need to do is\n // assert its squareness:\n assert(\n hint * hint == demo_x_not_square,\n f\"The hint {hint} does not demonstrate that {x} is not a square\",\n );\n}\n\n#[test]\nunconstrained fn bytes_field_test() {\n // Tests correctness of field_from_bytes_32_trunc against existing methods\n // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7\n let inputs = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167,\n ];\n let field = field_from_bytes(inputs, true);\n let return_bytes: [u8; 31] = field.to_be_bytes();\n assert_eq(inputs, return_bytes);\n // 32 bytes - we remove the final byte, and check it matches the field\n let inputs2 = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158,\n ];\n let field2 = field_from_bytes_32_trunc(inputs2);\n let return_bytes2: [u8; 31] = field2.to_be_bytes();\n\n assert_eq(return_bytes2, return_bytes);\n assert_eq(field2, field);\n}\n\n#[test]\nunconstrained fn max_field_test() {\n // Tests the hardcoded value in constants.nr vs underlying modulus\n // NB: We can't use 0-1 in constants.nr as it will be transpiled incorrectly to ts and sol constants files\n let max_value = crate::constants::MAX_FIELD_VALUE;\n assert_eq(max_value, 0 - 1);\n // modulus == 0 is tested elsewhere, so below is more of a sanity check\n let max_bytes: [u8; 32] = max_value.to_be_bytes();\n let mod_bytes = std::field::modulus_be_bytes();\n for i in 0..31 {\n assert_eq(max_bytes[i], mod_bytes[i]);\n }\n assert_eq(max_bytes[31], mod_bytes[31] - 1);\n}\n\n#[test]\nunconstrained fn sqrt_valid_test() {\n let x = 16; // examples: 16, 9, 25, 81\n let result = sqrt(x);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), x);\n}\n\n#[test]\nunconstrained fn sqrt_invalid_test() {\n let x = KNOWN_NON_RESIDUE; // has no square root in the field\n let result = sqrt(x);\n assert(result.is_none());\n}\n\n#[test]\nunconstrained fn sqrt_zero_test() {\n let result = sqrt(0);\n assert(result.is_some());\n assert_eq(result.unwrap(), 0);\n}\n\n#[test]\nunconstrained fn sqrt_one_test() {\n let result = sqrt(1);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), 1);\n}\n\n#[test]\nunconstrained fn field_from_bytes_empty_test() {\n let empty: [u8; 0] = [];\n let result = field_from_bytes(empty, true);\n assert_eq(result, 0);\n\n let result_le = field_from_bytes(empty, false);\n assert_eq(result_le, 0);\n}\n\n#[test]\nunconstrained fn field_from_bytes_little_endian_test() {\n // Test little-endian conversion: [0x01, 0x02] should be 0x0201 = 513\n let bytes = [0x01, 0x02];\n let result_le = field_from_bytes(bytes, false);\n assert_eq(result_le, 0x0201);\n\n // Compare with big-endian: [0x01, 0x02] should be 0x0102 = 258\n let result_be = field_from_bytes(bytes, true);\n assert_eq(result_be, 0x0102);\n}\n\n#[test]\nunconstrained fn pow_test() {\n assert_eq(pow(2, 0), 1);\n assert_eq(pow(2, 1), 2);\n assert_eq(pow(2, 10), 1024);\n assert_eq(pow(3, 5), 243);\n assert_eq(pow(0, 5), 0);\n assert_eq(pow(1, 100), 1);\n}\n\n#[test]\nunconstrained fn min_test() {\n assert_eq(min(5, 10), 5);\n assert_eq(min(10, 5), 5);\n assert_eq(min(7, 7), 7);\n assert_eq(min(0, 1), 0);\n}\n\n#[test]\nunconstrained fn sqrt_has_two_roots_test() {\n // Every square has two roots: r and -r (i.e., p - r)\n // sqrt(16) can return 4 or -4\n let x = 16;\n let result = sqrt(x).unwrap();\n assert(result * result == x);\n // The other root is -result\n let other_root = 0 - result;\n assert(other_root * other_root == x);\n // Verify they are different (unless x = 0)\n assert(result != other_root);\n\n // Same for 9: roots are 3 and -3\n let y = 9;\n let result_y = sqrt(y).unwrap();\n assert(result_y * result_y == y);\n let other_root_y = 0 - result_y;\n assert(other_root_y * other_root_y == y);\n assert(result_y != other_root_y);\n}\n\n#[test]\nunconstrained fn sqrt_negative_one_test() {\n let x = 0 - 1;\n let result = sqrt(x);\n assert(result.unwrap() == 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636);\n}\n\n#[test]\nunconstrained fn validate_sqrt_hint_valid_test() {\n // 4 is a valid sqrt of 16\n validate_sqrt_hint(16, 4);\n // -4 is also a valid sqrt of 16\n validate_sqrt_hint(16, 0 - 4);\n // 0 is a valid sqrt of 0\n validate_sqrt_hint(0, 0);\n // 1 is a valid sqrt of 1\n validate_sqrt_hint(1, 1);\n // -1 is also a valid sqrt of 1\n validate_sqrt_hint(1, 0 - 1);\n}\n\n#[test(should_fail_with = \"is not the sqrt of x\")]\nunconstrained fn validate_sqrt_hint_invalid_test() {\n // 5 is not a valid sqrt of 16\n validate_sqrt_hint(16, 5);\n}\n\n#[test]\nunconstrained fn validate_not_sqrt_hint_valid_test() {\n // 5 (KNOWN_NON_RESIDUE) is not a square.\n let x = KNOWN_NON_RESIDUE;\n let hint = tonelli_shanks_sqrt(x * KNOWN_NON_RESIDUE);\n validate_not_sqrt_hint(x, hint);\n}\n\n#[test(should_fail_with = \"0 has a square root\")]\nunconstrained fn validate_not_sqrt_hint_zero_test() {\n // 0 has a square root, so we cannot claim it is not square\n validate_not_sqrt_hint(0, 0);\n}\n\n#[test(should_fail_with = \"does not demonstrate that\")]\nunconstrained fn validate_not_sqrt_hint_wrong_hint_test() {\n // Provide a wrong hint for a non-square\n let x = KNOWN_NON_RESIDUE;\n validate_not_sqrt_hint(x, 123);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr","function_locations":[{"start":79,"name":"field_from_bytes"},{"start":553,"name":"field_from_bytes_32_trunc"},{"start":1054,"name":"min"},{"start":1899,"name":"pow"},{"start":2233,"name":"sqrt"},{"start":2915,"name":"is_square"},{"start":3343,"name":"tonelli_shanks_sqrt"},{"start":3951,"name":"__sqrt"},{"start":4795,"name":"validate_sqrt_hint"},{"start":4932,"name":"validate_not_sqrt_hint"},{"start":6570,"name":"bytes_field_test"},{"start":7553,"name":"max_field_test"},{"start":8177,"name":"sqrt_valid_test"},{"start":8379,"name":"sqrt_invalid_test"},{"start":8548,"name":"sqrt_zero_test"},{"start":8685,"name":"sqrt_one_test"},{"start":8854,"name":"field_from_bytes_empty_test"},{"start":9107,"name":"field_from_bytes_little_endian_test"},{"start":9492,"name":"pow_test"},{"start":9715,"name":"min_test"},{"start":9889,"name":"sqrt_has_two_roots_test"},{"start":10562,"name":"sqrt_negative_one_test"},{"start":10768,"name":"validate_sqrt_hint_valid_test"},{"start":11199,"name":"validate_sqrt_hint_invalid_test"},{"start":11331,"name":"validate_not_sqrt_hint_valid_test"},{"start":11611,"name":"validate_not_sqrt_hint_zero_test"},{"start":11828,"name":"validate_not_sqrt_hint_wrong_hint_test"}]},"409":{"source":"pub struct Reader {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Reader {\n pub fn new(data: [Field; N]) -> Self {\n Self { data, offset: 0 }\n }\n\n pub fn read(&mut self) -> Field {\n let result = self.data[self.offset];\n self.offset += 1;\n result\n }\n\n pub fn read_u32(&mut self) -> u32 {\n self.read() as u32\n }\n\n pub fn read_u64(&mut self) -> u64 {\n self.read() as u64\n }\n\n pub fn read_bool(&mut self) -> bool {\n self.read() != 0\n }\n\n pub fn read_array(&mut self) -> [Field; K] {\n let mut result = [0; K];\n for i in 0..K {\n result[i] = self.data[self.offset + i];\n }\n self.offset += K;\n result\n }\n\n pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T {\n let result = deserialise(self.read_array());\n result\n }\n\n pub fn read_struct_array(\n &mut self,\n deserialise: fn([Field; K]) -> T,\n mut result: [T; C],\n ) -> [T; C] {\n for i in 0..C {\n result[i] = self.read_struct(deserialise);\n }\n result\n }\n\n pub fn peek_offset(&mut self, offset: u32) -> Field {\n self.data[self.offset + offset]\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) {\n assert_eq(self.offset, self.data.len(), \"Reader did not read all data\");\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/reader.nr","function_locations":[{"start":144,"name":"Reader::new"},{"start":222,"name":"Reader::read"},{"start":355,"name":"Reader::read_u32"},{"start":429,"name":"Reader::read_u64"},{"start":505,"name":"Reader::read_bool"},{"start":598,"name":"Reader::read_array"},{"start":855,"name":"Reader::read_struct"},{"start":1094,"name":"Reader::read_struct_array"},{"start":1263,"name":"Reader::peek_offset"},{"start":1362,"name":"Reader::advance_offset"},{"start":1426,"name":"Reader::finish"}]},"410":{"source":"use crate::{reader::Reader, writer::Writer};\n\n/// Trait for serializing Noir types into arrays of Fields.\n///\n/// An implementation of the Serialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait (and Deserialize) are\n/// typically used to communicate between Noir and TypeScript (via oracles and function arguments).\n///\n/// # On Following Noir's Intrinsic Serialization\n/// When calling a Noir function from TypeScript (TS), first the function arguments are serialized into an array\n/// of fields. This array is then included in the initial witness. Noir's intrinsic serialization is then used\n/// to deserialize the arguments from the witness. When the same Noir function is called from Noir this Serialize trait\n/// is used instead of the serialization in TS. For this reason we need to have a match between TS serialization,\n/// Noir's intrinsic serialization and the implementation of this trait. If there is a mismatch, the function calls\n/// fail with an arguments hash mismatch error message.\n///\n/// # Associated Constants\n/// * `N` - The length of the output Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Serialize for str {\n/// let N: u32 = N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// let bytes = self.as_bytes();\n/// for i in 0..bytes.len() {\n/// writer.write(bytes[i] as Field);\n/// }\n/// }\n/// }\n/// ```\n#[derive_via(derive_serialize)]\npub trait Serialize {\n let N: u32;\n\n fn serialize(self) -> [Field; Self::N];\n\n fn stream_serialize(self, writer: &mut Writer);\n}\n\n/// Generates a `Serialize` trait implementation for a struct type.\n///\n/// # Parameters\n/// - `s`: The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A quoted code block containing the trait implementation\n///\n/// # Example\n/// For a struct defined as:\n/// ```\n/// struct Log {\n/// fields: [Field; N],\n/// length: u32\n/// }\n/// ```\n///\n/// This function generates code equivalent to:\n/// ```\n/// impl Serialize for Log {\n/// let N: u32 = <[Field; N] as Serialize>::N + ::N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// #[inline_always]\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// Serialize::stream_serialize(self.fields, writer);\n/// Serialize::stream_serialize(self.length, writer);\n/// }\n/// }\n/// ```\npub comptime fn derive_serialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n\n // We care only about the name and type so we drop the last item of the tuple\n let params = nested_struct.0.fields(nested_struct.1).map(|(name, typ, _)| (name, typ));\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Serialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_serialize_clause = get_where_trait_clause(s, quote {Serialize});\n\n let params_len_quote = get_params_len_quote(params);\n\n let function_body = params\n .map(|(name, _typ): (Quoted, Type)| {\n quote {\n $crate::serialization::Serialize::stream_serialize(self.$name, writer);\n }\n })\n .join(quote {});\n\n quote {\n impl$generics_declarations $crate::serialization::Serialize for $typ\n $where_serialize_clause\n {\n let N: u32 = $params_len_quote;\n\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n $crate::serialization::Serialize::stream_serialize(self, &mut writer);\n writer.finish()\n }\n\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n $function_body\n }\n }\n }\n}\n\n/// Trait for deserializing Noir types from arrays of Fields.\n///\n/// An implementation of the Deserialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait is typically used when\n/// deserializing return values from function calls in Noir. Since the same function could be called from TypeScript\n/// (TS), in which case the TS deserialization would get used, we need to have a match between the 2.\n///\n/// # Associated Constants\n/// * `N` - The length of the input Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Deserialize for str {\n/// let N: u32 = M;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let mut bytes = [0 as u8; M];\n/// for i in 0..M {\n/// bytes[i] = reader.read() as u8;\n/// }\n/// str::::from(bytes)\n/// }\n/// }\n/// ```\n#[derive_via(derive_deserialize)]\npub trait Deserialize {\n let N: u32;\n\n fn deserialize(fields: [Field; Self::N]) -> Self;\n\n fn stream_deserialize(reader: &mut Reader) -> Self;\n}\n\n/// Generates a `Deserialize` trait implementation for a given struct `s`.\n///\n/// # Arguments\n/// * `s` - The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A `Quoted` block containing the generated trait implementation\n///\n/// # Requirements\n/// Each struct member type must implement the `Deserialize` trait (it gets used in the generated code).\n///\n/// # Example\n/// For a struct like:\n/// ```\n/// struct MyStruct {\n/// x: AztecAddress,\n/// y: Field,\n/// }\n/// ```\n///\n/// This generates:\n/// ```\n/// impl Deserialize for MyStruct {\n/// let N: u32 = ::N + ::N;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// #[inline_always]\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let x = ::stream_deserialize(reader);\n/// let y = ::stream_deserialize(reader);\n/// Self { x, y }\n/// }\n/// }\n/// ```\npub comptime fn derive_deserialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n let params = nested_struct.0.fields(nested_struct.1);\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Deserialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_deserialize_clause = get_where_trait_clause(s, quote {Deserialize});\n\n // The following will give us:\n // ::N + ::N + ...\n // (or 0 if the struct has no members)\n let right_hand_side_of_definition_of_n = if params.len() > 0 {\n params\n .map(|(_, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n <$param_type as $crate::serialization::Deserialize>::N\n }\n })\n .join(quote {+})\n } else {\n quote {0}\n };\n\n // For structs containing a single member, we can enhance performance by directly deserializing the input array,\n // bypassing the need for loop-based array construction. While this optimization yields significant benefits in\n // Brillig where the loops are expected to not be optimized, it is not relevant in ACIR where the loops are\n // expected to be optimized away.\n let function_body = if params.len() > 1 {\n // This generates deserialization code for each struct member and concatenates them together.\n let deserialization_of_struct_members = params\n .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n let $param_name = <$param_type as Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote {});\n\n // We join the struct member names with a comma to be used in the `Self { ... }` syntax\n // This will give us e.g. `a, b, c` for a struct with three fields named `a`, `b`, and `c`.\n let struct_members = params\n .map(|(param_name, _, _): (Quoted, Type, Quoted)| quote { $param_name })\n .join(quote {,});\n\n quote {\n $deserialization_of_struct_members\n\n Self { $struct_members }\n }\n } else if params.len() == 1 {\n let param_name = params[0].0;\n quote {\n Self { $param_name: $crate::serialization::Deserialize::stream_deserialize(reader) }\n }\n } else {\n quote {\n Self {}\n }\n };\n\n quote {\n impl$generics_declarations $crate::serialization::Deserialize for $typ\n $where_deserialize_clause\n {\n let N: u32 = $right_hand_side_of_definition_of_n;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $function_body\n }\n }\n }\n}\n\n/// Generates a quoted expression that computes the total serialized length of function parameters.\n///\n/// # Parameters\n/// * `params` - An array of tuples where each tuple contains a quoted parameter name and its Type. The type needs\n/// to implement the Serialize trait.\n///\n/// # Returns\n/// A quoted expression that evaluates to:\n/// * `0` if there are no parameters\n/// * `(::N + ::N + ...)` for one or more parameters\ncomptime fn get_params_len_quote(params: [(Quoted, Type)]) -> Quoted {\n if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::serialization::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n }\n}\n\ncomptime fn get_generics_declarations(s: TypeDefinition) -> Quoted {\n let generics = s.generics();\n\n if generics.len() > 0 {\n let generics_declarations_items = generics\n .map(|(name, maybe_integer_typ)| {\n // The second item in the generics tuple is an Option of an integer type that is Some only if\n // the generic is numeric.\n if maybe_integer_typ.is_some() {\n // The generic is numeric, so we return a quote defined as e.g. \"let N: u32\"\n let integer_type = maybe_integer_typ.unwrap();\n quote {let $name: $integer_type}\n } else {\n // The generic is not numeric, so we return a quote containing the name of the generic (e.g. \"T\")\n quote {$name}\n }\n })\n .join(quote {,});\n quote {<$generics_declarations_items>}\n } else {\n // The struct doesn't have any generics defined, so we just return an empty quote.\n quote {}\n }\n}\n\ncomptime fn get_where_trait_clause(s: TypeDefinition, trait_name: Quoted) -> Quoted {\n let generics = s.generics();\n\n // The second item in the generics tuple is an Option of an integer type that is Some only if the generic is\n // numeric.\n let non_numeric_generics =\n generics.filter(|(_, maybe_integer_typ)| maybe_integer_typ.is_none());\n\n if non_numeric_generics.len() > 0 {\n let non_numeric_generics_declarations =\n non_numeric_generics.map(|(name, _)| quote {$name: $trait_name}).join(quote {,});\n quote {where $non_numeric_generics_declarations}\n } else {\n // There are no non-numeric generics, so we return an empty quote.\n quote {}\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/serialization.nr","function_locations":[{"start":3018,"name":"derive_serialize"},{"start":7206,"name":"derive_deserialize"},{"start":10928,"name":"get_params_len_quote"},{"start":11387,"name":"get_generics_declarations"},{"start":12469,"name":"get_where_trait_clause"}]},"412":{"source":"use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};\nuse std::embedded_curve_ops::EmbeddedCurvePoint;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\nglobal BOOL_SERIALIZED_LEN: u32 = 1;\nglobal U8_SERIALIZED_LEN: u32 = 1;\nglobal U16_SERIALIZED_LEN: u32 = 1;\nglobal U32_SERIALIZED_LEN: u32 = 1;\nglobal U64_SERIALIZED_LEN: u32 = 1;\nglobal U128_SERIALIZED_LEN: u32 = 1;\nglobal FIELD_SERIALIZED_LEN: u32 = 1;\nglobal I8_SERIALIZED_LEN: u32 = 1;\nglobal I16_SERIALIZED_LEN: u32 = 1;\nglobal I32_SERIALIZED_LEN: u32 = 1;\nglobal I64_SERIALIZED_LEN: u32 = 1;\n\nimpl Serialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> bool {\n reader.read() != 0\n }\n}\n\nimpl Serialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8\n }\n}\n\nimpl Serialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16\n }\n}\n\nimpl Serialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32\n }\n}\n\nimpl Serialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64\n }\n}\n\nimpl Serialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u128\n }\n}\n\nimpl Serialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self);\n }\n}\n\nimpl Deserialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read()\n }\n}\n\nimpl Serialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u8 as Field);\n }\n}\n\nimpl Deserialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8 as i8\n }\n}\n\nimpl Serialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u16 as Field);\n }\n}\n\nimpl Deserialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16 as i16\n }\n}\n\nimpl Serialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u32 as Field);\n }\n}\n\nimpl Deserialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32 as i32\n }\n}\n\nimpl Serialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u64 as Field);\n }\n}\n\nimpl Deserialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64 as i64\n }\n}\n\nimpl Serialize for [T; M]\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n for i in 0..M {\n self[i].stream_serialize(writer);\n }\n }\n}\n\nimpl Deserialize for [T; M]\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut result: [T; M] = std::mem::zeroed();\n for i in 0..M {\n result[i] = T::stream_deserialize(reader);\n }\n result\n }\n}\n\nimpl Serialize for Option\nwhere\n T: Serialize,\n{\n let N: u32 = ::N + 1;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write_bool(self.is_some());\n if self.is_some() {\n self.unwrap_unchecked().stream_serialize(writer);\n } else {\n writer.advance_offset(::N);\n }\n }\n}\n\nimpl Deserialize for Option\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n if reader.read_bool() {\n Option::some(::stream_deserialize(reader))\n } else {\n reader.advance_offset(::N);\n Option::none()\n }\n }\n}\n\nglobal SCALAR_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurveScalar {\n\n let N: u32 = SCALAR_SIZE;\n\n fn serialize(self) -> [Field; SCALAR_SIZE] {\n [self.lo, self.hi]\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.lo);\n writer.write(self.hi);\n }\n}\n\nimpl Deserialize for EmbeddedCurveScalar {\n let N: u32 = SCALAR_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { lo: fields[0], hi: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { lo: reader.read(), hi: reader.read() }\n }\n}\n\nglobal POINT_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn serialize(self) -> [Field; Self::N] {\n [self.x, self.y]\n }\n\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.x);\n writer.write(self.y);\n }\n}\n\nimpl Deserialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { x: fields[0], y: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { x: reader.read(), y: reader.read() }\n }\n}\n\nimpl Deserialize for str {\n let N: u32 = M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);\n str::::from(u8_arr)\n }\n}\n\nimpl Serialize for str {\n let N: u32 = M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.as_bytes().stream_serialize(writer);\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Deserialize for BoundedVec\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut new_bounded_vec: BoundedVec = BoundedVec::new();\n let payload_len = Self::N - 1;\n\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n let len = reader.peek_offset(payload_len) as u32;\n\n for i in 0..M {\n if i < len {\n new_bounded_vec.push(::stream_deserialize(reader));\n }\n }\n\n // +1 for the length of the BoundedVec\n reader.advance_offset((M - len) * ::N + 1);\n\n new_bounded_vec\n }\n}\n\n// This may cause issues if used as program input, because noir disallows empty arrays for program input.\n// I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint\n// if someone does run into this in the future.\nimpl Deserialize for () {\n let N: u32 = 0;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(_reader: &mut Reader) -> Self {\n ()\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Serialize for BoundedVec\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M + 1; // +1 for the length of the BoundedVec\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.storage().stream_serialize(writer);\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n writer.write_u32(self.len() as u32);\n }\n}\n\n// Create a slice of the given length with each element made from `f(i)` where `i` is the current index\ncomptime fn make_slice(length: u32, f: fn[Env](u32) -> T) -> [T] {\n let mut slice = @[];\n for i in 0..length {\n slice = slice.push_back(f(i));\n }\n slice\n}\n\n// Implements Serialize and Deserialize for an arbitrary tuple type\ncomptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {\n // `T0`, `T1`, `T2`\n let type_names = make_slice(length, |i| f\"T{i}\".quoted_contents());\n\n // `result0`, `result1`, `result2`\n let result_names = make_slice(length, |i| f\"result{i}\".quoted_contents());\n\n // `T0, T1, T2`\n let field_generics = type_names.join(quote [,]);\n\n // `::N + ::N + ::N`\n let full_size_serialize = type_names\n .map(|type_name| quote {\n <$type_name as Serialize>::N\n })\n .join(quote [+]);\n\n // `::N + ::N + ::N`\n let full_size_deserialize = type_names\n .map(|type_name| quote {\n <$type_name as Deserialize>::N\n })\n .join(quote [+]);\n\n // `T0: Serialize, T1: Serialize, T2: Serialize,`\n let serialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Serialize,\n })\n .join(quote []);\n\n // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`\n let deserialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Deserialize,\n })\n .join(quote []);\n\n // Statements to serialize each field\n let serialized_fields = type_names\n .mapi(|i, _type_name| quote {\n $crate::serialization::Serialize::stream_serialize(self.$i, writer);\n })\n .join(quote []);\n\n // Statements to deserialize each field\n let deserialized_fields = type_names\n .mapi(|i, type_name| {\n let result_name = result_names[i];\n quote {\n let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote []);\n let deserialize_results = result_names.join(quote [,]);\n\n quote {\n impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {\n let N: u32 = $full_size_serialize;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n\n $serialized_fields\n }\n }\n\n impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {\n let N: u32 = $full_size_deserialize;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n \n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $deserialized_fields\n ($deserialize_results)\n }\n }\n }\n}\n\n// Keeping these manual impls. They are more efficient since they do not\n// require copying sub-arrays from any serialized arrays.\nimpl Serialize for (T1,)\nwhere\n T1: Serialize,\n{\n let N: u32 = ::N;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: crate::writer::Writer = crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.0.stream_serialize(writer);\n }\n}\n\nimpl Deserialize for (T1,)\nwhere\n T1: Deserialize,\n{\n let N: u32 = ::N;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n (::stream_deserialize(reader),)\n }\n}\n\n#[impl_serialize_for_tuple(2)]\n#[impl_serialize_for_tuple(3)]\n#[impl_serialize_for_tuple(4)]\n#[impl_serialize_for_tuple(5)]\n#[impl_serialize_for_tuple(6)]\nmod impls {\n use crate::serialization::{Deserialize, Serialize};\n}\n\n#[test]\nunconstrained fn bounded_vec_serialization() {\n // Test empty BoundedVec\n let empty_vec: BoundedVec = BoundedVec::from_array([]);\n let serialized = empty_vec.serialize();\n let deserialized = BoundedVec::::deserialize(serialized);\n assert_eq(empty_vec, deserialized);\n assert_eq(deserialized.len(), 0);\n\n // Test partially filled BoundedVec\n let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);\n let serialized = partial_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(partial_vec, deserialized);\n assert_eq(deserialized.len(), 1);\n assert_eq(deserialized.get(0), [1, 2]);\n\n // Test full BoundedVec\n let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);\n let serialized = full_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(full_vec, deserialized);\n assert_eq(deserialized.len(), 3);\n assert_eq(deserialized.get(0), [1, 2]);\n assert_eq(deserialized.get(1), [3, 4]);\n assert_eq(deserialized.get(2), [5, 6]);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/type_impls.nr","function_locations":[{"start":693,"name":"::serialize"},{"start":914,"name":"::stream_serialize"},{"start":1082,"name":"::deserialize"},{"start":1328,"name":"::stream_deserialize"},{"start":1470,"name":"::serialize"},{"start":1691,"name":"::stream_serialize"},{"start":1855,"name":"::deserialize"},{"start":2101,"name":"::stream_deserialize"},{"start":2246,"name":"::serialize"},{"start":2467,"name":"::stream_serialize"},{"start":2633,"name":"::deserialize"},{"start":2879,"name":"::stream_deserialize"},{"start":3025,"name":"::serialize"},{"start":3246,"name":"::stream_serialize"},{"start":3412,"name":"::deserialize"},{"start":3658,"name":"::stream_deserialize"},{"start":3804,"name":"::serialize"},{"start":4025,"name":"::stream_serialize"},{"start":4191,"name":"::deserialize"},{"start":4437,"name":"::stream_deserialize"},{"start":4585,"name":"::serialize"},{"start":4806,"name":"::stream_serialize"},{"start":4974,"name":"::deserialize"},{"start":5220,"name":"::stream_deserialize"},{"start":5371,"name":"::serialize"},{"start":5592,"name":"::stream_serialize"},{"start":5753,"name":"::deserialize"},{"start":5999,"name":"::stream_deserialize"},{"start":6136,"name":"::serialize"},{"start":6357,"name":"::stream_serialize"},{"start":6527,"name":"::deserialize"},{"start":6773,"name":"::stream_deserialize"},{"start":6924,"name":"::serialize"},{"start":7145,"name":"::stream_serialize"},{"start":7318,"name":"::deserialize"},{"start":7564,"name":"::stream_deserialize"},{"start":7717,"name":"::serialize"},{"start":7938,"name":"::stream_serialize"},{"start":8111,"name":"::deserialize"},{"start":8357,"name":"::stream_deserialize"},{"start":8510,"name":"::serialize"},{"start":8731,"name":"::stream_serialize"},{"start":8904,"name":"::deserialize"},{"start":9150,"name":"::stream_deserialize"},{"start":9350,"name":"::serialize"},{"start":9571,"name":"::stream_serialize"},{"start":9831,"name":"::deserialize"},{"start":10077,"name":"::stream_deserialize"},{"start":10389,"name":">::serialize"},{"start":10610,"name":">::stream_serialize"},{"start":10997,"name":">::deserialize"},{"start":11243,"name":">::stream_deserialize"},{"start":11621,"name":"::serialize"},{"start":11744,"name":"::stream_serialize"},{"start":11944,"name":"::deserialize"},{"start":12090,"name":"::stream_deserialize"},{"start":12297,"name":"::serialize"},{"start":12397,"name":"::stream_serialize"},{"start":12593,"name":"::deserialize"},{"start":12737,"name":"::stream_deserialize"},{"start":12916,"name":">::deserialize"},{"start":13162,"name":">::stream_deserialize"},{"start":13395,"name":">::serialize"},{"start":13616,"name":">::stream_serialize"},{"start":13997,"name":">::deserialize"},{"start":14243,"name":">::stream_deserialize"},{"start":15299,"name":"::deserialize"},{"start":15546,"name":"::stream_deserialize"},{"start":15911,"name":">::serialize"},{"start":16132,"name":">::stream_serialize"},{"start":16617,"name":"make_slice"},{"start":16867,"name":"impl_serialize_for_tuple"},{"start":20158,"name":"::serialize"},{"start":20409,"name":"::stream_serialize"},{"start":20616,"name":"::deserialize"},{"start":20877,"name":"::stream_deserialize"},{"start":21226,"name":"bounded_vec_serialization"}]},"413":{"source":"pub struct Writer {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Writer {\n pub fn new() -> Self {\n Self { data: [0; N], offset: 0 }\n }\n\n pub fn write(&mut self, value: Field) {\n self.data[self.offset] = value;\n self.offset += 1;\n }\n\n pub fn write_u32(&mut self, value: u32) {\n self.write(value as Field);\n }\n\n pub fn write_u64(&mut self, value: u64) {\n self.write(value as Field);\n }\n\n pub fn write_bool(&mut self, value: bool) {\n self.write(value as Field);\n }\n\n pub fn write_array(&mut self, value: [Field; K]) {\n for i in 0..K {\n self.data[i + self.offset] = value[i];\n }\n self.offset += K;\n }\n\n pub fn write_struct(&mut self, value: T, serialize: fn(T) -> [Field; K]) {\n self.write_array(serialize(value));\n }\n\n pub fn write_struct_array(\n &mut self,\n value: [T; C],\n serialize: fn(T) -> [Field; K],\n ) {\n for i in 0..C {\n self.write_struct(value[i], serialize);\n }\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) -> [Field; N] {\n assert_eq(self.offset, self.data.len(), \"Writer did not write all data\");\n self.data\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/writer.nr","function_locations":[{"start":128,"name":"Writer::new"},{"start":220,"name":"Writer::write"},{"start":339,"name":"Writer::write_u32"},{"start":428,"name":"Writer::write_u64"},{"start":519,"name":"Writer::write_bool"},{"start":629,"name":"Writer::write_array"},{"start":841,"name":"Writer::write_struct"},{"start":1040,"name":"Writer::write_struct_array"},{"start":1185,"name":"Writer::advance_offset"},{"start":1263,"name":"Writer::finish"}]}}} \ No newline at end of file diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots.rs b/noir-projects/noir-contract-snapshots/tests/snapshots.rs new file mode 100644 index 000000000000..a0702d6009f2 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots.rs @@ -0,0 +1,107 @@ +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn manifest_dir() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) +} + +/// `noir-projects/noir-contract-snapshots/` → repo root. +fn repo_root() -> PathBuf { + manifest_dir() + .parent() + .unwrap() + .parent() + .unwrap() + .to_path_buf() +} + +fn nargo_path() -> PathBuf { + let raw = std::env::var("NARGO") + .map(PathBuf::from) + .unwrap_or_else(|_| manifest_dir().join("../../noir/noir-repo/target/release/nargo")); + if raw.is_absolute() { + raw + } else { + manifest_dir().join(raw) + } +} + +fn nargo(dir: &Path) -> Command { + let mut cmd = Command::new(nargo_path()); + cmd.current_dir(dir); + cmd +} + +/// Scrubs nargo stderr before snapshotting: +/// +/// 1. Drops `Waiting for lock on git dependencies cache...` lines that nargo +/// emits when concurrent test invocations contend on its git-deps cache. +/// 2. Replaces the absolute repo prefix with `` so call-stack lines +/// pointing into `aztec-nr/aztec/src/macros/...` are stable across machines. +fn scrub_stderr(s: String) -> String { + let prefix = format!("{}/", repo_root().display()); + s.lines() + .filter(|l| !l.contains("Waiting for lock")) + .map(|l| l.replace(&prefix, "/")) + .collect::>() + .join("\n") +} + +/// Asserts `nargo compile` fails for `dir` and snapshots scrubbed stderr +fn run_compile_failure(name: &str, dir: PathBuf) { + let out = nargo(&dir) + .args(["compile", "--silence-warnings"]) + .output() + .unwrap_or_else(|e| panic!("could not invoke nargo at {:?}: {e}", nargo_path())); + assert!( + !out.status.success(), + "{name} unexpectedly compiled successfully" + ); + let stderr = scrub_stderr(String::from_utf8(out.stderr).expect("nargo stderr should be utf-8")); + insta::with_settings!({ snapshot_path => format!("snapshots/compile_failure/{name}") }, { + insta::assert_snapshot!("stderr", stderr); + }); +} + +/// Asserts `nargo compile` succeeds for `dir` and snapshots stderr +/// (typically empty, but captures any warnings nargo emits despite +/// `--silence-warnings`). Used for contracts that exist purely to track a +/// regression. If the test ever starts failing, the case must be moved to +/// `compile_failure/`. +fn run_compile_success(name: &str, dir: PathBuf) { + let out = nargo(&dir) + .args(["compile", "--silence-warnings"]) + .output() + .unwrap_or_else(|e| panic!("could not invoke nargo at {:?}: {e}", nargo_path())); + if !out.status.success() { + panic!( + "{name} unexpectedly failed to compile:\n--- stderr ---\n{}", + String::from_utf8_lossy(&out.stderr) + ); + } + let stderr = scrub_stderr(String::from_utf8(out.stderr).expect("nargo stderr should be utf-8")); + insta::with_settings!({ snapshot_path => format!("snapshots/compile_success/{name}") }, { + insta::assert_snapshot!("stderr", stderr); + }); +} + +/// Runs `nargo expand` in `dir` and snapshots stdout verbatim. The expanded +/// source has no path references, so no scrubbing is needed. +fn run_expand(name: &str, dir: PathBuf) { + let out = nargo(&dir) + .arg("expand") + .output() + .unwrap_or_else(|e| panic!("could not invoke nargo at {:?}: {e}", nargo_path())); + if !out.status.success() { + panic!( + "{name} expand failed:\n--- stderr ---\n{}", + String::from_utf8_lossy(&out.stderr) + ); + } + let stdout = String::from_utf8(out.stdout).expect("nargo stdout should be utf-8"); + insta::with_settings!({ snapshot_path => format!("snapshots/expand/{name}") }, { + insta::assert_snapshot!("expanded", stdout); + }); +} + +include!(concat!(env!("OUT_DIR"), "/tests.rs")); diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..4ba03004fab3 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[allow_phase_change] attribute can only be applied to #[external("private")] functions - foo is not + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:11:5 + 2: allow_phase_change + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:166:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..8d21b0bec8f5 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[allow_phase_change] attribute cannot be applied to #[external("utility")] functions - foo + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:9:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:355:9 + 3: assert_valid_utility + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:505:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap new file mode 100644 index 000000000000..de4879598429 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap @@ -0,0 +1,67 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Trait crate::authwit::authorization_interface::AuthorizationInterface not found + ┌─ /noir-projects/aztec-nr/aztec/src/macros/authorization.nr:36:43 + │ +36 │ let authorization_interface = quote { crate::authwit::authorization_interface::AuthorizationInterface }; + │ --------------------------------------------------------------- + │ + ┌─ src/main.nr:24:5 + │ +24 │ #[authorization] + │ ---------------- While running this function attribute + │ + +error: Could not resolve 'authwit' in path + ┌─ /noir-projects/aztec-nr/aztec/src/macros/authorization.nr:37:54 + │ +37 │ let authorization_selector_type = quote { crate::authwit::AuthorizationSelector }; + │ ------- + │ + ┌─ src/main.nr:24:5 + │ +24 │ #[authorization] + │ ---------------- While running this function attribute + │ + +error: check_trait_impl_where_clause_matches_trait_where_clause: missing trait ID + ┌─ /noir-projects/aztec-nr/aztec/src/macros/authorization.nr:23:16 + │ +23 │ let name = s.name(); + │ -------- + │ + ┌─ src/main.nr:24:5 + │ +24 │ #[authorization] + │ ---------------- While running this function attribute + │ + +error: check_trait_impl_method_matches_declaration: missing trait impl + ┌─ /noir-projects/aztec-nr/aztec/src/macros/authorization.nr:42:16 + │ +42 │ fn get_authorization_selector(self) -> $authorization_selector_type { + │ -------------------------- + │ + ┌─ src/main.nr:24:5 + │ +24 │ #[authorization] + │ ---------------- While running this function attribute + │ + +error: Selector collision detected between authorizations 'EventCollision8370082250' and 'EventCollision' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: AuthorizationSelectorCollision::#[authorization] + at src/main.nr:27:5 + 2: authorization + at /noir-projects/aztec-nr/aztec/src/macros/authorization.nr:65:5 + 3: register_authorization + at /noir-projects/aztec-nr/aztec/src/macros/authorization.nr:15:9 + +Aborting due to 5 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap new file mode 100644 index 000000000000..d41d90c9c38b --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap @@ -0,0 +1,27 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Argument from in function foo must be of type AztecAddress, but is of type Field + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:4:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21 + 3: process_functions + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9 + 4: [T]::map + at std/vector.nr:67:33 + 5: process_functions + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41 + 6: generate_public_external + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9 + 7: create_authorize_once_check + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:72:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap new file mode 100644 index 000000000000..83939084f7a4 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap @@ -0,0 +1,27 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Function foo does not have a from parameter. Please specify which one to use in #[authorize_once("...", "authwit_nonce")] + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:4:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21 + 3: process_functions + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9 + 4: [T]::map + at std/vector.nr:67:33 + 5: process_functions + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41 + 6: generate_public_external + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9 + 7: create_authorize_once_check + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:67:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap new file mode 100644 index 000000000000..b0a19e34e8cc --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap @@ -0,0 +1,27 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Function foo does not have a authwit_nonce. Please specify which one to use in #[authorize_once("from", "...")] + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:4:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21 + 3: process_functions + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9 + 4: [T]::map + at std/vector.nr:67:33 + 5: process_functions + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41 + 6: generate_public_external + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9 + 7: create_authorize_once_check + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:81:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap new file mode 100644 index 000000000000..d2e4063624a2 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap @@ -0,0 +1,27 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Argument authwit_nonce in function foo must be of type Field, but is of type u64 + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:4:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:97:21 + 3: process_functions + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:9 + 4: [T]::map + at std/vector.nr:67:33 + 5: process_functions + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/mod.nr:46:41 + 6: generate_public_external + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr:97:9 + 7: create_authorize_once_check + at /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr:86:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..856129ff8810 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[authorize_once] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:14:5 + 2: authorize_once + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:320:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..8272342aa1d6 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[authorize_once] attribute cannot be applied to #[external("utility")] functions - foo + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:12:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:355:9 + 3: assert_valid_utility + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:470:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap new file mode 100644 index 000000000000..e7043b21b324 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: #[aztec] expects 0 or 1 arguments, got 2 + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:4:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:89:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap new file mode 100644 index 000000000000..48141769333e --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap @@ -0,0 +1,304 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[internal] attribute cannot be applied to external functions - transfer_public is marked as both #[external] and #[internal("public")] + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:53:5 + 2: internal + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:375:9 + +error: A function marked as #[external("private")] or #[internal("private")] must not have public Noir visibility - transfer_private's visibility is 'pub' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:85:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:349:9 + 3: assert_valid_private + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:398:9 + +error: The #[view] attribute can only be applied to #[external("private")] or #[external("public")] functions - _assert_is_owner is neither + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:107:5 + 2: view + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:283:9 + +error: #[external("private")] or #[internal("private")] functions must not be unconstrained - mint_private is + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:113:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:349:9 + 3: assert_valid_private + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:405:9 + +error: Function _assert_is_owner must be marked as either #[external(...)], #[internal(...)], or #[test] + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:18:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:93:5 + 3: check_each_fn_macroified + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:295:13 + +error: cannot find `self` in this scope + ┌─ src/main.nr:41:9 + │ +41 │ self.storage.owner.write(self.msg_sender()); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:46:19 + │ +46 │ assert_eq(self.msg_sender(), self.storage.owner.read(), "Only owner can mint"); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:46:38 + │ +46 │ assert_eq(self.msg_sender(), self.storage.owner.read(), "Only owner can mint"); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:47:31 + │ +47 │ let current_balance = self.storage.public_balances.at(employee).read(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:48:9 + │ +48 │ self.storage.public_balances.at(employee).write(current_balance + amount); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:55:22 + │ +55 │ let sender = self.msg_sender(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:56:30 + │ +56 │ let sender_balance = self.storage.public_balances.at(sender).read(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:57:9 + │ +57 │ self.storage.public_balances.at(sender).write(sender_balance - amount); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:58:33 + │ +58 │ let recipient_balance = self.storage.public_balances.at(to).read(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:59:9 + │ +59 │ self.storage.public_balances.at(to).write(recipient_balance + amount); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:64:19 + │ +64 │ assert_eq(self.msg_sender(), self.storage.owner.read(), "Only current owner"); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:64:38 + │ +64 │ assert_eq(self.msg_sender(), self.storage.owner.read(), "Only current owner"); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:65:9 + │ +65 │ self.storage.owner.write(new_owner); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:70:22 + │ +70 │ let sender = self.msg_sender(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:71:9 + │ +71 │ self.enqueue_self._deduct_public_balance(sender, amount); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:72:9 + │ +72 │ self.storage.private_balances.at(sender).add(amount).deliver( + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:80:23 + │ +80 │ let balance = self.storage.public_balances.at(owner).read(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:81:9 + │ +81 │ self.storage.public_balances.at(owner).write(balance - amount); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:87:22 + │ +87 │ let sender = self.msg_sender(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:88:9 + │ +88 │ self.storage.private_balances.at(sender).sub(amount).deliver( + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:91:9 + │ +91 │ self.storage.private_balances.at(to).add(amount).deliver( + │ ---- not found in this scope + │ + +error: missing pub keyword on return type of function private_balance_of + ┌─ src/main.nr:97:65 + │ +97 │ unconstrained fn private_balance_of(owner: AztecAddress) -> u128 { + │ ---- missing pub on return type + │ + = The `pub` keyword is mandatory for the entry-point function return type because the verifier cannot retrieve private witness and thus the function will not be able to return a 'priv' value + +error: cannot find `self` in this scope + ┌─ src/main.nr:98:9 + │ +98 │ self.storage.private_balances.at(owner).balance_of() + │ ---- not found in this scope + │ + +error: missing pub keyword on return type of function public_balance_of + ┌─ src/main.nr:102:64 + │ +102 │ unconstrained fn public_balance_of(owner: AztecAddress) -> u128 { + │ ---- missing pub on return type + │ + = The `pub` keyword is mandatory for the entry-point function return type because the verifier cannot retrieve private witness and thus the function will not be able to return a 'priv' value + +error: cannot find `self` in this scope + ┌─ src/main.nr:103:9 + │ +103 │ self.storage.public_balances.at(owner).read() + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:109:28 + │ +109 │ assert_eq(address, self.storage.owner.read(), "Only owner"); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:115:9 + │ +115 │ self.enqueue_self._assert_is_owner(self.msg_sender()); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:116:9 + │ +116 │ self.storage.private_balances.at(employee).add(amount).deliver( + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:123:22 + │ +123 │ let sender = self.msg_sender(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:124:9 + │ +124 │ self.storage.private_balances.at(sender).sub(amount).deliver( + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:127:9 + │ +127 │ self.enqueue_self._credit_public_balance(sender, amount); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:133:23 + │ +133 │ let balance = self.storage.public_balances.at(owner).read(); + │ ---- not found in this scope + │ + +error: cannot find `self` in this scope + ┌─ src/main.nr:134:9 + │ +134 │ self.storage.public_balances.at(owner).write(balance + amount); + │ ---- not found in this scope + │ + +Aborting due to 38 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap new file mode 100644 index 000000000000..d6afbfc40656 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[storage] macro can only be applied to a struct with name 'Storage', got 'Storage2' instead. + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: DuplicateStorage::#[storage] + at src/main.nr:10:5 + 2: storage + at /noir-projects/aztec-nr/aztec/src/macros/storage.nr:23:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap new file mode 100644 index 000000000000..1d7d038f0b81 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Event selector collision detected between events 'EventCollision8370082250' and 'EventCollision' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: EventSelectorCollision::#[event] + at src/main.nr:10:5 + 2: event + at /noir-projects/aztec-nr/aztec/src/macros/events.nr:56:5 + 3: register_event_selector + at /noir-projects/aztec-nr/aztec/src/macros/events.nr:38:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap new file mode 100644 index 000000000000..4e66449009a9 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[internal] attribute cannot be applied to external functions - foo is marked as both #[external] and #[internal("private")] + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:9:5 + 2: internal + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:375:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap new file mode 100644 index 000000000000..03ab1c2355a0 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[storage] macro can only be applied to a struct with name 'Storage', got 'Storage2' instead. + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: IncorrectStorageStructName::#[storage] + at src/main.nr:8:5 + 2: storage + at /noir-projects/aztec-nr/aztec/src/macros/storage.nr:23:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..eadf7d5ff548 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[initializer] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:11:5 + 2: initializer + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:100:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..22ddb085c680 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[initializer] attribute cannot be applied to #[external("utility")] functions - foo + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:9:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:355:9 + 3: assert_valid_utility + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:491:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap new file mode 100644 index 000000000000..83b77125cd5c --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap @@ -0,0 +1,24 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: event's serialized length exceeds the maximum allowed for private events + ┌─ /noir-projects/aztec-nr/aztec/src/messages/logs/event.nr:30:5 + │ +30 │ ╭ std::static_assert( +31 │ │ ::N <= MAX_EVENT_SERIALIZED_LEN, +32 │ │ "event's serialized length exceeds the maximum allowed for private events", +33 │ │ ); + │ ╰─────' + │ + = Call stack: + 1: remove_constraints + at /noir-projects/aztec-nr/aztec/src/utils/remove_constraints.nr:4:5 + 2: do_private_message_delivery + at /noir-projects/aztec-nr/aztec/src/messages/message_delivery.nr:222:28 + 3: EventMessage::deliver_to + at /noir-projects/aztec-nr/aztec/src/event/event_message.nr:57:16 + 4: encode_private_event_message + at /noir-projects/aztec-nr/aztec/src/messages/logs/event.nr:30:5 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap new file mode 100644 index 000000000000..35d786263891 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Function 'invalid_external_function_type' is marked as #[external("invalid")], but 'invalid' is not a valid external function type. External functions must be one of 'private', 'public' or 'utility' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:7:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:359:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap new file mode 100644 index 000000000000..a5d6a01dfe97 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Function 'foo' is marked as #[internal("utility")], but 'utility' is not a valid internal function type. Internal functions must be one of 'private', 'public' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:8:5 + 2: internal + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:388:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap new file mode 100644 index 000000000000..278bb9319a40 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap @@ -0,0 +1,35 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: InvalidNote has a packed length of 9 fields, which exceeds the maximum allowed length of 8 fields. See https://docs.aztec.network/errors/4 + ┌─ /noir-projects/aztec-nr/aztec/src/macros/notes.nr:52:17 + │ +52 │ std::static_assert(note_packed_len <= $max_note_packed_len, f"{note_type_name} has a packed length of {note_packed_len} fields, which exceeds the maximum allowed length of {max_note_packed_len} fields. See https://docs.aztec.network/errors/4"); + │ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + │ + = Call stack: + 1: generate_sync_state + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:240:13 + 2: do_sync_state + at /noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr:130:5 + 3: EphemeralArray::for_each + at /noir-projects/aztec-nr/aztec/src/ephemeral/mod.nr:99:13 + 4: do_sync_state + at /noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr:139:13 + 5: process_message_ciphertext + at /noir-projects/aztec-nr/aztec/src/messages/discovery/process_message.nr:41:9 + 6: process_message_plaintext + at /noir-projects/aztec-nr/aztec/src/messages/discovery/process_message.nr:76:13 + 7: process_private_note_msg + at /noir-projects/aztec-nr/aztec/src/messages/discovery/private_notes.nr:27:9 + 8: attempt_note_discovery + at /noir-projects/aztec-nr/aztec/src/messages/discovery/private_notes.nr:64:28 + 9: attempt_note_nonce_discovery + at /noir-projects/aztec-nr/aztec/src/messages/discovery/nonce_discovery.nr:46:27 + 10: generate_contract_library_method_compute_note_hash + at /noir-projects/aztec-nr/aztec/src/macros/aztec/compute_note_hash_and_nullifier.nr:107:53 + 11: generate_note_type_impl + at /noir-projects/aztec-nr/aztec/src/macros/notes.nr:52:17 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap new file mode 100644 index 000000000000..637b06f4e3f9 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: #[external("private")] or #[internal("private")] functions must not be unconstrained - unconstrained_private_function is + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:11:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:349:9 + 3: assert_valid_private + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:405:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap new file mode 100644 index 000000000000..f1f2b5c72bd8 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: #[external("public")] or #[internal("public")] functions must not be unconstrained - unconstrained_public_function is + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:11:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:352:9 + 3: assert_valid_public + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:422:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..d776325d7ef9 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[noinitcheck] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:11:5 + 2: noinitcheck + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:128:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..c04d0958d0af --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[noinitcheck] attribute cannot be applied to #[external("utility")] functions - foo + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:16:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:355:9 + 3: assert_valid_utility + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:498:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap new file mode 100644 index 000000000000..431529c017a6 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[noinitcheck] attribute is unnecessary for contracts with no #[initializer] functions + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:8:5 + 2: noinitcheck + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:134:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap new file mode 100644 index 000000000000..df59b3f78c18 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap @@ -0,0 +1,77 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Contract function 'bad_private_return' returns a value of type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:169:13 + │ +169 │ return_type.implements(deserialize_constraint), + │ ---------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:15:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:345:5 + +error: Parameter '_p' of contract function 'bad_private_param' has type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:188:13 + │ +188 │ param_type.implements(deserialize_constraint), + │ --------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:20:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:346:5 + +error: Contract function 'bad_public_return' returns a value of type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:169:13 + │ +169 │ return_type.implements(deserialize_constraint), + │ ---------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:23:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:345:5 + +error: Parameter '_p' of contract function 'bad_public_param' has type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:188:13 + │ +188 │ param_type.implements(deserialize_constraint), + │ --------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:28:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:346:5 + +error: Contract function 'bad_utility_return' returns a value of type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:169:13 + │ +169 │ return_type.implements(deserialize_constraint), + │ ---------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:31:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:345:5 + +error: Parameter '_p' of contract function 'bad_utility_param' has type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:188:13 + │ +188 │ param_type.implements(deserialize_constraint), + │ --------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:36:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:346:5 + +Aborting due to 6 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap new file mode 100644 index 000000000000..62ec3c61e351 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap @@ -0,0 +1,77 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Contract function 'bad_private_return' returns a value of type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:164:13 + │ +164 │ return_type.implements(serialize_constraint), + │ -------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:15:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:345:5 + +error: Parameter '_p' of contract function 'bad_private_param' has type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:183:13 + │ +183 │ param_type.implements(serialize_constraint), + │ ------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:20:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:346:5 + +error: Contract function 'bad_public_return' returns a value of type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:164:13 + │ +164 │ return_type.implements(serialize_constraint), + │ -------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:23:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:345:5 + +error: Parameter '_p' of contract function 'bad_public_param' has type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:183:13 + │ +183 │ param_type.implements(serialize_constraint), + │ ------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:28:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:346:5 + +error: Contract function 'bad_utility_return' returns a value of type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:164:13 + │ +164 │ return_type.implements(serialize_constraint), + │ -------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:31:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:345:5 + +error: Parameter '_p' of contract function 'bad_utility_param' has type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. + ┌─ /noir-projects/aztec-nr/aztec/src/macros/utils.nr:183:13 + │ +183 │ param_type.implements(serialize_constraint), + │ ------------------------------------------- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:36:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:346:5 + +Aborting due to 6 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..58b9830a8cea --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[only_self] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:11:5 + 2: only_self + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:244:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..aacfd01f46e0 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[only_self] attribute cannot be applied to #[external("utility")] functions - foo + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:9:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:355:9 + 3: assert_valid_utility + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:477:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap new file mode 100644 index 000000000000..1eee416fbe05 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap @@ -0,0 +1,15 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Direct invocation of private functions is not supported. You attempted to call arbitrary_external_function. See https://docs.aztec.network/errors/6 + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +12 │ arbitrary_external_function(); + │ --------------------------- `arbitrary_external_function` has been deprecated + │ + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap new file mode 100644 index 000000000000..829db1680a75 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap @@ -0,0 +1,15 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Direct invocation of private internal functions is not supported. You attempted to call arbitrary_private_function. See https://docs.aztec.network/errors/6 + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +12 │ arbitrary_private_function(); + │ -------------------------- `arbitrary_private_function` has been deprecated + │ + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap new file mode 100644 index 000000000000..51cef068790f --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap @@ -0,0 +1,15 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Direct invocation of public functions is not supported. You attempted to call arbitrary_external_function. See https://docs.aztec.network/errors/6 + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +12 │ arbitrary_external_function(); + │ --------------------------- `arbitrary_external_function` has been deprecated + │ + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap new file mode 100644 index 000000000000..5709ee3cb74b --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap @@ -0,0 +1,15 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Direct invocation of public internal functions is not supported. You attempted to call arbitrary_public_function. See https://docs.aztec.network/errors/6 + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +12 │ arbitrary_public_function(); + │ ------------------------- `arbitrary_public_function` has been deprecated + │ + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap new file mode 100644 index 000000000000..252accac8f0f --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap @@ -0,0 +1,15 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Direct invocation of utility functions is not supported. You attempted to call arbitrary_external_function. See https://docs.aztec.network/errors/6 + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +12 │ arbitrary_external_function(); + │ --------------------------- `arbitrary_external_function` has been deprecated + │ + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap new file mode 100644 index 000000000000..de1c268866c5 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap @@ -0,0 +1,25 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Could not resolve 'ZERO' in path + ┌─ src/main.nr:3:1 + │ +3 │ #[aztec] + │ -------- While running this function attribute + · +9 │ PanicOnIncorrectlyPerformedPrivateCall::at(AztecAddress::ZERO).arbitrary_external_function(); + │ ---- + │ + +error: Your private call needs to be passed into the `self.call(...)` method to be executed (e.g. `self.call(MyContract::at(address).my_private_function(...args))` + ┌─ src/main.nr:3:1 + │ +3 │ #[aztec] + │ -------- While running this function attribute + · +9 │ PanicOnIncorrectlyPerformedPrivateCall::at(AztecAddress::ZERO).arbitrary_external_function(); + │ -------------------------------------------------------------------------------------------- Unused expression result of type PrivateCall<27, 0, ()> which must be used + │ + +Aborting due to 2 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap new file mode 100644 index 000000000000..7bd6bfee98f3 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap @@ -0,0 +1,26 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Could not resolve 'ZERO' in path + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +18 │ PanicOnIncorrectlyPerformedPrivateStaticCall::at(AztecAddress::ZERO) + │ ---- + │ + +error: Your private static call needs to be passed into the `self.view(...)` method to be executed (e.g. `self.view(MyContract::at(address).my_private_static_function(...args))` + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +18 │ ╭ PanicOnIncorrectlyPerformedPrivateStaticCall::at(AztecAddress::ZERO) +19 │ │ .arbitrary_view_function(); + │ ╰──────────────────────────────────────' Unused expression result of type PrivateStaticCall<23, 0, Field> which must be used + │ + +Aborting due to 2 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap new file mode 100644 index 000000000000..3361a44915c4 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap @@ -0,0 +1,25 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Could not resolve 'ZERO' in path + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +12 │ PanicOnIncorrectlyPerformedPublicCall::at(AztecAddress::ZERO).arbitrary_public_function(); + │ ---- + │ + +error: Your public call needs to be passed into the `self.call(...)`, `self.enqueue(...)` or `self.enqueue_incognito(...)` method to be executed (e.g. `self.call(MyContract::at(address).my_public_function(...args))` + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +12 │ PanicOnIncorrectlyPerformedPublicCall::at(AztecAddress::ZERO).arbitrary_public_function(); + │ ----------------------------------------------------------------------------------------- Unused expression result of type PublicCall<25, 0, ()> which must be used + │ + +Aborting due to 2 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap new file mode 100644 index 000000000000..b426ebb70c1c --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap @@ -0,0 +1,26 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Could not resolve 'ZERO' in path + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +18 │ PanicOnIncorrectlyPerformedPublicStaticCall::at(AztecAddress::ZERO) + │ ---- + │ + +error: Your public static call needs to be passed into the `self.view(...)`, `self.enqueue_view(...)` or `self.enqueue_view_incognito(...)` method to be executed (e.g. `self.view(MyContract::at(address).my_public_static_function(...args))` + ┌─ src/main.nr:3:1 + │ + 3 │ #[aztec] + │ -------- While running this function attribute + · +18 │ ╭ PanicOnIncorrectlyPerformedPublicStaticCall::at(AztecAddress::ZERO) +19 │ │ .arbitrary_public_static_function(); + │ ╰───────────────────────────────────────────────' Unused expression result of type PublicStaticCall<32, 0, Field> which must be used + │ + +Aborting due to 2 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap new file mode 100644 index 000000000000..3a141f8feda1 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap @@ -0,0 +1,41 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Type NonStateVar does not implement StateVariable and hence cannot be placed in Storage struct. + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: PanicOnNonStateVarInStorage::#[storage] + at src/main.nr:12:5 + 2: storage + at /noir-projects/aztec-nr/aztec/src/macros/storage.nr:54:13 + +error: Could not resolve 'init' in path + ┌─ /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/private.nr:35:36 + │ +35 │ let storage = Storage::init(&mut context); + │ ---- + │ + ┌─ src/main.nr:4:1 + │ + 4 │ #[aztec] + │ -------- While running this function attribute + │ + +error: Type annotation needed + ┌─ /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/private.nr:61:56 + │ +61 │ aztec::contract_self::ContractSelfPrivate::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + │ --- Could not determine the type of the generic argument `Storage` declared on the struct `ContractSelfPrivate` + │ + ┌─ src/main.nr:4:1 + │ + 4 │ #[aztec] + │ -------- While running this function attribute + │ + +Aborting due to 3 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap new file mode 100644 index 000000000000..f7c7c14166a5 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap @@ -0,0 +1,41 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Type PrivateImmutable implements OwnedStateVariable and hence cannot be placed in Storage struct without being wrapped in Owned. Wrap the type in Owned<..., Context>. + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: PanicOnOwnedStateVarInStorage::#[storage] + at src/main.nr:8:5 + 2: storage + at /noir-projects/aztec-nr/aztec/src/macros/storage.nr:49:17 + +error: Could not resolve 'init' in path + ┌─ /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/private.nr:35:36 + │ +35 │ let storage = Storage::init(&mut context); + │ ---- + │ + ┌─ src/main.nr:4:1 + │ + 4 │ #[aztec] + │ -------- While running this function attribute + │ + +error: Type annotation needed + ┌─ /noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/private.nr:61:56 + │ +61 │ aztec::contract_self::ContractSelfPrivate::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + │ --- Could not determine the type of the generic argument `Storage` declared on the struct `ContractSelfPrivate` + │ + ┌─ src/main.nr:4:1 + │ + 4 │ #[aztec] + │ -------- While running this function attribute + │ + +Aborting due to 3 previous errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..a0e08ce30faf --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: A function marked as #[external("private")] or #[internal("private")] must not have public Noir visibility - foo's visibility is 'pub' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:8:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:349:9 + 3: assert_valid_private + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:398:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..7fc4c600b3bd --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: A function marked as #[external("public")] or #[internal("public")] must not have public Noir visibility - foo's visibility is 'pub' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:8:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:352:9 + 3: assert_valid_public + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:415:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..676a28b3f0f7 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: A function marked as #[external("utility")] must not have public Noir visibility - foo's visibility is 'pub' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:8:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:355:9 + 3: assert_valid_utility + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:451:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap new file mode 100644 index 000000000000..8466367d1039 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[allow_phase_change] attribute cannot be applied to #[external("public")] functions - foo + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:9:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:352:9 + 3: assert_valid_public + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:429:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap new file mode 100644 index 000000000000..5e1f5985c358 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap @@ -0,0 +1,23 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Public function selector collision detected between functions 'fn_selector_collision_1442740381' and 'fn_selector_collision' + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:4:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:145:27 + 3: generate_public_dispatch + at /noir-projects/aztec-nr/aztec/src/macros/dispatch.nr:20:19 + 4: [T]::map + at std/vector.nr:67:33 + 5: generate_public_dispatch + at /noir-projects/aztec-nr/aztec/src/macros/dispatch.nr:32:13 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap new file mode 100644 index 000000000000..7ddaf938517a --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Function name '__emit_public_init_nullifier' is reserved for internal use + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:9:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:352:9 + 3: assert_valid_public + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:435:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap new file mode 100644 index 000000000000..523b8cf5c4a4 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Function name 'public_dispatch' is reserved for internal use + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:9:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:352:9 + 3: assert_valid_public + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:441:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap new file mode 100644 index 000000000000..d96287947c14 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: Function foo must be marked as either #[external(...)], #[internal(...)], or #[test] + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:4:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:93:5 + 3: check_each_fn_macroified + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:295:13 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap new file mode 100644 index 000000000000..75565319fd2a --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: User-defined 'offchain_receive' is not allowed. The function is auto-injected by the #[aztec] macro. See https://docs.aztec.network/errors/7 + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: #[aztec] + at src/main.nr:4:1 + 2: aztec + at /noir-projects/aztec-nr/aztec/src/macros/aztec.nr:138:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap new file mode 100644 index 000000000000..2d724bb3ad5d --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: #[external("utility")] must be unconstrained - constrained_utility_function isn't + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:8:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:355:9 + 3: assert_valid_utility + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:458:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..e034afbf1b3b --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap @@ -0,0 +1,17 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[view] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:11:5 + 2: view + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:283:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap new file mode 100644 index 000000000000..f2ae6c5e785b --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap @@ -0,0 +1,19 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- +error: The #[view] attribute cannot be applied to #[external("utility")] functions - foo + ┌─ std/panic.nr:8:12 + │ +8 │ assert(false, message); + │ ----- Assertion failed + │ + = Call stack: + 1: ? + at src/main.nr:9:5 + 2: external + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:355:9 + 3: assert_valid_utility + at /noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr:484:9 + +Aborting due to 1 previous error diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap new file mode 100644 index 000000000000..f0834d0b50ea --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap @@ -0,0 +1,5 @@ +--- +source: tests/snapshots.rs +expression: stderr +--- + diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/amm_contract/snapshots__expanded.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/amm_contract/snapshots__expanded.snap new file mode 100644 index 000000000000..1253e48c4746 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/amm_contract/snapshots__expanded.snap @@ -0,0 +1,2920 @@ +--- +source: tests/snapshots.rs +expression: stdout +--- +use aztec::macros::aztec; +use aztec::macros::aztec; + +mod config { + use std::meta::derive; + use aztec::protocol::address::AztecAddress; + use aztec::protocol::traits::Deserialize; + use aztec::protocol::traits::Packable; + use aztec::protocol::traits::Serialize; + + /// We store the tokens of the pool in a struct such that to load it from PublicImmutable asserts only a single + /// merkle proof. + pub struct Config { + pub token0: AztecAddress, + pub token1: AztecAddress, + pub liquidity_token: AztecAddress, + } + + impl Eq for Config { + fn eq(_self: Self, _other: Self) -> bool { + ((_self.token0 == _other.token0) & (_self.token1 == _other.token1)) & (_self.liquidity_token == _other.liquidity_token) + } + } + + impl Packable for Config { + let N: u32 = 3; + + #[inline_always] + fn pack(self) -> [Field; 3] { + let mut result: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let packed_member: [Field; 1] = self.token0.pack(); + let packed_member_len: u32 = ::N; + for i in 0_u32..packed_member_len { + { + let i_0: u32 = i + offset; + result[i_0] = packed_member[i]; + } + }; + offset = offset + packed_member_len; + let packed_member: [Field; 1] = self.token1.pack(); + let packed_member_len: u32 = ::N; + for i in 0_u32..packed_member_len { + { + let i_1: u32 = i + offset; + result[i_1] = packed_member[i]; + } + }; + offset = offset + packed_member_len; + let packed_member: [Field; 1] = self.liquidity_token.pack(); + let packed_member_len: u32 = ::N; + for i in 0_u32..packed_member_len { + { + let i_2: u32 = i + offset; + result[i_2] = packed_member[i]; + } + }; + offset = offset + packed_member_len; + result + } + + #[inline_always] + fn unpack(packed: [Field; 3]) -> Self { + let mut offset: u32 = 0_u32; + let mut member_fields: [Field; 1] = [0_Field; 1]; + for i in 0_u32..::N { + member_fields[i] = packed[i + offset]; + }; + let token0: AztecAddress = ::unpack(member_fields); + offset = offset + ::N; + let mut member_fields: [Field; 1] = [0_Field; 1]; + for i in 0_u32..::N { + member_fields[i] = packed[i + offset]; + }; + let token1: AztecAddress = ::unpack(member_fields); + offset = offset + ::N; + let mut member_fields: [Field; 1] = [0_Field; 1]; + for i in 0_u32..::N { + member_fields[i] = packed[i + offset]; + }; + let liquidity_token: AztecAddress = ::unpack(member_fields); + offset = offset + ::N; + Self { token0: token0, token1: token1, liquidity_token: liquidity_token} + } + } + + impl Serialize for Config { + let N: u32 = 3; + + fn serialize(self) -> [Field; 3] { + let mut writer: aztec::protocol::utils::writer::Writer<3> = aztec::protocol::utils::writer::Writer::<3>::new(); + self.stream_serialize(&mut writer); + writer.finish() + } + + #[inline_always] + fn stream_serialize(self, writer: &mut aztec::protocol::utils::writer::Writer) { + self.token0.stream_serialize(writer); + self.token1.stream_serialize(writer); + self.liquidity_token.stream_serialize(writer); + } + } + + impl Deserialize for Config { + let N: u32 = 3; + + fn deserialize(fields: [Field; 3]) -> Self { + let mut reader: aztec::protocol::utils::reader::Reader<3> = aztec::protocol::utils::reader::Reader::<3>::new(fields); + let result: Self = Self::stream_deserialize(&mut reader); + reader.finish(); + result + } + + #[inline_always] + fn stream_deserialize(reader: &mut aztec::protocol::utils::reader::Reader) -> Self { + let token0: AztecAddress = ::stream_deserialize(reader); + let token1: AztecAddress = ::stream_deserialize(reader); + let liquidity_token: AztecAddress = ::stream_deserialize(reader); + Self { token0: token0, token1: token1, liquidity_token: liquidity_token} + } + } +} + +mod lib { + /// Given an input amount of an asset and pair balances, returns the maximum output amount of the other asset. + pub fn get_amount_out(amount_in: u128, balance_in: u128, balance_out: u128) -> u128 { + assert(amount_in > (0_Field as u128), "INSUFFICIENT_INPUT_AMOUNT"); + assert((balance_in > (0_Field as u128)) & (balance_out > (0_Field as u128)), "INSUFFICIENT_LIQUIDITY"); + let amount_in_with_fee: u128 = amount_in * (997_Field as u128); + let numerator: u128 = amount_in_with_fee * balance_out; + let denominator: u128 = (balance_in * (1000_Field as u128)) + amount_in_with_fee; + numerator / denominator + } + + /// Given an output amount of an asset and pair balances, returns a required input amount of the other asset. + pub fn get_amount_in(amount_out: u128, balance_in: u128, balance_out: u128) -> u128 { + assert(amount_out > (0_Field as u128), "INSUFFICIENT_OUTPUT_AMOUNT"); + assert((balance_in > (0_Field as u128)) & (balance_out > (0_Field as u128)), "INSUFFICIENT_LIQUIDITY"); + let numerator: u128 = (balance_in * amount_out) * (1000_Field as u128); + let denominator: u128 = (balance_out - amount_out) * (997_Field as u128); + (numerator / denominator) + (1_Field as u128) + } + + /// Given the desired amounts and balances of token0 and token1 returns the optimal amount of token0 and token1 to be + /// added to the pool. + pub fn get_amounts_to_add(amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128, balance0: u128, balance1: u128) -> (u128, u128) { + if (balance0 == (0_Field as u128)) | (balance1 == (0_Field as u128)) { + (amount0_max, amount1_max) + } else { + let amount1_equivalent: u128 = get_equivalent_amount(amount0_max, balance0, balance1); + if amount1_equivalent <= amount1_max { + assert(amount1_equivalent >= amount1_min, "AMOUNT_1_BELOW_MINIMUM"); + (amount0_max, amount1_equivalent) + } else { + let amount0_equivalent: u128 = get_equivalent_amount(amount1_max, balance1, balance0); + assert(amount0_equivalent <= amount0_max); + assert(amount0_equivalent >= amount0_min, "AMOUNT_0_BELOW_MINIMUM"); + (amount0_equivalent, amount1_max) + } + } + } + + /// Returns the amount of tokens to return to a liquidity provider when they remove liquidity from the pool. + pub fn get_amounts_on_remove(to_burn: u128, total_supply: u128, balance0: u128, balance1: u128) -> (u128, u128) { + ((to_burn * balance0) / total_supply, (to_burn * balance1) / total_supply) + } + + /// Given some amount of an asset and pair balances, returns an equivalent amount of the other asset. Tokens should be + /// added and removed from the Pool respecting this ratio. + fn get_equivalent_amount(amount0: u128, balance0: u128, balance1: u128) -> u128 { + assert((balance0 > (0_Field as u128)) & (balance1 > (0_Field as u128)), "INSUFFICIENT_LIQUIDITY"); + (amount0 * balance1) / balance0 + } +} + +/// ## Overview +/// This contract demonstrates how to implement an **Automated Market Maker (AMM)** that maintains **public state** +/// while still achieving **identity privacy**. However, it does **not provide function privacy**: +/// - Anyone can observe **what actions** were performed. +/// - All amounts involved are visible, but **who** performed the action remains private. +/// +/// Unlike most Ethereum AMMs, the AMM contract is not itself the token that tracks participation of liquidity +/// providers, mostly due to Noir lacking inheritance as a feature. Instead, the AMM is expected to have mint and burn +/// permission over an external token contract. +/// +/// **Note:** +/// This is purely a demonstration. The **Aztec team** does not consider this the optimal design for building a DEX. +/// +/// ## Reentrancy Guard Considerations +/// +/// ### 1. Private Functions: +/// Reentrancy protection is typically necessary if entering an intermediate state that is only valid when +/// the action completes uninterrupted. This follows the **Checks-Effects-Interactions** pattern. +/// +/// - In this contract, **private functions** do not introduce intermediate states. +/// - All operations will be fully executed in **public** without needing intermediate checks. +/// +/// ### 2. Public Functions: +/// No **reentrancy guard** is required for public functions because: +/// - All public functions are marked as **internal** with a **single callsite** - from a private function. +/// - Public functions **cannot call private functions**, eliminating the risk of reentering into them from private. +/// - Since public functions are internal-only, **external contracts cannot access them**, ensuring no external +/// contract can trigger a reentrant call. This eliminates the following attack vector: +/// `AMM.private_fn --> AMM.public_fn --> ExternalContract.fn --> AMM.public_fn`. +pub contract AMM { + use crate::config::Config; + use crate::lib::get_amount_in; + use crate::lib::get_amount_out; + use crate::lib::get_amounts_on_remove; + use crate::lib::get_amounts_to_add; + use aztec::macros::functions::external; + use aztec::macros::functions::initializer; + use aztec::macros::functions::only_self; + use aztec::macros::storage::storage; + use aztec::protocol::address::AztecAddress; + use aztec::state_vars::PublicImmutable; + use token::Token; + use uint_note::PartialUintNote; + + struct Storage { + config: PublicImmutable, + } + + impl Storage { + fn init(context: Context) -> Self { + Self { config: as aztec::state_vars::StateVariable<4, Context>>::new(context, 1_Field)} + } + } + + /// Amount of liquidity which gets locked when liquidity is provided for the first time. Its purpose is to prevent + /// the pool from ever emptying which could lead to undefined behavior. + pub global MINIMUM_LIQUIDITY: u128 = 1000; + + /// We set it to 99 times the minimum liquidity. That way the first LP gets 99% of the value of their deposit. + pub global INITIAL_LIQUIDITY: u128 = 99000; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call constructor. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn constructor(token0: AztecAddress, token1: AztecAddress, liquidity_token: AztecAddress); + + /// Privately adds liquidity to the pool. This function receives the minimum and maximum number of tokens the caller + /// is willing to add, in order to account for changing market conditions, and will try to add as many tokens as + /// possible. + /// + /// `authwit_nonce` can be any non-zero value, as it's only used to isolate token transfer authwits to this + /// specific call. + /// + /// The identity of the liquidity provider is not revealed, but the action and amounts are. + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call add_liquidity. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn add_liquidity(amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128, authwit_nonce: Field); + + #[abi(storage)] + pub global STORAGE_LAYOUT_AMM: StorageLayout<3> = StorageLayout::<3> { + contract_name: "AMM", + fields: StorageLayoutFields { + config: aztec::state_vars::Storable { + slot: 0x01, + }, + }, + }; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call _add_liquidity. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _add_liquidity(config: Config, refund_token0_partial_note: PartialUintNote, refund_token1_partial_note: PartialUintNote, liquidity_partial_note: PartialUintNote, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128); + + /// Privately removes liquidity from the pool. This function receives how many liquidity tokens to burn, and the + /// minimum number of tokens the caller is willing to receive, in order to account for changing market conditions. + /// + /// `authwit_nonce` can be any non-zero value, as it's only used to isolate token transfer authwits to this + /// specific call. + /// + /// The identity of the liquidity provider is not revealed, but the action and amounts are. + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call remove_liquidity. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn remove_liquidity(liquidity: u128, amount0_min: u128, amount1_min: u128, authwit_nonce: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call _remove_liquidity. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _remove_liquidity(config: Config, liquidity: u128, token0_partial_note: PartialUintNote, token1_partial_note: PartialUintNote, amount0_min: u128, amount1_min: u128); + + /// Privately swaps `amount_in` `token_in` tokens for at least `amount_out_mint` `token_out` tokens with the pool. + /// + /// `authwit_nonce` can be any non-zero value, as it's only used to isolate token transfer authwits to this + /// specific call. + /// + /// The identity of the swapper is not revealed, but the action and amounts are. + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call swap_exact_tokens_for_tokens. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn swap_exact_tokens_for_tokens(token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, authwit_nonce: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call _swap_exact_tokens_for_tokens. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _swap_exact_tokens_for_tokens(token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, token_out_partial_note: PartialUintNote); + + /// Privately swaps at most `amount_in_max` `token_in` tokens for `amount_out` `token_out` tokens with the pool. + /// + /// `authwit_nonce` can be any non-zero value, as it's only used to isolate token transfer authwits to this + /// specific call. + /// + /// The identity of the swapper is not revealed, but the action and amounts are. + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call swap_tokens_for_exact_tokens. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn swap_tokens_for_exact_tokens(token_in: AztecAddress, token_out: AztecAddress, amount_out: u128, amount_in_max: u128, authwit_nonce: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call _swap_tokens_for_exact_tokens. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _swap_tokens_for_exact_tokens(token_in: AztecAddress, token_out: AztecAddress, amount_in_max: u128, amount_out: u128, change_token_in_partial_note: PartialUintNote, token_out_partial_note: PartialUintNote); + + #[deprecated(deny, "Direct invocation of utility functions is not supported. You attempted to call get_amount_out_for_exact_in. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + unconstrained fn get_amount_out_for_exact_in(balance_in: u128, balance_out: u128, amount_in: u128) -> u128; + + #[deprecated(deny, "Direct invocation of utility functions is not supported. You attempted to call get_amount_in_for_exact_out. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + unconstrained fn get_amount_in_for_exact_out(balance_in: u128, balance_out: u128, amount_out: u128) -> u128; + + /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + #[allow(dead_code)] + unconstrained fn _compute_note_hash_and_nullifier(packed_note: BoundedVec, owner: AztecAddress, storage_slot: Field, note_type_id: Field, contract_address: AztecAddress, randomness: Field, note_nonce: Field) -> Option { + _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash: Field| -> aztec::messages::discovery::NoteHashAndNullifier { + let siloed_note_hash: Field = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash); + let unique_note_hash: Field = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash); + let inner_nullifier: Option = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness); + aztec::messages::discovery::NoteHashAndNullifier { note_hash: note_hash, inner_nullifier: inner_nullifier} + }) + } + + /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed). + /// + /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_hash(packed_note: BoundedVec, owner: AztecAddress, storage_slot: Field, note_type_id: Field, _contract_address: AztecAddress, randomness: Field) -> Option { + if note_type_id == ::get_id() { + let expected_len: u32 = ::N; + let actual_len: u32 = packed_note.len(); + if actual_len != expected_len { + (|args: [Field; 3]| aztec::oracle::logging::warn_log_format("[aztec-nr] Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.", args))([note_type_id, expected_len as Field, actual_len as Field]); + Option::::none() + } else { + let note: uint_note::UintNote = ::unpack(aztec::utils::array::subarray::subarray(packed_note.storage(), 0_u32)); + Option::::some(::compute_note_hash(note, owner, storage_slot, randomness)) + } + } else { + (|args: [Field; 1]| aztec::oracle::logging::warn_log_format("[aztec-nr] Unknown note type id {0}. Skipping note.", args))([note_type_id]); + Option::::none() + } + } + + /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data. + /// + /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_nullifier(unique_note_hash: Field, packed_note: BoundedVec, owner: AztecAddress, _storage_slot: Field, note_type_id: Field, _contract_address: AztecAddress, _randomness: Field) -> Option { + if note_type_id == ::get_id() { + let expected_len: u32 = ::N; + let actual_len: u32 = packed_note.len(); + if actual_len != expected_len { + (|args: [Field; 3]| aztec::oracle::logging::warn_log_format("[aztec-nr] Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.", args))([note_type_id, expected_len as Field, actual_len as Field]); + Option::::none() + } else { + let note: uint_note::UintNote = ::unpack(aztec::utils::array::subarray::subarray(packed_note.storage(), 0_u32)); + ::compute_nullifier_unconstrained(note, owner, unique_note_hash) + } + } else { + (|args: [Field; 1]| aztec::oracle::logging::warn_log_format("[aztec-nr] Unknown note type id {0}. Skipping note.", args))([note_type_id]); + Option::::none() + } + } + + /// Receives offchain messages into this contract's offchain inbox for subsequent processing. + /// + /// Each message is routed to the inbox scoped to its `recipient` field. + /// + /// For more details, see `aztec::messages::processing::offchain::receive`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + unconstrained fn offchain_receive(messages: BoundedVec) { + let address: AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::processing::offchain::receive(address, messages); + } + + pub struct AMM { + pub target_contract: AztecAddress, + } + + impl AMM { + pub fn storage_layout() -> StorageLayoutFields { + STORAGE_LAYOUT_AMM.fields + } + + pub fn at(addr: AztecAddress) -> Self { + Self { target_contract: addr} + } + + pub fn interface() -> Self { + Self { target_contract: AztecAddress::zero()} + } + + pub fn constructor(self, token0: AztecAddress, token1: AztecAddress, liquidity_token: AztecAddress) -> aztec::context::calls::PublicCall<11, 3, ()> { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token0); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token1); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity_token); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2287085075_Field); + aztec::context::calls::PublicCall::<11, 3, ()>::new(self.target_contract, selector, "constructor", serialized_params) + } + + pub fn add_liquidity(self, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128, authwit_nonce: Field) -> aztec::context::calls::PrivateCall<13, 5, ()> { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount0_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3734879327_Field); + aztec::context::calls::PrivateCall::<13, 5, ()>::new(self.target_contract, selector, "add_liquidity", serialized_params) + } + + pub fn swap_exact_tokens_for_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, authwit_nonce: Field) -> aztec::context::calls::PrivateCall<28, 5, ()> { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2960373586_Field); + aztec::context::calls::PrivateCall::<28, 5, ()>::new(self.target_contract, selector, "swap_exact_tokens_for_tokens", serialized_params) + } + + pub fn _swap_tokens_for_exact_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_in_max: u128, amount_out: u128, change_token_in_partial_note: PartialUintNote, token_out_partial_note: PartialUintNote) -> aztec::context::calls::PublicCall<29, 6, ()> { + let mut serialized_params: [Field; 6] = [0_Field; 6]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(change_token_in_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3156435103_Field); + aztec::context::calls::PublicCall::<29, 6, ()>::new(self.target_contract, selector, "_swap_tokens_for_exact_tokens", serialized_params) + } + + pub fn _swap_exact_tokens_for_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, token_out_partial_note: PartialUintNote) -> aztec::context::calls::PublicCall<29, 5, ()> { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1918288610_Field); + aztec::context::calls::PublicCall::<29, 5, ()>::new(self.target_contract, selector, "_swap_exact_tokens_for_tokens", serialized_params) + } + + pub fn _remove_liquidity(self, config: Config, liquidity: u128, token0_partial_note: PartialUintNote, token1_partial_note: PartialUintNote, amount0_min: u128, amount1_min: u128) -> aztec::context::calls::PublicCall<17, 8, ()> { + let mut serialized_params: [Field; 8] = [0_Field; 8]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = >::serialize(config); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token0_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token1_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2270402407_Field); + aztec::context::calls::PublicCall::<17, 8, ()>::new(self.target_contract, selector, "_remove_liquidity", serialized_params) + } + + pub fn _add_liquidity(self, config: Config, refund_token0_partial_note: PartialUintNote, refund_token1_partial_note: PartialUintNote, liquidity_partial_note: PartialUintNote, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128) -> aztec::context::calls::PublicCall<14, 10, ()> { + let mut serialized_params: [Field; 10] = [0_Field; 10]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = >::serialize(config); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(refund_token0_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(refund_token1_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_6: u32 = i + offset; + serialized_params[i_6] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_7: u32 = i + offset; + serialized_params[i_7] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1909103841_Field); + aztec::context::calls::PublicCall::<14, 10, ()>::new(self.target_contract, selector, "_add_liquidity", serialized_params) + } + + pub fn remove_liquidity(self, liquidity: u128, amount0_min: u128, amount1_min: u128, authwit_nonce: Field) -> aztec::context::calls::PrivateCall<16, 4, ()> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(liquidity); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1221183968_Field); + aztec::context::calls::PrivateCall::<16, 4, ()>::new(self.target_contract, selector, "remove_liquidity", serialized_params) + } + + pub fn swap_tokens_for_exact_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_out: u128, amount_in_max: u128, authwit_nonce: Field) -> aztec::context::calls::PrivateCall<28, 5, ()> { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2620890703_Field); + aztec::context::calls::PrivateCall::<28, 5, ()>::new(self.target_contract, selector, "swap_tokens_for_exact_tokens", serialized_params) + } + + pub fn get_amount_out_for_exact_in(self, balance_in: u128, balance_out: u128, amount_in: u128) -> aztec::context::calls::UtilityCall<27, 3, u128> { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(balance_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(balance_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(58321933_Field); + aztec::context::calls::UtilityCall::<27, 3, u128>::new(self.target_contract, selector, "get_amount_out_for_exact_in", serialized_params) + } + + pub fn get_amount_in_for_exact_out(self, balance_in: u128, balance_out: u128, amount_out: u128) -> aztec::context::calls::UtilityCall<27, 3, u128> { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(balance_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(balance_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4155151179_Field); + aztec::context::calls::UtilityCall::<27, 3, u128>::new(self.target_contract, selector, "get_amount_in_for_exact_out", serialized_params) + } + + pub fn offchain_receive(self, messages: BoundedVec) -> aztec::context::calls::UtilityCall<16, 321, ()> { + let serialized_params: [Field; 321] = as aztec::protocol::traits::Serialize>::serialize(messages); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1396850735_Field); + aztec::context::calls::UtilityCall::<16, 321, ()>::new(self.target_contract, selector, "offchain_receive", serialized_params) + } + } + + #[contract_library_method] + pub fn storage_layout() -> StorageLayoutFields { + STORAGE_LAYOUT_AMM.fields + } + + #[contract_library_method] + pub fn at(addr: AztecAddress) -> AMM { + AMM { target_contract: addr} + } + + #[contract_library_method] + pub fn interface() -> AMM { + AMM { target_contract: AztecAddress::zero()} + } + + pub struct sync_state_parameters { + pub scope: AztecAddress, + } + + #[abi(functions)] + pub struct sync_state_abi { + parameters: sync_state_parameters, + } + + unconstrained fn sync_state(scope: AztecAddress) { + let address: AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::discovery::do_sync_state(address, _compute_note_hash, _compute_note_nullifier, Option::>::none(), Option:: aztec::ephemeral::EphemeralArray>::some(aztec::messages::processing::offchain::sync_inbox), scope); + } + + pub struct offchain_receive_parameters { + pub messages: BoundedVec, + } + + #[abi(functions)] + pub struct offchain_receive_abi { + parameters: offchain_receive_parameters, + } + + pub struct CallSelf { + pub address: AztecAddress, + pub context: Context, + } + + impl CallSelf { + pub fn _remove_liquidity(self, config: Config, liquidity: u128, token0_partial_note: PartialUintNote, token1_partial_note: PartialUintNote, amount0_min: u128, amount1_min: u128) { + let mut serialized_params: [Field; 8] = [0_Field; 8]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = >::serialize(config); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token0_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token1_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2270402407_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<17, 8, ()>::new(self.address, selector, "_remove_liquidity", serialized_params).call(self.context) + } + } + + pub fn _add_liquidity(self, config: Config, refund_token0_partial_note: PartialUintNote, refund_token1_partial_note: PartialUintNote, liquidity_partial_note: PartialUintNote, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128) { + let mut serialized_params: [Field; 10] = [0_Field; 10]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = >::serialize(config); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(refund_token0_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(refund_token1_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_6: u32 = i + offset; + serialized_params[i_6] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_7: u32 = i + offset; + serialized_params[i_7] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1909103841_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 10, ()>::new(self.address, selector, "_add_liquidity", serialized_params).call(self.context) + } + } + + pub fn constructor(self, token0: AztecAddress, token1: AztecAddress, liquidity_token: AztecAddress) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token0); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token1); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity_token); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2287085075_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<11, 3, ()>::new(self.address, selector, "constructor", serialized_params).call(self.context) + } + } + + pub fn _swap_tokens_for_exact_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_in_max: u128, amount_out: u128, change_token_in_partial_note: PartialUintNote, token_out_partial_note: PartialUintNote) { + let mut serialized_params: [Field; 6] = [0_Field; 6]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(change_token_in_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3156435103_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<29, 6, ()>::new(self.address, selector, "_swap_tokens_for_exact_tokens", serialized_params).call(self.context) + } + } + + pub fn _swap_exact_tokens_for_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, token_out_partial_note: PartialUintNote) { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1918288610_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<29, 5, ()>::new(self.address, selector, "_swap_exact_tokens_for_tokens", serialized_params).call(self.context) + } + } + } + + impl CallSelf<&mut aztec::context::PrivateContext> { + pub fn remove_liquidity(self, liquidity: u128, amount0_min: u128, amount1_min: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(liquidity); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1221183968_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn add_liquidity(self, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount0_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3734879327_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn swap_tokens_for_exact_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_out: u128, amount_in_max: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2620890703_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn swap_exact_tokens_for_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2960373586_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + } + + pub struct CallSelfStatic { + pub address: AztecAddress, + pub context: Context, + } + + pub struct EnqueueSelf { + pub address: AztecAddress, + pub context: Context, + } + + impl EnqueueSelf<&mut aztec::context::PrivateContext> { + pub fn _remove_liquidity(self, config: Config, liquidity: u128, token0_partial_note: PartialUintNote, token1_partial_note: PartialUintNote, amount0_min: u128, amount1_min: u128) { + let mut serialized_params: [Field; 8] = [0_Field; 8]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = >::serialize(config); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token0_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token1_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2270402407_Field); + let calldata: [Field; 1 + 8] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn _swap_tokens_for_exact_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_in_max: u128, amount_out: u128, change_token_in_partial_note: PartialUintNote, token_out_partial_note: PartialUintNote) { + let mut serialized_params: [Field; 6] = [0_Field; 6]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(change_token_in_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3156435103_Field); + let calldata: [Field; 1 + 6] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn _add_liquidity(self, config: Config, refund_token0_partial_note: PartialUintNote, refund_token1_partial_note: PartialUintNote, liquidity_partial_note: PartialUintNote, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128) { + let mut serialized_params: [Field; 10] = [0_Field; 10]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = >::serialize(config); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(refund_token0_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(refund_token1_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_6: u32 = i + offset; + serialized_params[i_6] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_7: u32 = i + offset; + serialized_params[i_7] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1909103841_Field); + let calldata: [Field; 1 + 10] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn _swap_exact_tokens_for_tokens(self, token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, token_out_partial_note: PartialUintNote) { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out_partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1918288610_Field); + let calldata: [Field; 1 + 5] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn constructor(self, token0: AztecAddress, token1: AztecAddress, liquidity_token: AztecAddress) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token0); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token1); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(liquidity_token); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2287085075_Field); + let calldata: [Field; 1 + 3] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + } + + pub struct EnqueueSelfStatic { + pub address: AztecAddress, + pub context: Context, + } + + pub struct CallSelfUtility { + pub address: AztecAddress, + } + + impl CallSelfUtility { + pub unconstrained fn get_amount_out_for_exact_in(self, balance_in: u128, balance_out: u128, amount_in: u128) -> u128 { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(balance_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(balance_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(58321933_Field); + let returns: [Field; 1] = aztec::oracle::call_utility_function::call_utility_function(self.address, selector, serialized_params); + ::deserialize(returns) + } + + pub unconstrained fn get_amount_in_for_exact_out(self, balance_in: u128, balance_out: u128, amount_out: u128) -> u128 { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(balance_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(balance_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4155151179_Field); + let returns: [Field; 1] = aztec::oracle::call_utility_function::call_utility_function(self.address, selector, serialized_params); + ::deserialize(returns) + } + } + + pub struct CallInternal { + pub context: Context, + } + + pub unconstrained fn public_dispatch(selector: Field) { + if selector == 2287085075_Field { + let input_calldata: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (::N + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<3> = aztec::protocol::utils::reader::Reader::<3>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: AztecAddress = ::stream_deserialize(&mut reader); + let arg2: AztecAddress = ::stream_deserialize(&mut reader); + __aztec_nr_internals__constructor(arg0, arg1, arg2); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1909103841_Field { + let input_calldata: [Field; 10] = aztec::oracle::avm::calldata_copy(1_u32, ((((((>::N + ::N) + ::N) + ::N) + ::N) + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<10> = aztec::protocol::utils::reader::Reader::<10>::new(input_calldata); + let arg0: Config = >::stream_deserialize(&mut reader); + let arg1: PartialUintNote = ::stream_deserialize(&mut reader); + let arg2: PartialUintNote = ::stream_deserialize(&mut reader); + let arg3: PartialUintNote = ::stream_deserialize(&mut reader); + let arg4: u128 = ::stream_deserialize(&mut reader); + let arg5: u128 = ::stream_deserialize(&mut reader); + let arg6: u128 = ::stream_deserialize(&mut reader); + let arg7: u128 = ::stream_deserialize(&mut reader); + __aztec_nr_internals___add_liquidity(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2270402407_Field { + let input_calldata: [Field; 8] = aztec::oracle::avm::calldata_copy(1_u32, ((((>::N + ::N) + ::N) + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<8> = aztec::protocol::utils::reader::Reader::<8>::new(input_calldata); + let arg0: Config = >::stream_deserialize(&mut reader); + let arg1: u128 = ::stream_deserialize(&mut reader); + let arg2: PartialUintNote = ::stream_deserialize(&mut reader); + let arg3: PartialUintNote = ::stream_deserialize(&mut reader); + let arg4: u128 = ::stream_deserialize(&mut reader); + let arg5: u128 = ::stream_deserialize(&mut reader); + __aztec_nr_internals___remove_liquidity(arg0, arg1, arg2, arg3, arg4, arg5); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1918288610_Field { + let input_calldata: [Field; 5] = aztec::oracle::avm::calldata_copy(1_u32, (((::N + ::N) + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<5> = aztec::protocol::utils::reader::Reader::<5>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: AztecAddress = ::stream_deserialize(&mut reader); + let arg2: u128 = ::stream_deserialize(&mut reader); + let arg3: u128 = ::stream_deserialize(&mut reader); + let arg4: PartialUintNote = ::stream_deserialize(&mut reader); + __aztec_nr_internals___swap_exact_tokens_for_tokens(arg0, arg1, arg2, arg3, arg4); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3156435103_Field { + let input_calldata: [Field; 6] = aztec::oracle::avm::calldata_copy(1_u32, ((((::N + ::N) + ::N) + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<6> = aztec::protocol::utils::reader::Reader::<6>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: AztecAddress = ::stream_deserialize(&mut reader); + let arg2: u128 = ::stream_deserialize(&mut reader); + let arg3: u128 = ::stream_deserialize(&mut reader); + let arg4: PartialUintNote = ::stream_deserialize(&mut reader); + let arg5: PartialUintNote = ::stream_deserialize(&mut reader); + __aztec_nr_internals___swap_tokens_for_exact_tokens(arg0, arg1, arg2, arg3, arg4, arg5); + aztec::oracle::avm::avm_return([].as_slice()); + }; + panic(f"Unknown selector {selector}") + } + + pub struct _add_liquidity_parameters { + pub config: Config, + pub refund_token0_partial_note: PartialUintNote, + pub refund_token1_partial_note: PartialUintNote, + pub liquidity_partial_note: PartialUintNote, + pub amount0_max: u128, + pub amount1_max: u128, + pub amount0_min: u128, + pub amount1_min: u128, + } + + pub struct _remove_liquidity_parameters { + pub config: Config, + pub liquidity: u128, + pub token0_partial_note: PartialUintNote, + pub token1_partial_note: PartialUintNote, + pub amount0_min: u128, + pub amount1_min: u128, + } + + pub struct _swap_exact_tokens_for_tokens_parameters { + pub token_in: AztecAddress, + pub token_out: AztecAddress, + pub amount_in: u128, + pub amount_out_min: u128, + pub token_out_partial_note: PartialUintNote, + } + + pub struct _swap_tokens_for_exact_tokens_parameters { + pub token_in: AztecAddress, + pub token_out: AztecAddress, + pub amount_in_max: u128, + pub amount_out: u128, + pub change_token_in_partial_note: PartialUintNote, + pub token_out_partial_note: PartialUintNote, + } + + pub struct add_liquidity_parameters { + pub amount0_max: u128, + pub amount1_max: u128, + pub amount0_min: u128, + pub amount1_min: u128, + pub authwit_nonce: Field, + } + + pub struct constructor_parameters { + pub token0: AztecAddress, + pub token1: AztecAddress, + pub liquidity_token: AztecAddress, + } + + pub struct get_amount_in_for_exact_out_parameters { + pub balance_in: u128, + pub balance_out: u128, + pub amount_out: u128, + } + + pub struct get_amount_out_for_exact_in_parameters { + pub balance_in: u128, + pub balance_out: u128, + pub amount_in: u128, + } + + pub struct remove_liquidity_parameters { + pub liquidity: u128, + pub amount0_min: u128, + pub amount1_min: u128, + pub authwit_nonce: Field, + } + + pub struct swap_exact_tokens_for_tokens_parameters { + pub token_in: AztecAddress, + pub token_out: AztecAddress, + pub amount_in: u128, + pub amount_out_min: u128, + pub authwit_nonce: Field, + } + + pub struct swap_tokens_for_exact_tokens_parameters { + pub token_in: AztecAddress, + pub token_out: AztecAddress, + pub amount_out: u128, + pub amount_in_max: u128, + pub authwit_nonce: Field, + } + + #[abi(functions)] + pub struct _add_liquidity_abi { + parameters: _add_liquidity_parameters, + } + + #[abi(functions)] + pub struct _remove_liquidity_abi { + parameters: _remove_liquidity_parameters, + } + + #[abi(functions)] + pub struct _swap_exact_tokens_for_tokens_abi { + parameters: _swap_exact_tokens_for_tokens_parameters, + } + + #[abi(functions)] + pub struct _swap_tokens_for_exact_tokens_abi { + parameters: _swap_tokens_for_exact_tokens_parameters, + } + + #[abi(functions)] + pub struct add_liquidity_abi { + parameters: add_liquidity_parameters, + } + + #[abi(functions)] + pub struct constructor_abi { + parameters: constructor_parameters, + } + + #[abi(functions)] + pub struct get_amount_in_for_exact_out_abi { + parameters: get_amount_in_for_exact_out_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct get_amount_out_for_exact_in_abi { + parameters: get_amount_out_for_exact_in_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct remove_liquidity_abi { + parameters: remove_liquidity_parameters, + } + + #[abi(functions)] + pub struct swap_exact_tokens_for_tokens_abi { + parameters: swap_exact_tokens_for_tokens_parameters, + } + + #[abi(functions)] + pub struct swap_tokens_for_exact_tokens_abi { + parameters: swap_tokens_for_exact_tokens_parameters, + } + + fn __aztec_nr_internals__add_liquidity(inputs: aztec::context::inputs::PrivateContextInputs, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount0_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut aztec::context::PrivateContext> = Storage::<&mut aztec::context::PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut aztec::context::PrivateContext> = CallSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut aztec::context::PrivateContext> = EnqueueSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal::<&mut aztec::context::PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + assert((amount0_min < amount0_max) | (amount0_min == amount0_max), "INCORRECT_TOKEN0_LIMITS"); + assert((amount1_min < amount1_max) | (amount1_min == amount1_max), "INCORRECT_TOKEN1_LIMITS"); + assert(((0_Field as u128) < amount0_max) & ((0_Field as u128) < amount1_max), "INSUFFICIENT_INPUT_AMOUNTS"); + let config: Config = self.storage.config.read(); + let token0: Token::Token = Token::at(config.token0); + let token1: Token::Token = Token::at(config.token1); + let liquidity_token: Token::Token = Token::at(config.liquidity_token); + let sender: AztecAddress = self.msg_sender(); + let refund_token0_partial_note: PartialUintNote = self.call(token0.transfer_to_public_and_prepare_private_balance_increase(sender, self.address, amount0_max, authwit_nonce)); + let refund_token1_partial_note: PartialUintNote = self.call(token1.transfer_to_public_and_prepare_private_balance_increase(sender, self.address, amount1_max, authwit_nonce)); + let liquidity_partial_note: PartialUintNote = self.call(liquidity_token.prepare_private_balance_increase(sender)); + self.enqueue_self._add_liquidity(config, refund_token0_partial_note, refund_token1_partial_note, liquidity_partial_note, amount0_max, amount1_max, amount0_min, amount1_min); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__remove_liquidity(inputs: aztec::context::inputs::PrivateContextInputs, liquidity: u128, amount0_min: u128, amount1_min: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(liquidity); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount0_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount1_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut aztec::context::PrivateContext> = Storage::<&mut aztec::context::PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut aztec::context::PrivateContext> = CallSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut aztec::context::PrivateContext> = EnqueueSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal::<&mut aztec::context::PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + let config: Config = self.storage.config.read(); + let liquidity_token: Token::Token = Token::at(config.liquidity_token); + let token0: Token::Token = Token::at(config.token0); + let token1: Token::Token = Token::at(config.token1); + let sender: AztecAddress = self.msg_sender(); + self.call(liquidity_token.transfer_to_public(sender, self.address, liquidity, authwit_nonce)); + let token0_partial_note: PartialUintNote = self.call(token0.prepare_private_balance_increase(sender)); + let token1_partial_note: PartialUintNote = self.call(token1.prepare_private_balance_increase(sender)); + self.enqueue_self._remove_liquidity(config, liquidity, token0_partial_note, token1_partial_note, amount0_min, amount1_min); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__swap_exact_tokens_for_tokens(inputs: aztec::context::inputs::PrivateContextInputs, token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out_min); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut aztec::context::PrivateContext> = Storage::<&mut aztec::context::PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut aztec::context::PrivateContext> = CallSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut aztec::context::PrivateContext> = EnqueueSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal::<&mut aztec::context::PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + let config: Config = self.storage.config.read(); + assert((token_in == config.token0) | (token_in == config.token1), "TOKEN_IN_IS_INVALID"); + assert((token_out == config.token0) | (token_out == config.token1), "TOKEN_OUT_IS_INVALID"); + assert(token_in != token_out, "SAME_TOKEN_SWAP"); + let sender: AztecAddress = self.msg_sender(); + self.call(Token::at(token_in).transfer_to_public(sender, self.address, amount_in, authwit_nonce)); + let token_out_partial_note: PartialUintNote = self.call(Token::at(token_out).prepare_private_balance_increase(sender)); + self.enqueue_self._swap_exact_tokens_for_tokens(token_in, token_out, amount_in, amount_out_min, token_out_partial_note); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__swap_tokens_for_exact_tokens(inputs: aztec::context::inputs::PrivateContextInputs, token_in: AztecAddress, token_out: AztecAddress, amount_out: u128, amount_in_max: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 5] = [0_Field; 5]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(token_in); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(token_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_out); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount_in_max); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut aztec::context::PrivateContext> = Storage::<&mut aztec::context::PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut aztec::context::PrivateContext> = CallSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut aztec::context::PrivateContext> = EnqueueSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal::<&mut aztec::context::PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + let config: Config = self.storage.config.read(); + assert((token_in == config.token0) | (token_in == config.token1), "TOKEN_IN_IS_INVALID"); + assert((token_out == config.token0) | (token_out == config.token1), "TOKEN_OUT_IS_INVALID"); + assert(token_in != token_out, "SAME_TOKEN_SWAP"); + let sender: AztecAddress = self.msg_sender(); + let change_token_in_partial_note: PartialUintNote = self.call(Token::at(token_in).transfer_to_public_and_prepare_private_balance_increase(sender, self.address, amount_in_max, authwit_nonce)); + let token_out_partial_note: PartialUintNote = self.call(Token::at(token_out).prepare_private_balance_increase(sender)); + self.enqueue_self._swap_tokens_for_exact_tokens(token_in, token_out, amount_in_max, amount_out, change_token_in_partial_note, token_out_partial_note); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + unconstrained fn __aztec_nr_internals___add_liquidity(config: Config, refund_token0_partial_note: PartialUintNote, refund_token1_partial_note: PartialUintNote, liquidity_partial_note: PartialUintNote, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 10] = aztec::oracle::avm::calldata_copy(1_u32, ((((((>::N + ::N) + ::N) + ::N) + ::N) + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.msg_sender() == self.address, "Function _add_liquidity can only be called by the same contract"); + { + let token0: Token::Token = Token::at(config.token0); + let token1: Token::Token = Token::at(config.token1); + let liquidity_token: Token::Token = Token::at(config.liquidity_token); + let balance0_plus_amount0_max: u128 = self.view(token0.balance_of_public(self.address)); + let balance0: u128 = balance0_plus_amount0_max - amount0_max; + let balance1_plus_amount1_max: u128 = self.view(token1.balance_of_public(self.address)); + let balance1: u128 = balance1_plus_amount1_max - amount1_max; + let (amount0, amount1): (u128, u128) = get_amounts_to_add(amount0_max, amount1_max, amount0_min, amount1_min, balance0, balance1); + let refund_amount_token0: u128 = amount0_max - amount0; + let refund_amount_token1: u128 = amount1_max - amount1; + if refund_amount_token0 > (0_Field as u128) { + self.call(token0.finalize_transfer_to_private(refund_amount_token0, refund_token0_partial_note)); + }; + if refund_amount_token1 > (0_Field as u128) { + self.call(token1.finalize_transfer_to_private(refund_amount_token1, refund_token1_partial_note)); + }; + let total_supply: u128 = self.view(liquidity_token.total_supply()); + let liquidity_amount: u128 = if total_supply != (0_Field as u128) { + std::cmp::min((amount0 * total_supply) / balance0, (amount1 * total_supply) / balance1) + } else { + liquidity_token.mint_to_public(AztecAddress::zero(), MINIMUM_LIQUIDITY).call(self.context); + INITIAL_LIQUIDITY + }; + assert(liquidity_amount > (0_Field as u128), "INSUFFICIENT_LIQUIDITY_MINTED"); + liquidity_token.finalize_mint_to_private(liquidity_amount, liquidity_partial_note).call(self.context); + } + } + + unconstrained fn __aztec_nr_internals___remove_liquidity(config: Config, liquidity: u128, token0_partial_note: PartialUintNote, token1_partial_note: PartialUintNote, amount0_min: u128, amount1_min: u128) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 8] = aztec::oracle::avm::calldata_copy(1_u32, ((((>::N + ::N) + ::N) + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.msg_sender() == self.address, "Function _remove_liquidity can only be called by the same contract"); + { + let token0: Token::Token = Token::at(config.token0); + let token1: Token::Token = Token::at(config.token1); + let liquidity_token: Token::Token = Token::at(config.liquidity_token); + let balance0: u128 = self.view(token0.balance_of_public(self.address)); + let balance1: u128 = self.view(token1.balance_of_public(self.address)); + let total_supply: u128 = self.view(liquidity_token.total_supply()); + let (amount0, amount1): (u128, u128) = get_amounts_on_remove(liquidity, total_supply, balance0, balance1); + assert(amount0 >= amount0_min, "INSUFFICIENT_0_AMOUNT"); + assert(amount1 >= amount1_min, "INSUFFICIENT_1_AMOUNT"); + self.call(liquidity_token.burn_public(self.address, liquidity, 0_Field)); + self.call(token0.finalize_transfer_to_private(amount0, token0_partial_note)); + self.call(token1.finalize_transfer_to_private(amount1, token1_partial_note)); + } + } + + unconstrained fn __aztec_nr_internals___swap_exact_tokens_for_tokens(token_in: AztecAddress, token_out: AztecAddress, amount_in: u128, amount_out_min: u128, token_out_partial_note: PartialUintNote) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 5] = aztec::oracle::avm::calldata_copy(1_u32, (((::N + ::N) + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.msg_sender() == self.address, "Function _swap_exact_tokens_for_tokens can only be called by the same contract"); + { + let balance_in_plus_amount_in: u128 = self.view(Token::at(token_in).balance_of_public(self.address)); + let balance_in: u128 = balance_in_plus_amount_in - amount_in; + let balance_out: u128 = self.view(Token::at(token_out).balance_of_public(self.address)); + let amount_out: u128 = get_amount_out(amount_in, balance_in, balance_out); + assert(amount_out >= amount_out_min, "INSUFFICIENT_OUTPUT_AMOUNT"); + Token::at(token_out).finalize_transfer_to_private(amount_out, token_out_partial_note).call(self.context); + } + } + + unconstrained fn __aztec_nr_internals___swap_tokens_for_exact_tokens(token_in: AztecAddress, token_out: AztecAddress, amount_in_max: u128, amount_out: u128, change_token_in_partial_note: PartialUintNote, token_out_partial_note: PartialUintNote) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 6] = aztec::oracle::avm::calldata_copy(1_u32, ((((::N + ::N) + ::N) + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.msg_sender() == self.address, "Function _swap_tokens_for_exact_tokens can only be called by the same contract"); + { + let balance_in_plus_amount_in_max: u128 = self.view(Token::at(token_in).balance_of_public(self.address)); + let balance_in: u128 = balance_in_plus_amount_in_max - amount_in_max; + let balance_out: u128 = self.view(Token::at(token_out).balance_of_public(self.address)); + let amount_in: u128 = get_amount_in(amount_out, balance_in, balance_out); + assert(amount_in <= amount_in_max, "INSUFFICIENT_OUTPUT_AMOUNT"); + let change: u128 = amount_in_max - amount_in; + if change > (0_Field as u128) { + self.call(Token::at(token_in).finalize_transfer_to_private(change, change_token_in_partial_note)); + }; + Token::at(token_out).finalize_transfer_to_private(amount_out, token_out_partial_note).call(self.context); + } + } + + unconstrained fn __aztec_nr_internals__constructor(token0: AztecAddress, token1: AztecAddress, liquidity_token: AztecAddress) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (::N + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_public(self.context); + { + self.storage.config.initialize(Config { token0: token0, token1: token1, liquidity_token: liquidity_token}); + }; + aztec::macros::functions::initialization_utils::mark_as_initialized_from_public_initializer(self.context); + } + + unconstrained fn __aztec_nr_internals__get_amount_in_for_exact_out(balance_in: u128, balance_out: u128, amount_out: u128) -> pub u128 { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_utility::ContractSelfUtility, CallSelfUtility> = { + let context: aztec::context::UtilityContext = aztec::context::UtilityContext::new(); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelfUtility = CallSelfUtility { address: self_address}; + aztec::contract_self::contract_self_utility::ContractSelfUtility::, CallSelfUtility>::new(context, storage, call_self) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_utility(self.context); + { + get_amount_in(amount_out, balance_in, balance_out) + } + } + + unconstrained fn __aztec_nr_internals__get_amount_out_for_exact_in(balance_in: u128, balance_out: u128, amount_in: u128) -> pub u128 { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_utility::ContractSelfUtility, CallSelfUtility> = { + let context: aztec::context::UtilityContext = aztec::context::UtilityContext::new(); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelfUtility = CallSelfUtility { address: self_address}; + aztec::contract_self::contract_self_utility::ContractSelfUtility::, CallSelfUtility>::new(context, storage, call_self) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_utility(self.context); + { + get_amount_out(amount_in, balance_in, balance_out) + } + } + + pub struct StorageLayoutFields { + pub config: aztec::state_vars::Storable, + } + + pub struct StorageLayout { + pub contract_name: str, + pub fields: StorageLayoutFields, + } +} + +mod test { + mod test { + use crate::AMM; + use super::utils::add_liquidity; + use super::utils::remove_liquidity; + use super::utils::setup; + use aztec::protocol::address::AztecAddress; + use aztec::protocol::traits::FromField; + use aztec::test::helpers::authwit::add_private_authwit_from_call; + use token::Token; + + global AUTHWIT_NONCE: Field = 0x01; + + global DEFAULT_AMOUNT_0_MIN: u128 = 0; + + global DEFAULT_AMOUNT_1_MIN: u128 = 0; + + #[test] + unconstrained fn add_liquidity_twice_and_remove_liquidity() { + let (mut env, amm_address, token0_address, token1_address, liquidity_token_address, minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider_1: AztecAddress = env.create_contract_account(); + let liquidity_provider_2: AztecAddress = env.create_contract_account(); + let token0: Token::Token = Token::at(token0_address); + let token1: Token::Token = Token::at(token1_address); + let liquidity_token: Token::Token = Token::at(liquidity_token_address); + let initial_amount0: u128 = 1000_Field as u128; + let initial_amount1: u128 = 2000_Field as u128; + add_liquidity(env, amm_address, token0_address, token1_address, minter, liquidity_provider_1, initial_amount0, initial_amount1, DEFAULT_AMOUNT_0_MIN, DEFAULT_AMOUNT_1_MIN); + let initial_liquidity_token_supply: u128 = env.view_public(liquidity_token.total_supply()); + assert(initial_liquidity_token_supply == (AMM::MINIMUM_LIQUIDITY + AMM::INITIAL_LIQUIDITY)); + let expected_amount_0_in: u128 = initial_amount0 / 2_u128; + let expected_amount_1_in: u128 = initial_amount1 / 2_u128; + let expected_refund_amount1: u128 = 200_Field as u128; + let amount1_max: u128 = expected_amount_1_in + expected_refund_amount1; + add_liquidity(env, amm_address, token0_address, token1_address, minter, liquidity_provider_2, expected_amount_0_in, amount1_max, DEFAULT_AMOUNT_0_MIN, DEFAULT_AMOUNT_1_MIN); + assert(env.view_public(token0.balance_of_public(amm_address)) == (initial_amount0 + expected_amount_0_in)); + assert(env.view_public(token1.balance_of_public(amm_address)) == (initial_amount1 + expected_amount_1_in)); + assert(env.execute_utility(token0.balance_of_private(liquidity_provider_2)) == 0_u128); + assert(env.execute_utility(token1.balance_of_private(liquidity_provider_2)) == expected_refund_amount1); + let expected_liquidity_tokens: u128 = (expected_amount_0_in * initial_liquidity_token_supply) / initial_amount0; + assert(env.execute_utility(liquidity_token.balance_of_private(liquidity_provider_2)) == expected_liquidity_tokens); + let liquidity_to_remove: u128 = AMM::INITIAL_LIQUIDITY / 2_u128; + let amount0_min: u128 = 400_Field as u128; + let amount1_min: u128 = 800_Field as u128; + remove_liquidity(env, amm_address, liquidity_token_address, liquidity_provider_1, liquidity_to_remove, amount0_min, amount1_min); + let expected_token0_back: u128 = (liquidity_to_remove * initial_amount0) / initial_liquidity_token_supply; + let expected_token1_back: u128 = (liquidity_to_remove * initial_amount1) / initial_liquidity_token_supply; + assert(env.execute_utility(token0.balance_of_private(liquidity_provider_1)) == expected_token0_back); + assert(env.execute_utility(token1.balance_of_private(liquidity_provider_1)) == expected_token1_back); + assert(env.execute_utility(liquidity_token.balance_of_private(liquidity_provider_1)) == (AMM::INITIAL_LIQUIDITY / 2_u128)); + } + + #[test] + unconstrained fn swap_exact_tokens_for_tokens() { + let (mut env, amm_address, token0_address, token1_address, _liquidity_token_address, minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider: AztecAddress = env.create_contract_account(); + let swapper: AztecAddress = env.create_contract_account(); + let token0: Token::Token = Token::at(token0_address); + let token1: Token::Token = Token::at(token1_address); + let amm: AMM::AMM = AMM::at(amm_address); + let liquidity_amount0: u128 = 10000_Field as u128; + let liquidity_amount1: u128 = 20000_Field as u128; + add_liquidity(env, amm_address, token0_address, token1_address, minter, liquidity_provider, liquidity_amount0, liquidity_amount1, DEFAULT_AMOUNT_0_MIN, DEFAULT_AMOUNT_1_MIN); + let amount_in: u128 = 1000_Field as u128; + let amount_out_min: u128 = 1800_Field as u128; + env.call_private(minter, token0.mint_to_private(swapper, amount_in)); + add_private_authwit_from_call(env, swapper, amm_address, token0.transfer_to_public(swapper, amm_address, amount_in, AUTHWIT_NONCE)); + env.call_private(swapper, amm.swap_exact_tokens_for_tokens(token0_address, token1_address, amount_in, amount_out_min, AUTHWIT_NONCE)); + assert(env.execute_utility(token0.balance_of_private(swapper)) == 0_u128); + assert(env.execute_utility(token1.balance_of_private(swapper)) >= amount_out_min); + } + + #[test] + unconstrained fn swap_tokens_for_exact_tokens() { + let (mut env, amm_address, token0_address, token1_address, _liquidity_token_address, minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider: AztecAddress = env.create_contract_account(); + let swapper: AztecAddress = env.create_contract_account(); + let token0: Token::Token = Token::at(token0_address); + let token1: Token::Token = Token::at(token1_address); + let amm: AMM::AMM = AMM::at(amm_address); + let liquidity_amount0: u128 = 10000_Field as u128; + let liquidity_amount1: u128 = 20000_Field as u128; + add_liquidity(env, amm_address, token0_address, token1_address, minter, liquidity_provider, liquidity_amount0, liquidity_amount1, DEFAULT_AMOUNT_0_MIN, DEFAULT_AMOUNT_1_MIN); + let amount_out: u128 = 1000_Field as u128; + let amount_in_max: u128 = 600_Field as u128; + env.call_private(minter, token0.mint_to_private(swapper, amount_in_max)); + let transfer_call: aztec::context::calls::PrivateCall<55, 4, uint_note::PartialUintNote> = token0.transfer_to_public_and_prepare_private_balance_increase(swapper, amm_address, amount_in_max, AUTHWIT_NONCE); + add_private_authwit_from_call(env, swapper, amm_address, transfer_call); + env.call_private(swapper, amm.swap_tokens_for_exact_tokens(token0_address, token1_address, amount_out, amount_in_max, AUTHWIT_NONCE)); + assert(env.execute_utility(token1.balance_of_private(swapper)) == amount_out); + let swapper_token0_balance: u128 = env.execute_utility(token0.balance_of_private(swapper)); + assert(swapper_token0_balance > 0_u128); + assert(swapper_token0_balance < amount_in_max); + } + + #[test(should_fail_with = "INCORRECT_TOKEN0_LIMITS")] + unconstrained fn add_liquidity_incorrect_token0_limits() { + let (mut env, amm_address, _token0_address, _token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let amount0_max: u128 = 500_Field as u128; + let amount1_max: u128 = 1000_Field as u128; + let amount0_min: u128 = 600_Field as u128; + let amount1_min: u128 = 500_Field as u128; + env.call_private(liquidity_provider, amm.add_liquidity(amount0_max, amount1_max, amount0_min, amount1_min, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "INCORRECT_TOKEN1_LIMITS")] + unconstrained fn add_liquidity_incorrect_token1_limits() { + let (mut env, amm_address, _token0_address, _token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let amount0_max: u128 = 500_Field as u128; + let amount1_max: u128 = 1000_Field as u128; + let amount0_min: u128 = 400_Field as u128; + let amount1_min: u128 = 1100_Field as u128; + env.call_private(liquidity_provider, amm.add_liquidity(amount0_max, amount1_max, amount0_min, amount1_min, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "INSUFFICIENT_INPUT_AMOUNTS")] + unconstrained fn add_liquidity_zero_amount0_max() { + let (mut env, amm_address, _token0_address, _token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let amount0_max: u128 = 0_Field as u128; + let amount1_max: u128 = 1000_Field as u128; + let amount0_min: u128 = 0_Field as u128; + let amount1_min: u128 = 500_Field as u128; + env.call_private(liquidity_provider, amm.add_liquidity(amount0_max, amount1_max, amount0_min, amount1_min, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "INSUFFICIENT_INPUT_AMOUNTS")] + unconstrained fn add_liquidity_zero_amount1_max() { + let (mut env, amm_address, _token0_address, _token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let amount0_max: u128 = 1000_Field as u128; + let amount1_max: u128 = 0_Field as u128; + let amount0_min: u128 = 500_Field as u128; + let amount1_min: u128 = 0_Field as u128; + env.call_private(liquidity_provider, amm.add_liquidity(amount0_max, amount1_max, amount0_min, amount1_min, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "TOKEN_IN_IS_INVALID")] + unconstrained fn swap_exact_tokens_invalid_token_in() { + let (mut env, amm_address, _token0_address, token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let swapper: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let invalid_token: AztecAddress = AztecAddress::from_field(999_Field); + let amount_in: u128 = 1000_Field as u128; + let amount_out_min: u128 = 900_Field as u128; + env.call_private(swapper, amm.swap_exact_tokens_for_tokens(invalid_token, token1_address, amount_in, amount_out_min, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "TOKEN_OUT_IS_INVALID")] + unconstrained fn swap_exact_tokens_invalid_token_out() { + let (mut env, amm_address, token0_address, _token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let swapper: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let invalid_token: AztecAddress = AztecAddress::from_field(999_Field); + let amount_in: u128 = 1000_Field as u128; + let amount_out_min: u128 = 900_Field as u128; + env.call_private(swapper, amm.swap_exact_tokens_for_tokens(token0_address, invalid_token, amount_in, amount_out_min, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "SAME_TOKEN_SWAP")] + unconstrained fn swap_exact_tokens_same_tokens() { + let (mut env, amm_address, token0_address, _token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let swapper: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let amount_in: u128 = 1000_Field as u128; + let amount_out_min: u128 = 900_Field as u128; + env.call_private(swapper, amm.swap_exact_tokens_for_tokens(token0_address, token0_address, amount_in, amount_out_min, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "TOKEN_IN_IS_INVALID")] + unconstrained fn swap_tokens_for_exact_invalid_token_in() { + let (mut env, amm_address, _token0_address, token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let swapper: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let invalid_token: AztecAddress = AztecAddress::from_field(999_Field); + let amount_out: u128 = 1000_Field as u128; + let amount_in_max: u128 = 1200_Field as u128; + env.call_private(swapper, amm.swap_tokens_for_exact_tokens(invalid_token, token1_address, amount_out, amount_in_max, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "TOKEN_OUT_IS_INVALID")] + unconstrained fn swap_tokens_for_exact_invalid_token_out() { + let (mut env, amm_address, token0_address, _token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let swapper: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let invalid_token: AztecAddress = AztecAddress::from_field(999_Field); + let amount_out: u128 = 1000_Field as u128; + let amount_in_max: u128 = 1200_Field as u128; + env.call_private(swapper, amm.swap_tokens_for_exact_tokens(token0_address, invalid_token, amount_out, amount_in_max, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "SAME_TOKEN_SWAP")] + unconstrained fn swap_tokens_for_exact_same_tokens() { + let (mut env, amm_address, token0_address, _token1_address, _liquidity_token_address, _minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let swapper: AztecAddress = env.create_contract_account(); + let amm: AMM::AMM = AMM::at(amm_address); + let amount_out: u128 = 1000_Field as u128; + let amount_in_max: u128 = 1200_Field as u128; + env.call_private(swapper, amm.swap_tokens_for_exact_tokens(token0_address, token0_address, amount_out, amount_in_max, AUTHWIT_NONCE)); + } + + #[test(should_fail_with = "INSUFFICIENT_LIQUIDITY_MINTED")] + unconstrained fn add_liquidity_insufficient_liquidity_minted() { + let (mut env, amm_address, token0_address, token1_address, _liquidity_token_address, minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider_1: AztecAddress = env.create_contract_account(); + let liquidity_provider_2: AztecAddress = env.create_contract_account(); + let initial_amount0: u128 = 100000000_Field as u128; + let initial_amount1: u128 = 200000000_Field as u128; + add_liquidity(env, amm_address, token0_address, token1_address, minter, liquidity_provider_1, initial_amount0, initial_amount1, DEFAULT_AMOUNT_0_MIN, DEFAULT_AMOUNT_1_MIN); + let tiny_amount0: u128 = 1_Field as u128; + let tiny_amount1: u128 = 2_Field as u128; + add_liquidity(env, amm_address, token0_address, token1_address, minter, liquidity_provider_2, tiny_amount0, tiny_amount1, DEFAULT_AMOUNT_0_MIN, DEFAULT_AMOUNT_1_MIN); + } + + #[test(should_fail_with = "INSUFFICIENT_0_AMOUNT")] + unconstrained fn remove_liquidity_insufficient_amount0() { + let (mut env, amm_address, token0_address, token1_address, liquidity_token_address, minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider: AztecAddress = env.create_contract_account(); + let amount0: u128 = 1000_Field as u128; + let amount1: u128 = 2000_Field as u128; + add_liquidity(env, amm_address, token0_address, token1_address, minter, liquidity_provider, amount0, amount1, DEFAULT_AMOUNT_0_MIN, DEFAULT_AMOUNT_1_MIN); + let liquidity_to_remove: u128 = AMM::INITIAL_LIQUIDITY / 2_u128; + let amount0_min: u128 = 10000_Field as u128; + let amount1_min: u128 = 800_Field as u128; + remove_liquidity(env, amm_address, liquidity_token_address, liquidity_provider, liquidity_to_remove, amount0_min, amount1_min); + } + + #[test(should_fail_with = "INSUFFICIENT_1_AMOUNT")] + unconstrained fn remove_liquidity_insufficient_amount1() { + let (mut env, amm_address, token0_address, token1_address, liquidity_token_address, minter): (aztec::test::helpers::test_environment::TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) = setup(); + let liquidity_provider: AztecAddress = env.create_contract_account(); + let amount0: u128 = 1000_Field as u128; + let amount1: u128 = 2000_Field as u128; + add_liquidity(env, amm_address, token0_address, token1_address, minter, liquidity_provider, amount0, amount1, DEFAULT_AMOUNT_0_MIN, DEFAULT_AMOUNT_1_MIN); + let liquidity_to_remove: u128 = AMM::INITIAL_LIQUIDITY / 2_u128; + let amount0_min: u128 = 400_Field as u128; + let amount1_min: u128 = 20000_Field as u128; + remove_liquidity(env, amm_address, liquidity_token_address, liquidity_provider, liquidity_to_remove, amount0_min, amount1_min); + } + } + + pub(crate) mod utils { + use crate::AMM; + use aztec::protocol::address::AztecAddress; + use aztec::test::helpers::authwit::add_private_authwit_from_call; + use aztec::test::helpers::test_environment::TestEnvironment; + use token::Token; + + global AUTHWIT_NONCE: Field = 0x01; + + pub(crate) unconstrained fn setup() -> (TestEnvironment, AztecAddress, AztecAddress, AztecAddress, AztecAddress, AztecAddress) { + let mut env: TestEnvironment = TestEnvironment::new(); + let admin: AztecAddress = env.create_contract_account(); + let token0_initializer: aztec::context::calls::PublicCall<11, 64, ()> = Token::interface().constructor(admin, "Token00000000000000000000000000", "TK00000000000000000000000000000", 18_u8); + let token0_address: AztecAddress = env.deploy("@token_contract/Token").with_public_initializer(admin, token0_initializer); + let token1_initializer: aztec::context::calls::PublicCall<11, 64, ()> = Token::interface().constructor(admin, "Token11111111111111111111111111", "TK11111111111111111111111111111", 18_u8); + let token1_address: AztecAddress = env.deploy("@token_contract/Token").with_public_initializer(admin, token1_initializer); + let liquidity_token_initializer: aztec::context::calls::PublicCall<11, 64, ()> = Token::interface().constructor(admin, "LiquidityToken00000000000000000", "LT00000000000000000000000000000", 18_u8); + let liquidity_token_address: AztecAddress = env.deploy("@token_contract/Token").with_public_initializer(admin, liquidity_token_initializer); + let amm_initializer: aztec::context::calls::PublicCall<11, 3, ()> = AMM::interface().constructor(token0_address, token1_address, liquidity_token_address); + let amm_address: AztecAddress = env.deploy("AMM").with_public_initializer(admin, amm_initializer); + env.call_public(admin, Token::at(liquidity_token_address).set_minter(amm_address, true)); + let minter: AztecAddress = admin; + (env, amm_address, token0_address, token1_address, liquidity_token_address, minter) + } + + pub(crate) unconstrained fn add_liquidity(env: TestEnvironment, amm_address: AztecAddress, token0_address: AztecAddress, token1_address: AztecAddress, minter: AztecAddress, liquidity_provider: AztecAddress, amount0_max: u128, amount1_max: u128, amount0_min: u128, amount1_min: u128) { + let token0: Token::Token = Token::at(token0_address); + let token1: Token::Token = Token::at(token1_address); + let amm: AMM::AMM = AMM::at(amm_address); + env.call_private(minter, token0.mint_to_private(liquidity_provider, amount0_max)); + env.call_private(minter, token1.mint_to_private(liquidity_provider, amount1_max)); + let transfer0_call: aztec::context::calls::PrivateCall<55, 4, uint_note::PartialUintNote> = token0.transfer_to_public_and_prepare_private_balance_increase(liquidity_provider, amm_address, amount0_max, AUTHWIT_NONCE); + add_private_authwit_from_call(env, liquidity_provider, amm_address, transfer0_call); + let transfer1_call: aztec::context::calls::PrivateCall<55, 4, uint_note::PartialUintNote> = token1.transfer_to_public_and_prepare_private_balance_increase(liquidity_provider, amm_address, amount1_max, AUTHWIT_NONCE); + add_private_authwit_from_call(env, liquidity_provider, amm_address, transfer1_call); + env.call_private(liquidity_provider, amm.add_liquidity(amount0_max, amount1_max, amount0_min, amount1_min, AUTHWIT_NONCE)); + } + + pub(crate) unconstrained fn remove_liquidity(env: TestEnvironment, amm_address: AztecAddress, liquidity_token_address: AztecAddress, liquidity_provider: AztecAddress, liquidity_amount: u128, amount0_min: u128, amount1_min: u128) { + let liquidity_token: Token::Token = Token::at(liquidity_token_address); + let amm: AMM::AMM = AMM::at(amm_address); + let transfer_liquidity_call: aztec::context::calls::PrivateCall<18, 4, ()> = liquidity_token.transfer_to_public(liquidity_provider, amm_address, liquidity_amount, AUTHWIT_NONCE); + add_private_authwit_from_call(env, liquidity_provider, amm_address, transfer_liquidity_call); + env.call_private(liquidity_provider, amm.remove_liquidity(liquidity_amount, amount0_min, amount1_min, AUTHWIT_NONCE)); + } + } +} + +// Warning: the generated code has syntax errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap new file mode 100644 index 000000000000..2f36a53d539e --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap @@ -0,0 +1,1655 @@ +--- +source: tests/snapshots.rs +expression: stdout +--- +use aztec::macros::aztec; +use aztec::macros::aztec; + +contract AvmGadgetsTest { + use aztec::macros::functions::external; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call keccak_hash. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn keccak_hash(data: [u8; 10]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call keccak_hash_300. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn keccak_hash_300(data: [u8; 300]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call keccak_hash_1400. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn keccak_hash_1400(data: [u8; 1400]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call keccak_f1600. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn keccak_f1600(data: [u64; 25]) -> [u64; 25]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call poseidon2_hash. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn poseidon2_hash(data: [Field; 10]) -> Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call poseidon2_hash_1000fields. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn poseidon2_hash_1000fields(data: [Field; 1000]) -> Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_10. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_10(data: [u8; 10]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_20. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_20(data: [u8; 20]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_30. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_30(data: [u8; 30]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_40. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_40(data: [u8; 40]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_50. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_50(data: [u8; 50]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_60. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_60(data: [u8; 60]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_70. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_70(data: [u8; 70]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_80. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_80(data: [u8; 80]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_90. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_90(data: [u8; 90]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_100. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_100(data: [u8; 100]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_255. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_255(data: [u8; 255]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_256. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_256(data: [u8; 256]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_511. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_511(data: [u8; 511]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_512. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_512(data: [u8; 512]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_1024. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_1024(data: [u8; 1024]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call sha256_hash_1536. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn sha256_hash_1536(data: [u8; 1536]) -> [u8; 32]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call pedersen_hash. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn pedersen_hash(data: [Field; 10]) -> Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call pedersen_hash_with_index. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn pedersen_hash_with_index(data: [Field; 10]) -> Field; + + /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + #[allow(dead_code)] + unconstrained fn _compute_note_hash_and_nullifier(packed_note: BoundedVec, owner: aztec::protocol::address::AztecAddress, storage_slot: Field, note_type_id: Field, contract_address: aztec::protocol::address::AztecAddress, randomness: Field, note_nonce: Field) -> Option { + _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash: Field| -> aztec::messages::discovery::NoteHashAndNullifier { + let siloed_note_hash: Field = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash); + let unique_note_hash: Field = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash); + let inner_nullifier: Option = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness); + aztec::messages::discovery::NoteHashAndNullifier { note_hash: note_hash, inner_nullifier: inner_nullifier} + }) + } + + /// This contract does not use private notes, so this function should never be called as it will unconditionally fail. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_hash(_packed_note: BoundedVec, _owner: aztec::protocol::address::AztecAddress, _storage_slot: Field, _note_type_id: Field, _contract_address: aztec::protocol::address::AztecAddress, _randomness: Field) -> Option { + panic(f"This contract does not use private notes") + } + + /// This contract does not use private notes, so this function should never be called as it will unconditionally fail. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_nullifier(_unique_note_hash: Field, _packed_note: BoundedVec, _owner: aztec::protocol::address::AztecAddress, _storage_slot: Field, _note_type_id: Field, _contract_address: aztec::protocol::address::AztecAddress, _randomness: Field) -> Option { + panic(f"This contract does not use private notes") + } + + /// Receives offchain messages into this contract's offchain inbox for subsequent processing. + /// + /// Each message is routed to the inbox scoped to its `recipient` field. + /// + /// For more details, see `aztec::messages::processing::offchain::receive`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + unconstrained fn offchain_receive(messages: BoundedVec) { + let address: aztec::protocol::address::AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::processing::offchain::receive(address, messages); + } + + pub struct AvmGadgetsTest { + pub target_contract: aztec::protocol::address::AztecAddress, + } + + impl AvmGadgetsTest { + pub fn at(addr: aztec::protocol::address::AztecAddress) -> Self { + Self { target_contract: addr} + } + + pub fn interface() -> Self { + Self { target_contract: aztec::protocol::address::AztecAddress::zero()} + } + + pub fn sha256_hash_1536(self, data: [u8; 1536]) -> aztec::context::calls::PublicCall<16, 1536, [u8; 32]> { + let serialized_params: [Field; 1536] = <[u8; 1536] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(373006257_Field); + aztec::context::calls::PublicCall::<16, 1536, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_1536", serialized_params) + } + + pub fn pedersen_hash_with_index(self, data: [Field; 10]) -> aztec::context::calls::PublicCall<24, 10, Field> { + let serialized_params: [Field; 10] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3265405934_Field); + aztec::context::calls::PublicCall::<24, 10, Field>::new(self.target_contract, selector, "pedersen_hash_with_index", serialized_params) + } + + pub fn keccak_hash(self, data: [u8; 10]) -> aztec::context::calls::PublicCall<11, 10, [u8; 32]> { + let serialized_params: [Field; 10] = <[u8; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1352369823_Field); + aztec::context::calls::PublicCall::<11, 10, [u8; 32]>::new(self.target_contract, selector, "keccak_hash", serialized_params) + } + + pub fn sha256_hash_511(self, data: [u8; 511]) -> aztec::context::calls::PublicCall<15, 511, [u8; 32]> { + let serialized_params: [Field; 511] = <[u8; 511] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(797967809_Field); + aztec::context::calls::PublicCall::<15, 511, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_511", serialized_params) + } + + pub fn sha256_hash_100(self, data: [u8; 100]) -> aztec::context::calls::PublicCall<15, 100, [u8; 32]> { + let serialized_params: [Field; 100] = <[u8; 100] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2074027672_Field); + aztec::context::calls::PublicCall::<15, 100, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_100", serialized_params) + } + + pub fn sha256_hash_80(self, data: [u8; 80]) -> aztec::context::calls::PublicCall<14, 80, [u8; 32]> { + let serialized_params: [Field; 80] = <[u8; 80] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4268069756_Field); + aztec::context::calls::PublicCall::<14, 80, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_80", serialized_params) + } + + pub fn pedersen_hash(self, data: [Field; 10]) -> aztec::context::calls::PublicCall<13, 10, Field> { + let serialized_params: [Field; 10] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2669406607_Field); + aztec::context::calls::PublicCall::<13, 10, Field>::new(self.target_contract, selector, "pedersen_hash", serialized_params) + } + + pub fn sha256_hash_20(self, data: [u8; 20]) -> aztec::context::calls::PublicCall<14, 20, [u8; 32]> { + let serialized_params: [Field; 20] = <[u8; 20] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2926274626_Field); + aztec::context::calls::PublicCall::<14, 20, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_20", serialized_params) + } + + pub fn poseidon2_hash(self, data: [Field; 10]) -> aztec::context::calls::PublicCall<14, 10, Field> { + let serialized_params: [Field; 10] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3724082008_Field); + aztec::context::calls::PublicCall::<14, 10, Field>::new(self.target_contract, selector, "poseidon2_hash", serialized_params) + } + + pub fn sha256_hash_512(self, data: [u8; 512]) -> aztec::context::calls::PublicCall<15, 512, [u8; 32]> { + let serialized_params: [Field; 512] = <[u8; 512] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2560938307_Field); + aztec::context::calls::PublicCall::<15, 512, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_512", serialized_params) + } + + pub fn keccak_f1600(self, data: [u64; 25]) -> aztec::context::calls::PublicCall<12, 25, [u64; 25]> { + let serialized_params: [Field; 25] = <[u64; 25] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1867977279_Field); + aztec::context::calls::PublicCall::<12, 25, [u64; 25]>::new(self.target_contract, selector, "keccak_f1600", serialized_params) + } + + pub fn sha256_hash_30(self, data: [u8; 30]) -> aztec::context::calls::PublicCall<14, 30, [u8; 32]> { + let serialized_params: [Field; 30] = <[u8; 30] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3609677267_Field); + aztec::context::calls::PublicCall::<14, 30, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_30", serialized_params) + } + + pub fn sha256_hash_50(self, data: [u8; 50]) -> aztec::context::calls::PublicCall<14, 50, [u8; 32]> { + let serialized_params: [Field; 50] = <[u8; 50] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(256881939_Field); + aztec::context::calls::PublicCall::<14, 50, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_50", serialized_params) + } + + pub fn sha256_hash_60(self, data: [u8; 60]) -> aztec::context::calls::PublicCall<14, 60, [u8; 32]> { + let serialized_params: [Field; 60] = <[u8; 60] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2495458303_Field); + aztec::context::calls::PublicCall::<14, 60, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_60", serialized_params) + } + + pub fn poseidon2_hash_1000fields(self, data: [Field; 1000]) -> aztec::context::calls::PublicCall<25, 1000, Field> { + let serialized_params: [Field; 1000] = <[Field; 1000] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(278602445_Field); + aztec::context::calls::PublicCall::<25, 1000, Field>::new(self.target_contract, selector, "poseidon2_hash_1000fields", serialized_params) + } + + pub fn sha256_hash_70(self, data: [u8; 70]) -> aztec::context::calls::PublicCall<14, 70, [u8; 32]> { + let serialized_params: [Field; 70] = <[u8; 70] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2200074453_Field); + aztec::context::calls::PublicCall::<14, 70, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_70", serialized_params) + } + + pub fn sha256_hash_90(self, data: [u8; 90]) -> aztec::context::calls::PublicCall<14, 90, [u8; 32]> { + let serialized_params: [Field; 90] = <[u8; 90] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(799349905_Field); + aztec::context::calls::PublicCall::<14, 90, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_90", serialized_params) + } + + pub fn sha256_hash_40(self, data: [u8; 40]) -> aztec::context::calls::PublicCall<14, 40, [u8; 32]> { + let serialized_params: [Field; 40] = <[u8; 40] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(900925045_Field); + aztec::context::calls::PublicCall::<14, 40, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_40", serialized_params) + } + + pub fn sha256_hash_10(self, data: [u8; 10]) -> aztec::context::calls::PublicCall<14, 10, [u8; 32]> { + let serialized_params: [Field; 10] = <[u8; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3545543018_Field); + aztec::context::calls::PublicCall::<14, 10, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_10", serialized_params) + } + + pub fn sha256_hash_1024(self, data: [u8; 1024]) -> aztec::context::calls::PublicCall<16, 1024, [u8; 32]> { + let serialized_params: [Field; 1024] = <[u8; 1024] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2235915052_Field); + aztec::context::calls::PublicCall::<16, 1024, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_1024", serialized_params) + } + + pub fn sha256_hash_255(self, data: [u8; 255]) -> aztec::context::calls::PublicCall<15, 255, [u8; 32]> { + let serialized_params: [Field; 255] = <[u8; 255] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3548859530_Field); + aztec::context::calls::PublicCall::<15, 255, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_255", serialized_params) + } + + pub fn sha256_hash_256(self, data: [u8; 256]) -> aztec::context::calls::PublicCall<15, 256, [u8; 32]> { + let serialized_params: [Field; 256] = <[u8; 256] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3409224101_Field); + aztec::context::calls::PublicCall::<15, 256, [u8; 32]>::new(self.target_contract, selector, "sha256_hash_256", serialized_params) + } + + pub fn keccak_hash_1400(self, data: [u8; 1400]) -> aztec::context::calls::PublicCall<16, 1400, [u8; 32]> { + let serialized_params: [Field; 1400] = <[u8; 1400] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(372001522_Field); + aztec::context::calls::PublicCall::<16, 1400, [u8; 32]>::new(self.target_contract, selector, "keccak_hash_1400", serialized_params) + } + + pub fn keccak_hash_300(self, data: [u8; 300]) -> aztec::context::calls::PublicCall<15, 300, [u8; 32]> { + let serialized_params: [Field; 300] = <[u8; 300] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3065624740_Field); + aztec::context::calls::PublicCall::<15, 300, [u8; 32]>::new(self.target_contract, selector, "keccak_hash_300", serialized_params) + } + + pub fn offchain_receive(self, messages: BoundedVec) -> aztec::context::calls::UtilityCall<16, 321, ()> { + let serialized_params: [Field; 321] = as aztec::protocol::traits::Serialize>::serialize(messages); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1396850735_Field); + aztec::context::calls::UtilityCall::<16, 321, ()>::new(self.target_contract, selector, "offchain_receive", serialized_params) + } + } + + #[contract_library_method] + pub fn at(addr: aztec::protocol::address::AztecAddress) -> AvmGadgetsTest { + AvmGadgetsTest { target_contract: addr} + } + + #[contract_library_method] + pub fn interface() -> AvmGadgetsTest { + AvmGadgetsTest { target_contract: aztec::protocol::address::AztecAddress::zero()} + } + + pub struct sync_state_parameters { + pub scope: aztec::protocol::address::AztecAddress, + } + + #[abi(functions)] + pub struct sync_state_abi { + parameters: sync_state_parameters, + } + + unconstrained fn sync_state(scope: aztec::protocol::address::AztecAddress) { + let address: aztec::protocol::address::AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::discovery::do_sync_state(address, _compute_note_hash, _compute_note_nullifier, Option::>::none(), Option:: aztec::ephemeral::EphemeralArray>::some(aztec::messages::processing::offchain::sync_inbox), scope); + } + + pub struct offchain_receive_parameters { + pub messages: BoundedVec, + } + + #[abi(functions)] + pub struct offchain_receive_abi { + parameters: offchain_receive_parameters, + } + + pub struct CallSelf { + pub address: aztec::protocol::address::AztecAddress, + pub context: Context, + } + + impl CallSelf { + pub fn sha256_hash_1536(self, data: [u8; 1536]) -> [u8; 32] { + let serialized_params: [Field; 1536 * 1] = <[u8; 1536] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(373006257_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 1536 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_1536", serialized_params).call(self.context) + } + } + + pub fn pedersen_hash_with_index(self, data: [Field; 10]) -> Field { + let serialized_params: [Field; 10 * 1] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3265405934_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<24, 10 * 1, Field>::new(self.address, selector, "pedersen_hash_with_index", serialized_params).call(self.context) + } + } + + pub fn keccak_hash(self, data: [u8; 10]) -> [u8; 32] { + let serialized_params: [Field; 10 * 1] = <[u8; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1352369823_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<11, 10 * 1, [u8; 32]>::new(self.address, selector, "keccak_hash", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_511(self, data: [u8; 511]) -> [u8; 32] { + let serialized_params: [Field; 511 * 1] = <[u8; 511] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(797967809_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 511 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_511", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_100(self, data: [u8; 100]) -> [u8; 32] { + let serialized_params: [Field; 100 * 1] = <[u8; 100] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2074027672_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 100 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_100", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_80(self, data: [u8; 80]) -> [u8; 32] { + let serialized_params: [Field; 80 * 1] = <[u8; 80] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4268069756_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 80 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_80", serialized_params).call(self.context) + } + } + + pub fn pedersen_hash(self, data: [Field; 10]) -> Field { + let serialized_params: [Field; 10 * 1] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2669406607_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 10 * 1, Field>::new(self.address, selector, "pedersen_hash", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_20(self, data: [u8; 20]) -> [u8; 32] { + let serialized_params: [Field; 20 * 1] = <[u8; 20] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2926274626_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 20 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_20", serialized_params).call(self.context) + } + } + + pub fn poseidon2_hash(self, data: [Field; 10]) -> Field { + let serialized_params: [Field; 10 * 1] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3724082008_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 10 * 1, Field>::new(self.address, selector, "poseidon2_hash", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_512(self, data: [u8; 512]) -> [u8; 32] { + let serialized_params: [Field; 512 * 1] = <[u8; 512] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2560938307_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 512 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_512", serialized_params).call(self.context) + } + } + + pub fn keccak_f1600(self, data: [u64; 25]) -> [u64; 25] { + let serialized_params: [Field; 25 * 1] = <[u64; 25] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1867977279_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<12, 25 * 1, [u64; 25]>::new(self.address, selector, "keccak_f1600", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_30(self, data: [u8; 30]) -> [u8; 32] { + let serialized_params: [Field; 30 * 1] = <[u8; 30] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3609677267_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 30 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_30", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_50(self, data: [u8; 50]) -> [u8; 32] { + let serialized_params: [Field; 50 * 1] = <[u8; 50] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(256881939_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 50 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_50", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_60(self, data: [u8; 60]) -> [u8; 32] { + let serialized_params: [Field; 60 * 1] = <[u8; 60] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2495458303_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 60 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_60", serialized_params).call(self.context) + } + } + + pub fn poseidon2_hash_1000fields(self, data: [Field; 1000]) -> Field { + let serialized_params: [Field; 1000 * 1] = <[Field; 1000] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(278602445_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<25, 1000 * 1, Field>::new(self.address, selector, "poseidon2_hash_1000fields", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_70(self, data: [u8; 70]) -> [u8; 32] { + let serialized_params: [Field; 70 * 1] = <[u8; 70] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2200074453_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 70 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_70", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_90(self, data: [u8; 90]) -> [u8; 32] { + let serialized_params: [Field; 90 * 1] = <[u8; 90] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(799349905_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 90 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_90", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_40(self, data: [u8; 40]) -> [u8; 32] { + let serialized_params: [Field; 40 * 1] = <[u8; 40] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(900925045_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 40 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_40", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_10(self, data: [u8; 10]) -> [u8; 32] { + let serialized_params: [Field; 10 * 1] = <[u8; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3545543018_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 10 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_10", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_1024(self, data: [u8; 1024]) -> [u8; 32] { + let serialized_params: [Field; 1024 * 1] = <[u8; 1024] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2235915052_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 1024 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_1024", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_255(self, data: [u8; 255]) -> [u8; 32] { + let serialized_params: [Field; 255 * 1] = <[u8; 255] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3548859530_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 255 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_255", serialized_params).call(self.context) + } + } + + pub fn sha256_hash_256(self, data: [u8; 256]) -> [u8; 32] { + let serialized_params: [Field; 256 * 1] = <[u8; 256] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3409224101_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 256 * 1, [u8; 32]>::new(self.address, selector, "sha256_hash_256", serialized_params).call(self.context) + } + } + + pub fn keccak_hash_1400(self, data: [u8; 1400]) -> [u8; 32] { + let serialized_params: [Field; 1400 * 1] = <[u8; 1400] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(372001522_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 1400 * 1, [u8; 32]>::new(self.address, selector, "keccak_hash_1400", serialized_params).call(self.context) + } + } + + pub fn keccak_hash_300(self, data: [u8; 300]) -> [u8; 32] { + let serialized_params: [Field; 300 * 1] = <[u8; 300] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3065624740_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 300 * 1, [u8; 32]>::new(self.address, selector, "keccak_hash_300", serialized_params).call(self.context) + } + } + } + + pub struct CallSelfStatic { + pub address: aztec::protocol::address::AztecAddress, + pub context: Context, + } + + pub struct EnqueueSelf { + pub address: aztec::protocol::address::AztecAddress, + pub context: Context, + } + + impl EnqueueSelf<&mut aztec::context::PrivateContext> { + pub fn sha256_hash_1536(self, data: [u8; 1536]) { + let serialized_params: [Field; 1536 * 1] = <[u8; 1536] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(373006257_Field); + let calldata: [Field; 1 + (1536 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn pedersen_hash_with_index(self, data: [Field; 10]) { + let serialized_params: [Field; 10 * 1] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3265405934_Field); + let calldata: [Field; 1 + (10 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn keccak_hash(self, data: [u8; 10]) { + let serialized_params: [Field; 10 * 1] = <[u8; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1352369823_Field); + let calldata: [Field; 1 + (10 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_511(self, data: [u8; 511]) { + let serialized_params: [Field; 511 * 1] = <[u8; 511] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(797967809_Field); + let calldata: [Field; 1 + (511 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_100(self, data: [u8; 100]) { + let serialized_params: [Field; 100 * 1] = <[u8; 100] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2074027672_Field); + let calldata: [Field; 1 + (100 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_80(self, data: [u8; 80]) { + let serialized_params: [Field; 80 * 1] = <[u8; 80] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4268069756_Field); + let calldata: [Field; 1 + (80 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn pedersen_hash(self, data: [Field; 10]) { + let serialized_params: [Field; 10 * 1] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2669406607_Field); + let calldata: [Field; 1 + (10 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_20(self, data: [u8; 20]) { + let serialized_params: [Field; 20 * 1] = <[u8; 20] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2926274626_Field); + let calldata: [Field; 1 + (20 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn poseidon2_hash(self, data: [Field; 10]) { + let serialized_params: [Field; 10 * 1] = <[Field; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3724082008_Field); + let calldata: [Field; 1 + (10 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_512(self, data: [u8; 512]) { + let serialized_params: [Field; 512 * 1] = <[u8; 512] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2560938307_Field); + let calldata: [Field; 1 + (512 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn keccak_f1600(self, data: [u64; 25]) { + let serialized_params: [Field; 25 * 1] = <[u64; 25] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1867977279_Field); + let calldata: [Field; 1 + (25 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_30(self, data: [u8; 30]) { + let serialized_params: [Field; 30 * 1] = <[u8; 30] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3609677267_Field); + let calldata: [Field; 1 + (30 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_50(self, data: [u8; 50]) { + let serialized_params: [Field; 50 * 1] = <[u8; 50] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(256881939_Field); + let calldata: [Field; 1 + (50 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_60(self, data: [u8; 60]) { + let serialized_params: [Field; 60 * 1] = <[u8; 60] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2495458303_Field); + let calldata: [Field; 1 + (60 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn poseidon2_hash_1000fields(self, data: [Field; 1000]) { + let serialized_params: [Field; 1000 * 1] = <[Field; 1000] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(278602445_Field); + let calldata: [Field; 1 + (1000 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_70(self, data: [u8; 70]) { + let serialized_params: [Field; 70 * 1] = <[u8; 70] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2200074453_Field); + let calldata: [Field; 1 + (70 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_90(self, data: [u8; 90]) { + let serialized_params: [Field; 90 * 1] = <[u8; 90] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(799349905_Field); + let calldata: [Field; 1 + (90 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_40(self, data: [u8; 40]) { + let serialized_params: [Field; 40 * 1] = <[u8; 40] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(900925045_Field); + let calldata: [Field; 1 + (40 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_10(self, data: [u8; 10]) { + let serialized_params: [Field; 10 * 1] = <[u8; 10] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3545543018_Field); + let calldata: [Field; 1 + (10 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_1024(self, data: [u8; 1024]) { + let serialized_params: [Field; 1024 * 1] = <[u8; 1024] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2235915052_Field); + let calldata: [Field; 1 + (1024 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_255(self, data: [u8; 255]) { + let serialized_params: [Field; 255 * 1] = <[u8; 255] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3548859530_Field); + let calldata: [Field; 1 + (255 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn sha256_hash_256(self, data: [u8; 256]) { + let serialized_params: [Field; 256 * 1] = <[u8; 256] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3409224101_Field); + let calldata: [Field; 1 + (256 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn keccak_hash_1400(self, data: [u8; 1400]) { + let serialized_params: [Field; 1400 * 1] = <[u8; 1400] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(372001522_Field); + let calldata: [Field; 1 + (1400 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn keccak_hash_300(self, data: [u8; 300]) { + let serialized_params: [Field; 300 * 1] = <[u8; 300] as aztec::protocol::traits::Serialize>::serialize(data); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3065624740_Field); + let calldata: [Field; 1 + (300 * 1)] = [::to_field(selector)].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + } + + pub struct EnqueueSelfStatic { + pub address: aztec::protocol::address::AztecAddress, + pub context: Context, + } + + pub struct CallSelfUtility { + pub address: aztec::protocol::address::AztecAddress, + } + + pub struct CallInternal { + pub context: Context, + } + + pub unconstrained fn public_dispatch(selector: Field) { + if selector == 1352369823_Field { + let input_calldata: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 10] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<10 * 1> = aztec::protocol::utils::reader::Reader::<10 * 1>::new(input_calldata); + let arg0: [u8; 10] = <[u8; 10] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__keccak_hash(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3065624740_Field { + let input_calldata: [Field; 300 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 300] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<300 * 1> = aztec::protocol::utils::reader::Reader::<300 * 1>::new(input_calldata); + let arg0: [u8; 300] = <[u8; 300] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__keccak_hash_300(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 372001522_Field { + let input_calldata: [Field; 1400 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 1400] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<1400 * 1> = aztec::protocol::utils::reader::Reader::<1400 * 1>::new(input_calldata); + let arg0: [u8; 1400] = <[u8; 1400] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__keccak_hash_1400(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1867977279_Field { + let input_calldata: [Field; 25 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u64; 25] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<25 * 1> = aztec::protocol::utils::reader::Reader::<25 * 1>::new(input_calldata); + let arg0: [u64; 25] = <[u64; 25] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 25 * 1] = <[u64; 25] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__keccak_f1600(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3724082008_Field { + let input_calldata: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 10] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<10 * 1> = aztec::protocol::utils::reader::Reader::<10 * 1>::new(input_calldata); + let arg0: [Field; 10] = <[Field; 10] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__poseidon2_hash(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 278602445_Field { + let input_calldata: [Field; 1000 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 1000] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<1000 * 1> = aztec::protocol::utils::reader::Reader::<1000 * 1>::new(input_calldata); + let arg0: [Field; 1000] = <[Field; 1000] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__poseidon2_hash_1000fields(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3545543018_Field { + let input_calldata: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 10] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<10 * 1> = aztec::protocol::utils::reader::Reader::<10 * 1>::new(input_calldata); + let arg0: [u8; 10] = <[u8; 10] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_10(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2926274626_Field { + let input_calldata: [Field; 20 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 20] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<20 * 1> = aztec::protocol::utils::reader::Reader::<20 * 1>::new(input_calldata); + let arg0: [u8; 20] = <[u8; 20] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_20(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3609677267_Field { + let input_calldata: [Field; 30 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 30] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<30 * 1> = aztec::protocol::utils::reader::Reader::<30 * 1>::new(input_calldata); + let arg0: [u8; 30] = <[u8; 30] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_30(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 900925045_Field { + let input_calldata: [Field; 40 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 40] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<40 * 1> = aztec::protocol::utils::reader::Reader::<40 * 1>::new(input_calldata); + let arg0: [u8; 40] = <[u8; 40] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_40(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 256881939_Field { + let input_calldata: [Field; 50 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 50] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<50 * 1> = aztec::protocol::utils::reader::Reader::<50 * 1>::new(input_calldata); + let arg0: [u8; 50] = <[u8; 50] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_50(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2495458303_Field { + let input_calldata: [Field; 60 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 60] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<60 * 1> = aztec::protocol::utils::reader::Reader::<60 * 1>::new(input_calldata); + let arg0: [u8; 60] = <[u8; 60] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_60(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2200074453_Field { + let input_calldata: [Field; 70 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 70] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<70 * 1> = aztec::protocol::utils::reader::Reader::<70 * 1>::new(input_calldata); + let arg0: [u8; 70] = <[u8; 70] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_70(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 4268069756_Field { + let input_calldata: [Field; 80 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 80] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<80 * 1> = aztec::protocol::utils::reader::Reader::<80 * 1>::new(input_calldata); + let arg0: [u8; 80] = <[u8; 80] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_80(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 799349905_Field { + let input_calldata: [Field; 90 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 90] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<90 * 1> = aztec::protocol::utils::reader::Reader::<90 * 1>::new(input_calldata); + let arg0: [u8; 90] = <[u8; 90] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_90(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2074027672_Field { + let input_calldata: [Field; 100 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 100] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<100 * 1> = aztec::protocol::utils::reader::Reader::<100 * 1>::new(input_calldata); + let arg0: [u8; 100] = <[u8; 100] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_100(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3548859530_Field { + let input_calldata: [Field; 255 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 255] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<255 * 1> = aztec::protocol::utils::reader::Reader::<255 * 1>::new(input_calldata); + let arg0: [u8; 255] = <[u8; 255] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_255(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3409224101_Field { + let input_calldata: [Field; 256 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 256] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<256 * 1> = aztec::protocol::utils::reader::Reader::<256 * 1>::new(input_calldata); + let arg0: [u8; 256] = <[u8; 256] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_256(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 797967809_Field { + let input_calldata: [Field; 511 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 511] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<511 * 1> = aztec::protocol::utils::reader::Reader::<511 * 1>::new(input_calldata); + let arg0: [u8; 511] = <[u8; 511] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_511(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2560938307_Field { + let input_calldata: [Field; 512 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 512] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<512 * 1> = aztec::protocol::utils::reader::Reader::<512 * 1>::new(input_calldata); + let arg0: [u8; 512] = <[u8; 512] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_512(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2235915052_Field { + let input_calldata: [Field; 1024 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 1024] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<1024 * 1> = aztec::protocol::utils::reader::Reader::<1024 * 1>::new(input_calldata); + let arg0: [u8; 1024] = <[u8; 1024] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_1024(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 373006257_Field { + let input_calldata: [Field; 1536 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 1536] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<1536 * 1> = aztec::protocol::utils::reader::Reader::<1536 * 1>::new(input_calldata); + let arg0: [u8; 1536] = <[u8; 1536] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 32 * 1] = <[u8; 32] as aztec::protocol::traits::Serialize>::serialize(__aztec_nr_internals__sha256_hash_1536(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2669406607_Field { + let input_calldata: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 10] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<10 * 1> = aztec::protocol::utils::reader::Reader::<10 * 1>::new(input_calldata); + let arg0: [Field; 10] = <[Field; 10] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__pedersen_hash(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3265405934_Field { + let input_calldata: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 10] as aztec::protocol::traits::Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<10 * 1> = aztec::protocol::utils::reader::Reader::<10 * 1>::new(input_calldata); + let arg0: [Field; 10] = <[Field; 10] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__pedersen_hash_with_index(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + panic(f"Unknown selector {selector}") + } + + pub struct keccak_f1600_parameters { + pub data: [u64; 25], + } + + pub struct keccak_hash_1400_parameters { + pub data: [u8; 1400], + } + + pub struct keccak_hash_300_parameters { + pub data: [u8; 300], + } + + pub struct keccak_hash_parameters { + pub data: [u8; 10], + } + + pub struct pedersen_hash_parameters { + pub data: [Field; 10], + } + + pub struct pedersen_hash_with_index_parameters { + pub data: [Field; 10], + } + + pub struct poseidon2_hash_1000fields_parameters { + pub data: [Field; 1000], + } + + pub struct poseidon2_hash_parameters { + pub data: [Field; 10], + } + + pub struct sha256_hash_100_parameters { + pub data: [u8; 100], + } + + pub struct sha256_hash_1024_parameters { + pub data: [u8; 1024], + } + + pub struct sha256_hash_10_parameters { + pub data: [u8; 10], + } + + pub struct sha256_hash_1536_parameters { + pub data: [u8; 1536], + } + + pub struct sha256_hash_20_parameters { + pub data: [u8; 20], + } + + pub struct sha256_hash_255_parameters { + pub data: [u8; 255], + } + + pub struct sha256_hash_256_parameters { + pub data: [u8; 256], + } + + pub struct sha256_hash_30_parameters { + pub data: [u8; 30], + } + + pub struct sha256_hash_40_parameters { + pub data: [u8; 40], + } + + pub struct sha256_hash_50_parameters { + pub data: [u8; 50], + } + + pub struct sha256_hash_511_parameters { + pub data: [u8; 511], + } + + pub struct sha256_hash_512_parameters { + pub data: [u8; 512], + } + + pub struct sha256_hash_60_parameters { + pub data: [u8; 60], + } + + pub struct sha256_hash_70_parameters { + pub data: [u8; 70], + } + + pub struct sha256_hash_80_parameters { + pub data: [u8; 80], + } + + pub struct sha256_hash_90_parameters { + pub data: [u8; 90], + } + + #[abi(functions)] + pub struct keccak_f1600_abi { + parameters: keccak_f1600_parameters, + return_type: [u64; 25], + } + + #[abi(functions)] + pub struct keccak_hash_1400_abi { + parameters: keccak_hash_1400_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct keccak_hash_300_abi { + parameters: keccak_hash_300_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct keccak_hash_abi { + parameters: keccak_hash_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct pedersen_hash_abi { + parameters: pedersen_hash_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct pedersen_hash_with_index_abi { + parameters: pedersen_hash_with_index_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct poseidon2_hash_1000fields_abi { + parameters: poseidon2_hash_1000fields_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct poseidon2_hash_abi { + parameters: poseidon2_hash_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct sha256_hash_100_abi { + parameters: sha256_hash_100_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_1024_abi { + parameters: sha256_hash_1024_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_10_abi { + parameters: sha256_hash_10_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_1536_abi { + parameters: sha256_hash_1536_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_20_abi { + parameters: sha256_hash_20_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_255_abi { + parameters: sha256_hash_255_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_256_abi { + parameters: sha256_hash_256_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_30_abi { + parameters: sha256_hash_30_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_40_abi { + parameters: sha256_hash_40_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_50_abi { + parameters: sha256_hash_50_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_511_abi { + parameters: sha256_hash_511_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_512_abi { + parameters: sha256_hash_512_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_60_abi { + parameters: sha256_hash_60_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_70_abi { + parameters: sha256_hash_70_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_80_abi { + parameters: sha256_hash_80_parameters, + return_type: [u8; 32], + } + + #[abi(functions)] + pub struct sha256_hash_90_abi { + parameters: sha256_hash_90_parameters, + return_type: [u8; 32], + } + + unconstrained fn __aztec_nr_internals__keccak_f1600(data: [u64; 25]) -> pub [u64; 25] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 25 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u64; 25] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + std::hash::keccakf1600(data) + } + } + + unconstrained fn __aztec_nr_internals__keccak_hash(data: [u8; 10]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 10] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + keccak256::keccak256(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__keccak_hash_1400(data: [u8; 1400]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1400 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 1400] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + keccak256::keccak256(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__keccak_hash_300(data: [u8; 300]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 300 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 300] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + keccak256::keccak256(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__pedersen_hash(data: [Field; 10]) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 10] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + std::hash::pedersen_hash(data) + } + } + + unconstrained fn __aztec_nr_internals__pedersen_hash_with_index(data: [Field; 10]) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 10] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + std::hash::pedersen_hash_with_separator(data, 20_u32) + } + } + + unconstrained fn __aztec_nr_internals__poseidon2_hash(data: [Field; 10]) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 10] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + poseidon::poseidon2::Poseidon2::hash(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__poseidon2_hash_1000fields(data: [Field; 1000]) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1000 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 1000] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + poseidon::poseidon2::Poseidon2::hash(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_10(data: [u8; 10]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 10 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 10] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_100(data: [u8; 100]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 100 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 100] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_1024(data: [u8; 1024]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1024 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 1024] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_1536(data: [u8; 1536]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1536 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 1536] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_20(data: [u8; 20]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 20 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 20] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_255(data: [u8; 255]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 255 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 255] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_256(data: [u8; 256]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 256 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 256] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_30(data: [u8; 30]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 30 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 30] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_40(data: [u8; 40]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 40 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 40] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_50(data: [u8; 50]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 50 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 50] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_511(data: [u8; 511]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 511 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 511] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_512(data: [u8; 512]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 512 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 512] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_60(data: [u8; 60]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 60 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 60] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_70(data: [u8; 70]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 70 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 70] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_80(data: [u8; 80]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 80 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 80] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } + + unconstrained fn __aztec_nr_internals__sha256_hash_90(data: [u8; 90]) -> pub [u8; 32] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 90 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[u8; 90] as aztec::protocol::traits::Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: aztec::protocol::address::AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + sha256::sha256_var(data, data.len()) + } + } +} + +// Warning: the generated code has syntax errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap new file mode 100644 index 000000000000..7b88b9531a0c --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap @@ -0,0 +1,7788 @@ +--- +source: tests/snapshots.rs +expression: stdout +--- +use aztec::macros::aztec; +use aztec::macros::aztec; + +mod fake_avm_oracle { + use aztec::protocol::address::AztecAddress; + + pub unconstrained fn call(l2_gas_allocation: u32, da_gas_allocation: u32, address: AztecAddress, args: [Field; N]) { + call_opcode(l2_gas_allocation, da_gas_allocation, address, N, args) + } + + pub unconstrained fn success_copy() -> bool { + success_copy_opcode() + } + + pub unconstrained fn returndata_size() -> u32 { + returndata_size_opcode() + } + + pub unconstrained fn returndata_copy(rdoffset: u32, copy_size: u32) -> [Field] { + returndata_copy_opcode(rdoffset, copy_size) + } + + pub unconstrained fn avm_return(returndata: [Field]) { + return_opcode(returndata) + } + + pub unconstrained fn revert(revertdata: [Field]) { + revert_opcode(revertdata) + } + + #[oracle(aztec_avm_call)] + unconstrained fn call_opcode(l2_gas_allocation: u32, da_gas_allocation: u32, address: AztecAddress, length: u32, args: [Field; N]) {} + + #[oracle(aztec_avm_successCopy)] + unconstrained fn success_copy_opcode() -> bool {} + + #[oracle(aztec_avm_returndataSize)] + unconstrained fn returndata_size_opcode() -> u32 {} + + #[oracle(aztec_avm_returndataCopy)] + unconstrained fn returndata_copy_opcode(rdoffset: u32, copy_size: u32) -> [Field] {} + + #[oracle(aztec_avm_return)] + unconstrained fn return_opcode(returndata: [Field]) {} + + #[oracle(aztec_avm_revert)] + unconstrained fn revert_opcode(revertdata: [Field]) {} +} + +pub contract AvmTest { + use crate::note::Note; + use crate::fake_avm_oracle::avm_return; + use crate::fake_avm_oracle::call; + use crate::fake_avm_oracle::returndata_copy; + use crate::fake_avm_oracle::returndata_size; + use crate::fake_avm_oracle::revert; + use crate::fake_avm_oracle::success_copy; + use aztec::context::gas::GasOpts; + use aztec::macros::functions::external; + use aztec::macros::functions::view; + use aztec::macros::storage::storage; + use aztec::oracle::get_contract_instance::get_contract_instance_class_id_avm; + use aztec::oracle::get_contract_instance::get_contract_instance_deployer_avm; + use aztec::oracle::get_contract_instance::get_contract_instance_initialization_hash_avm; + use aztec::protocol::abis::function_selector::FunctionSelector; + use aztec::protocol::address::AztecAddress; + use aztec::protocol::address::EthAddress; + use aztec::protocol::point::Point; + use std::embedded_curve_ops::EmbeddedCurveScalar as Scalar; + use aztec::protocol::constants::CANONICAL_AUTH_REGISTRY_ADDRESS; + use aztec::protocol::constants::CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS; + use aztec::protocol::constants::FEE_JUICE_ADDRESS; + use aztec::protocol::constants::GRUMPKIN_ONE_X; + use aztec::protocol::constants::GRUMPKIN_ONE_Y; + use aztec::protocol::constants::MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS; + use aztec::protocol::contract_class_id::ContractClassId; + use aztec::protocol::storage::map::derive_storage_slot_in_map; + use aztec::protocol::traits::Empty; + use aztec::protocol::traits::FromField; + use aztec::protocol::traits::ToField; + use aztec::protocol::traits::Serialize; + use aztec::state_vars::Map; + use aztec::state_vars::PublicMutable; + use aztec::state_vars::StateVariable; + use compressed_string::CompressedString; + use std::embedded_curve_ops::multi_scalar_mul; + use auth_contract::AuthRegistry; + use aztec::context::PublicContext; + use fee_juice::FeeJuice; + use instance_contract::ContractInstanceRegistry; + use std::ops::Add; + + global big_field_128_bits: Field = 0x1234567890abcdef1234567890abcdef; + + global big_field_136_bits: Field = 0x991234567890abcdef1234567890abcdef; + + global big_field_254_bits: Field = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef; + + struct Storage { + single: PublicMutable, + list: PublicMutable, + map: Map, Context>, + } + + impl Storage { + fn init(context: Context) -> Self { + Self { single: as StateVariable<1, Context>>::new(context, 1_Field), list: as StateVariable<2, Context>>::new(context, 2_Field), map: , Context> as StateVariable<1, Context>>::new(context, 4_Field)} + } + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_storage_single. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_storage_single(a: Field); + + #[contract_library_method] + fn _set_storage_single(storage: Storage, a: Field) { + storage.single.write(a); + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call read_storage_single. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn read_storage_single() -> Field; + + #[contract_library_method] + fn _read_storage_single(storage: Storage) -> Field { + storage.single.read() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call read_assert_storage_single. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn read_assert_storage_single(a: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_read_storage_single. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_read_storage_single(a: Field) -> pub Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_storage_list. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_storage_list(a: Field, b: Field); + + #[contract_library_method] + fn _set_storage_list(storage: Storage, a: Field, b: Field) { + storage.list.write(Note { a: a, b: b}); + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call read_storage_list. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn read_storage_list() -> [Field; 2]; + + #[contract_library_method] + fn _read_storage_list(storage: Storage) -> [Field; 2] { + let note: Note = storage.list.read(); + note.serialize() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_storage_map. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_storage_map(to: AztecAddress, amount: u32) -> Field; + + #[contract_library_method] + fn _set_storage_map(storage: Storage, to: AztecAddress, amount: u32) -> Field { + storage.map.at(to).write(amount); + derive_storage_slot_in_map(storage.map.get_storage_slot(), to) + } + + #[abi(storage)] + pub global STORAGE_LAYOUT_AvmTest: StorageLayout<7> = StorageLayout::<7> { + contract_name: "AvmTest", + fields: StorageLayoutFields { + single: aztec::state_vars::Storable { + slot: 0x01, + }, + list: aztec::state_vars::Storable { + slot: 0x02, + }, + map: aztec::state_vars::Storable { + slot: 0x04, + }, + }, + }; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call add_storage_map. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn add_storage_map(to: AztecAddress, amount: u32) -> Field; + + #[contract_library_method] + fn _add_storage_map(storage: Storage, to: AztecAddress, amount: u32) -> Field { + let new_balance: u32 = storage.map.at(to).read().add(amount); + storage.map.at(to).write(new_balance); + derive_storage_slot_in_map(storage.map.get_storage_slot(), to) + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call read_storage_map. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn read_storage_map(address: AztecAddress) -> u32; + + #[contract_library_method] + fn _read_storage_map(storage: Storage, address: AztecAddress) -> u32 { + storage.map.at(address).read() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call add_args_return. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn add_args_return(arg_a: Field, arg_b: Field) -> Field; + + #[contract_library_method] + unconstrained fn add(lhs: Field, rhs: Field) -> Field { + lhs + rhs + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_opcode_u8. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_opcode_u8() -> u8; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_opcode_u8_view. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_opcode_u8_view() -> u8; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_opcode_u32. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_opcode_u32() -> u32; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_opcode_u64. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_opcode_u64() -> u64; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_opcode_small_field. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_opcode_small_field() -> Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_opcode_big_field. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_opcode_big_field() -> Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_opcode_really_big_field. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_opcode_really_big_field() -> Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call add_u128. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn add_u128(a: u128, b: u128) -> u128; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call modulo2. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn modulo2(a: u64) -> u64; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call elliptic_curve_add. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn elliptic_curve_add(lhs: Point, rhs: Point) -> Point; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call elliptic_curve_add_and_double. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn elliptic_curve_add_and_double() -> Point; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call variable_base_msm. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn variable_base_msm(scalar_lo: Field, scalar_hi: Field, scalar2_lo: Field, scalar2_hi: Field) -> Point; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call pedersen_commit. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn pedersen_commit(x: Field, y: Field) -> Point; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call conditional_move. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn conditional_move(x: [Field; 1], y: [Field; 1], b: bool) -> [Field; 1]; + + #[contract_library_method] + fn bitwise_ops(x: u32, y: u32) -> u32 { + let mut result: u32 = x & y; + result = result | x; + result = result >> (x % 32_u32); + result = result << (y % 32_u32); + result ^ y + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call u128_addition_overflow. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn u128_addition_overflow() -> u128; + + #[contract_library_method] + fn integer_division(x: u8, y: u8) -> u8 { + x / y + } + + #[contract_library_method] + fn field_division(x: Field, y: Field) -> Field { + x / y + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call to_le_bytes. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn to_le_bytes(input: Field) -> [u8; 10]; + + #[contract_library_method] + fn _to_le_bytes(input: Field) -> [u8; 10] { + input.to_le_bytes() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call to_le_bits. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn to_le_bits(input: Field) -> [bool; 16]; + + #[contract_library_method] + fn _to_le_bits(input: Field) -> [bool; 16] { + input.to_le_bits() + } + + #[contract_library_method] + fn inner_helper_with_failed_assertion() { + let not_true: bool = false; + assert(not_true == true, "This assertion should fail!"); + } + + #[contract_library_method] + fn helper_with_failed_assertion() { + inner_helper_with_failed_assertion(); + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call assertion_failure. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn assertion_failure(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call external_call_to_assertion_failure. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn external_call_to_assertion_failure(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call divide_by_zero. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn divide_by_zero(denominator: u8) -> u8; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call external_call_to_divide_by_zero. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn external_call_to_divide_by_zero(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call external_call_to_divide_by_zero_recovers. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn external_call_to_divide_by_zero_recovers(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call debug_logging. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn debug_logging(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call assert_same. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn assert_same(arg_a: Field, arg_b: Field) -> pub Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call assert_calldata_copy. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn assert_calldata_copy(args: [Field; 3], with_selector: bool); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call assert_calldata_copy_large. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn assert_calldata_copy_large(args: [Field; 300], with_selector: bool); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call returndata_copy_oracle. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn returndata_copy_oracle(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call return_oracle. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn return_oracle() -> [Field; 3]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call revert_oracle. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn revert_oracle() -> [Field; 3]; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call test_get_contract_instance. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn test_get_contract_instance(address: AztecAddress); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call test_get_contract_instance_matches. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn test_get_contract_instance_matches(address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field); + + #[contract_library_method] + fn _test_get_contract_instance_matches(address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field) { + let deployer: Option = get_contract_instance_deployer_avm(address); + let class_id: Option = get_contract_instance_class_id_avm(address); + let initialization_hash: Option = get_contract_instance_initialization_hash_avm(address); + assert(deployer.is_some(), "Contract instance not found when getting DEPLOYER!"); + assert(class_id.is_some(), "Contract instance not found when getting CLASS_ID!"); + assert(initialization_hash.is_some(), "Contract instance not found when getting INIT_HASH!"); + assert(deployer.unwrap().eq(expected_deployer)); + assert(class_id.unwrap().eq(expected_class_id)); + assert(initialization_hash.unwrap().eq(expected_initialization_hash)); + aztec::oracle::logging::debug_log("Get Contract Instance Protocol Contract Instance"); + let fee_juice_class_id: Option = get_contract_instance_class_id_avm(FEE_JUICE_ADDRESS); + assert(fee_juice_class_id.is_some(), "Protocol Contract instance not found when getting CLASS_ID!"); + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_address. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_address() -> AztecAddress; + + #[contract_library_method] + fn _get_address(address: AztecAddress) -> AztecAddress { + address + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_sender. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_sender() -> AztecAddress; + + #[contract_library_method] + fn _get_sender(context: PublicContext) -> AztecAddress { + context.maybe_msg_sender().unwrap() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_transaction_fee. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_transaction_fee() -> Field; + + #[contract_library_method] + fn _get_transaction_fee(context: PublicContext) -> Field { + context.transaction_fee() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_chain_id. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_chain_id() -> Field; + + #[contract_library_method] + fn _get_chain_id(context: PublicContext) -> Field { + context.chain_id() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_version. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_version() -> Field; + + #[contract_library_method] + fn _get_version(context: PublicContext) -> Field { + context.version() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_block_number. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_block_number() -> u32; + + #[contract_library_method] + fn _get_block_number(context: PublicContext) -> u32 { + context.block_number() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_timestamp. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_timestamp() -> u64; + + #[contract_library_method] + fn _get_timestamp(context: PublicContext) -> u64 { + context.timestamp() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_fee_per_l2_gas. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_fee_per_l2_gas() -> u128; + + #[contract_library_method] + fn _get_fee_per_l2_gas(context: PublicContext) -> u128 { + context.min_fee_per_l2_gas() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_fee_per_da_gas. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_fee_per_da_gas() -> u128; + + #[contract_library_method] + fn _get_fee_per_da_gas(context: PublicContext) -> u128 { + context.min_fee_per_da_gas() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_l2_gas_left. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_l2_gas_left() -> u32; + + #[contract_library_method] + fn _get_l2_gas_left(context: PublicContext) -> u32 { + context.l2_gas_left() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_da_gas_left. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_da_gas_left() -> u32; + + #[contract_library_method] + fn _get_da_gas_left(context: PublicContext) -> u32 { + context.da_gas_left() + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_args_hash. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_args_hash(_a: u8, _fields: [Field; 3]) -> Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call emit_public_log. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn emit_public_log(); + + #[contract_library_method] + fn _emit_public_log(context: PublicContext) { + context.emit_public_log_unsafe(0_Field, [10_Field, 20_Field, 30_Field]); + context.emit_public_log_unsafe(0_Field, "Hello, world!"); + let s: CompressedString<2, 44> = CompressedString::<2, 44>::from_string("A long time ago, in a galaxy far far away..."); + context.emit_public_log_unsafe(0_Field, s); + context.emit_public_log_unsafe(0_Field, [1_Field, 2_Field, 3_Field, 4_Field, 5_Field, 6_Field, 7_Field, 8_Field, 9_Field, 10_Field, 11_Field, 12_Field, 13_Field, 14_Field, 15_Field, 16_Field, 17_Field, 18_Field, 19_Field, 20_Field, 21_Field, 22_Field, 23_Field, 24_Field, 25_Field, 26_Field, 27_Field, 28_Field, 29_Field, 30_Field, 31_Field, 32_Field, 33_Field, 34_Field, 35_Field, 36_Field, 37_Field, 38_Field, 39_Field, 40_Field, 41_Field, 42_Field]); + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call note_hash_exists. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn note_hash_exists(note_hash: Field, leaf_index: u64) -> bool; + + #[contract_library_method] + fn _note_hash_exists(context: PublicContext, note_hash: Field, leaf_index: u64) -> bool { + context.note_hash_exists(note_hash, leaf_index) + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call new_note_hash. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn new_note_hash(note_hash: Field); + + #[contract_library_method] + fn _new_note_hash(context: PublicContext, note_hash: Field) { + context.push_note_hash(note_hash); + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call new_nullifier. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn new_nullifier(nullifier: Field); + + #[contract_library_method] + fn _new_nullifier(context: PublicContext, nullifier: Field) { + context.push_nullifier(nullifier); + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call n_storage_writes. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn n_storage_writes(num: u32); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call n_new_note_hashes. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn n_new_note_hashes(num: u32); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call n_new_nullifiers. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn n_new_nullifiers(num: u32); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call n_new_l2_to_l1_msgs. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn n_new_l2_to_l1_msgs(num: u32); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call raw_l2_to_l1_msg. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn raw_l2_to_l1_msg(recipient: EthAddress, content: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call n_new_public_logs. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn n_new_public_logs(num: u32); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nullifier_exists. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nullifier_exists(nullifier: Field) -> bool; + + #[contract_library_method] + fn _nullifier_exists(context: PublicContext, address: AztecAddress, nullifier: Field) -> bool { + context.nullifier_exists_unsafe(nullifier, address) + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call assert_nullifier_exists. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn assert_nullifier_exists(nullifier: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call emit_nullifier_and_check. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn emit_nullifier_and_check(nullifier: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nullifier_collision. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nullifier_collision(nullifier: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call l1_to_l2_msg_exists. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> bool; + + #[contract_library_method] + fn _l1_to_l2_msg_exists(context: PublicContext, msg_hash: Field, msg_leaf_index: Field) -> bool { + context.l1_to_l2_msg_exists(msg_hash, msg_leaf_index) + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call send_l2_to_l1_msg. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn send_l2_to_l1_msg(recipient: EthAddress, content: Field); + + #[contract_library_method] + fn _send_l2_to_l1_msg(context: PublicContext, recipient: EthAddress, content: Field) { + context.message_portal(recipient, content) + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_call_to_nothing. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_call_to_nothing(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_call_to_nothing_recovers. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_call_to_nothing_recovers(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_call_to_add_with_gas. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_call_to_add_with_gas(arg_a: Field, arg_b: Field, l2_gas: u32, da_gas: u32) -> pub Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_call_to_add. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field; + + #[contract_library_method] + unconstrained fn _nested_call_to_add(context: PublicContext, address: AztecAddress, arg_a: Field, arg_b: Field) -> Field { + AvmTest::at(address).add_args_return(arg_a, arg_b).call(context) + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_call_to_add_n_times_different_addresses. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_call_to_add_n_times_different_addresses(addrs: [AztecAddress; 23]); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_static_call_to_add. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field; + + #[contract_library_method] + unconstrained fn _nested_static_call_to_add(context: PublicContext, address: AztecAddress, arg_a: Field, arg_b: Field) -> Field { + let selector: FunctionSelector = FunctionSelector { inner: 2858633377_u32}; + context.static_call_public_function(address, selector, [arg_a, arg_b], GasOpts::default())[0_u32] + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_static_call_to_set_storage. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_static_call_to_set_storage(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call create_same_nullifier_in_nested_call. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn create_same_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call create_different_nullifier_in_nested_call. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn create_different_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_call_to_assert_same. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_call_to_assert_same(arg_a: Field, arg_b: Field) -> pub Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call fn_w_large_calldata. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn fn_w_large_calldata(_arr: [Field; 300]) -> pub Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call nested_call_large_calldata. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn nested_call_large_calldata(arr: [Field; 300]) -> pub Field; + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call enqueue_public_from_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn enqueue_public_from_private(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call call_fee_juice. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn call_fee_juice(); + + #[contract_library_method] + unconstrained fn _call_fee_juice(context: PublicContext, address: AztecAddress) { + let _: u128 = FeeJuice::at(FEE_JUICE_ADDRESS).balance_of_public(address).view(context); + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call call_auth_registry. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn call_auth_registry(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call call_instance_registry. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn call_instance_registry(); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call bulk_testing. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn bulk_testing(args_field: [Field; 10], args_u8: [u8; 10], get_instance_for_address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field, skip_strictly_limited_side_effects: bool); + + /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + #[allow(dead_code)] + unconstrained fn _compute_note_hash_and_nullifier(packed_note: BoundedVec, owner: AztecAddress, storage_slot: Field, note_type_id: Field, contract_address: AztecAddress, randomness: Field, note_nonce: Field) -> Option { + _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash: Field| -> aztec::messages::discovery::NoteHashAndNullifier { + let siloed_note_hash: Field = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash); + let unique_note_hash: Field = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash); + let inner_nullifier: Option = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness); + aztec::messages::discovery::NoteHashAndNullifier { note_hash: note_hash, inner_nullifier: inner_nullifier} + }) + } + + /// This contract does not use private notes, so this function should never be called as it will unconditionally fail. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_hash(_packed_note: BoundedVec, _owner: AztecAddress, _storage_slot: Field, _note_type_id: Field, _contract_address: AztecAddress, _randomness: Field) -> Option { + panic(f"This contract does not use private notes") + } + + /// This contract does not use private notes, so this function should never be called as it will unconditionally fail. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_nullifier(_unique_note_hash: Field, _packed_note: BoundedVec, _owner: AztecAddress, _storage_slot: Field, _note_type_id: Field, _contract_address: AztecAddress, _randomness: Field) -> Option { + panic(f"This contract does not use private notes") + } + + /// Receives offchain messages into this contract's offchain inbox for subsequent processing. + /// + /// Each message is routed to the inbox scoped to its `recipient` field. + /// + /// For more details, see `aztec::messages::processing::offchain::receive`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + unconstrained fn offchain_receive(messages: BoundedVec) { + let address: AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::processing::offchain::receive(address, messages); + } + + pub struct AvmTest { + pub target_contract: AztecAddress, + } + + impl AvmTest { + pub fn storage_layout() -> StorageLayoutFields { + STORAGE_LAYOUT_AvmTest.fields + } + + pub fn at(addr: AztecAddress) -> Self { + Self { target_contract: addr} + } + + pub fn interface() -> Self { + Self { target_contract: AztecAddress::zero()} + } + + pub fn assert_calldata_copy(self, args: [Field; 3], with_selector: bool) -> aztec::context::calls::PublicCall<20, 4, ()> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3 * 1] = args.serialize(); + let serialized_member_len: u32 = <[Field; 3] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = with_selector.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3853740100_Field); + aztec::context::calls::PublicCall::<20, 4, ()>::new(self.target_contract, selector, "assert_calldata_copy", serialized_params) + } + + pub fn get_chain_id(self) -> aztec::context::calls::PublicCall<12, 0, Field> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1458572288_Field); + aztec::context::calls::PublicCall::<12, 0, Field>::new(self.target_contract, selector, "get_chain_id", serialized_params) + } + + pub fn get_args_hash(self, _a: u8, _fields: [Field; 3]) -> aztec::context::calls::PublicCall<13, 4, Field> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = _a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 3 * 1] = _fields.serialize(); + let serialized_member_len: u32 = <[Field; 3] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1608415988_Field); + aztec::context::calls::PublicCall::<13, 4, Field>::new(self.target_contract, selector, "get_args_hash", serialized_params) + } + + pub fn external_call_to_divide_by_zero(self) -> aztec::context::calls::PublicCall<31, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3880450065_Field); + aztec::context::calls::PublicCall::<31, 0, ()>::new(self.target_contract, selector, "external_call_to_divide_by_zero", serialized_params) + } + + pub fn n_new_nullifiers(self, num: u32) -> aztec::context::calls::PublicCall<16, 1, ()> { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(592684400_Field); + aztec::context::calls::PublicCall::<16, 1, ()>::new(self.target_contract, selector, "n_new_nullifiers", serialized_params) + } + + pub fn new_note_hash(self, note_hash: Field) -> aztec::context::calls::PublicCall<13, 1, ()> { + let serialized_params: [Field; 1] = note_hash.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1524332459_Field); + aztec::context::calls::PublicCall::<13, 1, ()>::new(self.target_contract, selector, "new_note_hash", serialized_params) + } + + pub fn nullifier_collision(self, nullifier: Field) -> aztec::context::calls::PublicCall<19, 1, ()> { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2417179850_Field); + aztec::context::calls::PublicCall::<19, 1, ()>::new(self.target_contract, selector, "nullifier_collision", serialized_params) + } + + pub fn get_l2_gas_left(self) -> aztec::context::calls::PublicCall<15, 0, u32> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1635524210_Field); + aztec::context::calls::PublicCall::<15, 0, u32>::new(self.target_contract, selector, "get_l2_gas_left", serialized_params) + } + + pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> aztec::context::calls::PublicCall<19, 2, bool> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = msg_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = msg_leaf_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3972971575_Field); + aztec::context::calls::PublicCall::<19, 2, bool>::new(self.target_contract, selector, "l1_to_l2_msg_exists", serialized_params) + } + + pub fn add_storage_map(self, to: AztecAddress, amount: u32) -> aztec::context::calls::PublicCall<15, 2, Field> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = to.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = amount.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2606877757_Field); + aztec::context::calls::PublicCall::<15, 2, Field>::new(self.target_contract, selector, "add_storage_map", serialized_params) + } + + pub fn bulk_testing(self, args_field: [Field; 10], args_u8: [u8; 10], get_instance_for_address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field, skip_strictly_limited_side_effects: bool) -> aztec::context::calls::PublicCall<12, 25, ()> { + let mut serialized_params: [Field; 25] = [0_Field; 25]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 10 * 1] = args_field.serialize(); + let serialized_member_len: u32 = <[Field; 10] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 10 * 1] = args_u8.serialize(); + let serialized_member_len: u32 = <[u8; 10] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = get_instance_for_address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_deployer.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_class_id.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_initialization_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = skip_strictly_limited_side_effects.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_6: u32 = i + offset; + serialized_params[i_6] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(43639379_Field); + aztec::context::calls::PublicCall::<12, 25, ()>::new(self.target_contract, selector, "bulk_testing", serialized_params) + } + + pub fn variable_base_msm(self, scalar_lo: Field, scalar_hi: Field, scalar2_lo: Field, scalar2_hi: Field) -> aztec::context::calls::PublicCall<17, 4, Point> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = scalar_lo.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar_hi.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar2_lo.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar2_hi.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2931784034_Field); + aztec::context::calls::PublicCall::<17, 4, Point>::new(self.target_contract, selector, "variable_base_msm", serialized_params) + } + + pub fn add_args_return(self, arg_a: Field, arg_b: Field) -> aztec::context::calls::PublicCall<15, 2, Field> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2858633377_Field); + aztec::context::calls::PublicCall::<15, 2, Field>::new(self.target_contract, selector, "add_args_return", serialized_params) + } + + pub fn test_get_contract_instance_matches(self, address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field) -> aztec::context::calls::PublicCall<34, 4, ()> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_deployer.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_class_id.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_initialization_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2723912183_Field); + aztec::context::calls::PublicCall::<34, 4, ()>::new(self.target_contract, selector, "test_get_contract_instance_matches", serialized_params) + } + + pub fn get_sender(self) -> aztec::context::calls::PublicCall<10, 0, AztecAddress> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(301170519_Field); + aztec::context::calls::PublicCall::<10, 0, AztecAddress>::new(self.target_contract, selector, "get_sender", serialized_params) + } + + pub fn n_new_l2_to_l1_msgs(self, num: u32) -> aztec::context::calls::PublicCall<19, 1, ()> { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3921925917_Field); + aztec::context::calls::PublicCall::<19, 1, ()>::new(self.target_contract, selector, "n_new_l2_to_l1_msgs", serialized_params) + } + + pub fn set_storage_list(self, a: Field, b: Field) -> aztec::context::calls::PublicCall<16, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1745164739_Field); + aztec::context::calls::PublicCall::<16, 2, ()>::new(self.target_contract, selector, "set_storage_list", serialized_params) + } + + pub fn pedersen_commit(self, x: Field, y: Field) -> aztec::context::calls::PublicCall<15, 2, Point> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = x.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = y.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2484465428_Field); + aztec::context::calls::PublicCall::<15, 2, Point>::new(self.target_contract, selector, "pedersen_commit", serialized_params) + } + + pub fn nullifier_exists(self, nullifier: Field) -> aztec::context::calls::PublicCall<16, 1, bool> { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2051407563_Field); + aztec::context::calls::PublicCall::<16, 1, bool>::new(self.target_contract, selector, "nullifier_exists", serialized_params) + } + + pub fn read_storage_list(self) -> aztec::context::calls::PublicCall<17, 0, [Field; 2]> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1727615163_Field); + aztec::context::calls::PublicCall::<17, 0, [Field; 2]>::new(self.target_contract, selector, "read_storage_list", serialized_params) + } + + pub fn emit_nullifier_and_check(self, nullifier: Field) -> aztec::context::calls::PublicCall<24, 1, ()> { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2367487025_Field); + aztec::context::calls::PublicCall::<24, 1, ()>::new(self.target_contract, selector, "emit_nullifier_and_check", serialized_params) + } + + pub fn assert_same(self, arg_a: Field, arg_b: Field) -> aztec::context::calls::PublicCall<11, 2, Field> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(290442984_Field); + aztec::context::calls::PublicCall::<11, 2, Field>::new(self.target_contract, selector, "assert_same", serialized_params) + } + + pub fn get_fee_per_da_gas(self) -> aztec::context::calls::PublicCall<18, 0, u128> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(514475538_Field); + aztec::context::calls::PublicCall::<18, 0, u128>::new(self.target_contract, selector, "get_fee_per_da_gas", serialized_params) + } + + pub fn modulo2(self, a: u64) -> aztec::context::calls::PublicCall<7, 1, u64> { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(222531562_Field); + aztec::context::calls::PublicCall::<7, 1, u64>::new(self.target_contract, selector, "modulo2", serialized_params) + } + + pub fn nested_static_call_to_add(self, arg_a: Field, arg_b: Field) -> aztec::context::calls::PublicCall<25, 2, Field> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1362946309_Field); + aztec::context::calls::PublicCall::<25, 2, Field>::new(self.target_contract, selector, "nested_static_call_to_add", serialized_params) + } + + pub fn to_le_bits(self, input: Field) -> aztec::context::calls::PublicCall<10, 1, [bool; 16]> { + let serialized_params: [Field; 1] = input.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2961959597_Field); + aztec::context::calls::PublicCall::<10, 1, [bool; 16]>::new(self.target_contract, selector, "to_le_bits", serialized_params) + } + + pub fn call_auth_registry(self) -> aztec::context::calls::PublicCall<18, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1225767423_Field); + aztec::context::calls::PublicCall::<18, 0, ()>::new(self.target_contract, selector, "call_auth_registry", serialized_params) + } + + pub fn set_opcode_u64(self) -> aztec::context::calls::PublicCall<14, 0, u64> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1435480431_Field); + aztec::context::calls::PublicCall::<14, 0, u64>::new(self.target_contract, selector, "set_opcode_u64", serialized_params) + } + + pub fn return_oracle(self) -> aztec::context::calls::PublicCall<13, 0, [Field; 3]> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3794636397_Field); + aztec::context::calls::PublicCall::<13, 0, [Field; 3]>::new(self.target_contract, selector, "return_oracle", serialized_params) + } + + pub fn test_get_contract_instance(self, address: AztecAddress) -> aztec::context::calls::PublicCall<26, 1, ()> { + let serialized_params: [Field; 1] = address.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2488367864_Field); + aztec::context::calls::PublicCall::<26, 1, ()>::new(self.target_contract, selector, "test_get_contract_instance", serialized_params) + } + + pub fn get_timestamp(self) -> aztec::context::calls::PublicCall<13, 0, u64> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(448989811_Field); + aztec::context::calls::PublicCall::<13, 0, u64>::new(self.target_contract, selector, "get_timestamp", serialized_params) + } + + pub fn to_le_bytes(self, input: Field) -> aztec::context::calls::PublicCall<11, 1, [u8; 10]> { + let serialized_params: [Field; 1] = input.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1975931334_Field); + aztec::context::calls::PublicCall::<11, 1, [u8; 10]>::new(self.target_contract, selector, "to_le_bytes", serialized_params) + } + + pub fn external_call_to_assertion_failure(self) -> aztec::context::calls::PublicCall<34, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(294808228_Field); + aztec::context::calls::PublicCall::<34, 0, ()>::new(self.target_contract, selector, "external_call_to_assertion_failure", serialized_params) + } + + pub fn divide_by_zero(self, denominator: u8) -> aztec::context::calls::PublicCall<14, 1, u8> { + let serialized_params: [Field; 1] = denominator.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(815932481_Field); + aztec::context::calls::PublicCall::<14, 1, u8>::new(self.target_contract, selector, "divide_by_zero", serialized_params) + } + + pub fn emit_public_log(self) -> aztec::context::calls::PublicCall<15, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2033426724_Field); + aztec::context::calls::PublicCall::<15, 0, ()>::new(self.target_contract, selector, "emit_public_log", serialized_params) + } + + pub fn new_nullifier(self, nullifier: Field) -> aztec::context::calls::PublicCall<13, 1, ()> { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3648851082_Field); + aztec::context::calls::PublicCall::<13, 1, ()>::new(self.target_contract, selector, "new_nullifier", serialized_params) + } + + pub fn raw_l2_to_l1_msg(self, recipient: EthAddress, content: Field) -> aztec::context::calls::PublicCall<16, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = recipient.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = content.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3409962923_Field); + aztec::context::calls::PublicCall::<16, 2, ()>::new(self.target_contract, selector, "raw_l2_to_l1_msg", serialized_params) + } + + pub fn nested_call_to_nothing_recovers(self) -> aztec::context::calls::PublicCall<31, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1843532057_Field); + aztec::context::calls::PublicCall::<31, 0, ()>::new(self.target_contract, selector, "nested_call_to_nothing_recovers", serialized_params) + } + + pub fn assert_calldata_copy_large(self, args: [Field; 300], with_selector: bool) -> aztec::context::calls::PublicCall<26, 301, ()> { + let mut serialized_params: [Field; 301] = [0_Field; 301]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 300 * 1] = args.serialize(); + let serialized_member_len: u32 = <[Field; 300] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = with_selector.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2293565755_Field); + aztec::context::calls::PublicCall::<26, 301, ()>::new(self.target_contract, selector, "assert_calldata_copy_large", serialized_params) + } + + pub fn set_opcode_really_big_field(self) -> aztec::context::calls::PublicCall<27, 0, Field> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4095821182_Field); + aztec::context::calls::PublicCall::<27, 0, Field>::new(self.target_contract, selector, "set_opcode_really_big_field", serialized_params) + } + + pub fn enqueue_public_from_private(self) -> aztec::context::calls::PrivateCall<27, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2771384488_Field); + aztec::context::calls::PrivateCall::<27, 0, ()>::new(self.target_contract, selector, "enqueue_public_from_private", serialized_params) + } + + pub fn elliptic_curve_add(self, lhs: Point, rhs: Point) -> aztec::context::calls::PublicCall<18, 6, Point> { + let mut serialized_params: [Field; 6] = [0_Field; 6]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = lhs.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 3] = rhs.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1700026912_Field); + aztec::context::calls::PublicCall::<18, 6, Point>::new(self.target_contract, selector, "elliptic_curve_add", serialized_params) + } + + pub fn set_read_storage_single(self, a: Field) -> aztec::context::calls::PublicCall<23, 1, Field> { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1932358992_Field); + aztec::context::calls::PublicCall::<23, 1, Field>::new(self.target_contract, selector, "set_read_storage_single", serialized_params) + } + + pub fn returndata_copy_oracle(self) -> aztec::context::calls::PublicCall<22, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4172530660_Field); + aztec::context::calls::PublicCall::<22, 0, ()>::new(self.target_contract, selector, "returndata_copy_oracle", serialized_params) + } + + pub fn conditional_move(self, x: [Field; 1], y: [Field; 1], b: bool) -> aztec::context::calls::PublicCall<16, 3, [Field; 1]> { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1 * 1] = x.serialize(); + let serialized_member_len: u32 = <[Field; 1] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1 * 1] = y.serialize(); + let serialized_member_len: u32 = <[Field; 1] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2633971407_Field); + aztec::context::calls::PublicCall::<16, 3, [Field; 1]>::new(self.target_contract, selector, "conditional_move", serialized_params) + } + + pub fn set_opcode_small_field(self) -> aztec::context::calls::PublicCall<22, 0, Field> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3464175345_Field); + aztec::context::calls::PublicCall::<22, 0, Field>::new(self.target_contract, selector, "set_opcode_small_field", serialized_params) + } + + pub fn n_new_public_logs(self, num: u32) -> aztec::context::calls::PublicCall<17, 1, ()> { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2907114368_Field); + aztec::context::calls::PublicCall::<17, 1, ()>::new(self.target_contract, selector, "n_new_public_logs", serialized_params) + } + + pub fn nested_call_to_nothing(self) -> aztec::context::calls::PublicCall<22, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1183868090_Field); + aztec::context::calls::PublicCall::<22, 0, ()>::new(self.target_contract, selector, "nested_call_to_nothing", serialized_params) + } + + pub fn nested_call_to_add_with_gas(self, arg_a: Field, arg_b: Field, l2_gas: u32, da_gas: u32) -> aztec::context::calls::PublicCall<27, 4, Field> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = l2_gas.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = da_gas.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3561659563_Field); + aztec::context::calls::PublicCall::<27, 4, Field>::new(self.target_contract, selector, "nested_call_to_add_with_gas", serialized_params) + } + + pub fn create_different_nullifier_in_nested_call(self, nestedAddress: AztecAddress, nullifier: Field) -> aztec::context::calls::PublicCall<41, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = nestedAddress.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = nullifier.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1630216043_Field); + aztec::context::calls::PublicCall::<41, 2, ()>::new(self.target_contract, selector, "create_different_nullifier_in_nested_call", serialized_params) + } + + pub fn call_fee_juice(self) -> aztec::context::calls::PublicCall<14, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2734888597_Field); + aztec::context::calls::PublicCall::<14, 0, ()>::new(self.target_contract, selector, "call_fee_juice", serialized_params) + } + + pub fn get_transaction_fee(self) -> aztec::context::calls::PublicCall<19, 0, Field> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2524054657_Field); + aztec::context::calls::PublicCall::<19, 0, Field>::new(self.target_contract, selector, "get_transaction_fee", serialized_params) + } + + pub fn get_da_gas_left(self) -> aztec::context::calls::PublicCall<15, 0, u32> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2319460898_Field); + aztec::context::calls::PublicCall::<15, 0, u32>::new(self.target_contract, selector, "get_da_gas_left", serialized_params) + } + + pub fn read_storage_single(self) -> aztec::context::calls::PublicCall<19, 0, Field> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3140392744_Field); + aztec::context::calls::PublicCall::<19, 0, Field>::new(self.target_contract, selector, "read_storage_single", serialized_params) + } + + pub fn set_opcode_u8_view(self) -> aztec::context::calls::PublicStaticCall<18, 0, u8> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(643109956_Field); + aztec::context::calls::PublicStaticCall::<18, 0, u8>::new(self.target_contract, selector, "set_opcode_u8_view", serialized_params) + } + + pub fn assert_nullifier_exists(self, nullifier: Field) -> aztec::context::calls::PublicCall<23, 1, ()> { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2810255355_Field); + aztec::context::calls::PublicCall::<23, 1, ()>::new(self.target_contract, selector, "assert_nullifier_exists", serialized_params) + } + + pub fn assertion_failure(self) -> aztec::context::calls::PublicCall<17, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3276887878_Field); + aztec::context::calls::PublicCall::<17, 0, ()>::new(self.target_contract, selector, "assertion_failure", serialized_params) + } + + pub fn debug_logging(self) -> aztec::context::calls::PublicCall<13, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3667472301_Field); + aztec::context::calls::PublicCall::<13, 0, ()>::new(self.target_contract, selector, "debug_logging", serialized_params) + } + + pub fn nested_call_large_calldata(self, arr: [Field; 300]) -> aztec::context::calls::PublicCall<26, 300, Field> { + let serialized_params: [Field; 300] = arr.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(14812432_Field); + aztec::context::calls::PublicCall::<26, 300, Field>::new(self.target_contract, selector, "nested_call_large_calldata", serialized_params) + } + + pub fn external_call_to_divide_by_zero_recovers(self) -> aztec::context::calls::PublicCall<40, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2245930342_Field); + aztec::context::calls::PublicCall::<40, 0, ()>::new(self.target_contract, selector, "external_call_to_divide_by_zero_recovers", serialized_params) + } + + pub fn set_opcode_u32(self) -> aztec::context::calls::PublicCall<14, 0, u32> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4045556597_Field); + aztec::context::calls::PublicCall::<14, 0, u32>::new(self.target_contract, selector, "set_opcode_u32", serialized_params) + } + + pub fn call_instance_registry(self) -> aztec::context::calls::PublicCall<22, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2336742722_Field); + aztec::context::calls::PublicCall::<22, 0, ()>::new(self.target_contract, selector, "call_instance_registry", serialized_params) + } + + pub fn set_storage_single(self, a: Field) -> aztec::context::calls::PublicCall<18, 1, ()> { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2230419055_Field); + aztec::context::calls::PublicCall::<18, 1, ()>::new(self.target_contract, selector, "set_storage_single", serialized_params) + } + + pub fn nested_call_to_add(self, arg_a: Field, arg_b: Field) -> aztec::context::calls::PublicCall<18, 2, Field> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(94115833_Field); + aztec::context::calls::PublicCall::<18, 2, Field>::new(self.target_contract, selector, "nested_call_to_add", serialized_params) + } + + pub fn revert_oracle(self) -> aztec::context::calls::PublicCall<13, 0, [Field; 3]> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4147614534_Field); + aztec::context::calls::PublicCall::<13, 0, [Field; 3]>::new(self.target_contract, selector, "revert_oracle", serialized_params) + } + + pub fn send_l2_to_l1_msg(self, recipient: EthAddress, content: Field) -> aztec::context::calls::PublicCall<17, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = recipient.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = content.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2709402942_Field); + aztec::context::calls::PublicCall::<17, 2, ()>::new(self.target_contract, selector, "send_l2_to_l1_msg", serialized_params) + } + + pub fn note_hash_exists(self, note_hash: Field, leaf_index: u64) -> aztec::context::calls::PublicCall<16, 2, bool> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = note_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = leaf_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(671085844_Field); + aztec::context::calls::PublicCall::<16, 2, bool>::new(self.target_contract, selector, "note_hash_exists", serialized_params) + } + + pub fn read_storage_map(self, address: AztecAddress) -> aztec::context::calls::PublicCall<16, 1, u32> { + let serialized_params: [Field; 1] = address.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(711888726_Field); + aztec::context::calls::PublicCall::<16, 1, u32>::new(self.target_contract, selector, "read_storage_map", serialized_params) + } + + pub fn read_assert_storage_single(self, a: Field) -> aztec::context::calls::PublicCall<26, 1, ()> { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1067389427_Field); + aztec::context::calls::PublicCall::<26, 1, ()>::new(self.target_contract, selector, "read_assert_storage_single", serialized_params) + } + + pub fn elliptic_curve_add_and_double(self) -> aztec::context::calls::PublicCall<29, 0, Point> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1891218722_Field); + aztec::context::calls::PublicCall::<29, 0, Point>::new(self.target_contract, selector, "elliptic_curve_add_and_double", serialized_params) + } + + pub fn get_block_number(self) -> aztec::context::calls::PublicCall<16, 0, u32> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3223336515_Field); + aztec::context::calls::PublicCall::<16, 0, u32>::new(self.target_contract, selector, "get_block_number", serialized_params) + } + + pub fn nested_call_to_assert_same(self, arg_a: Field, arg_b: Field) -> aztec::context::calls::PublicCall<26, 2, Field> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1563037608_Field); + aztec::context::calls::PublicCall::<26, 2, Field>::new(self.target_contract, selector, "nested_call_to_assert_same", serialized_params) + } + + pub fn fn_w_large_calldata(self, _arr: [Field; 300]) -> aztec::context::calls::PublicCall<19, 300, Field> { + let serialized_params: [Field; 300] = _arr.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3786762676_Field); + aztec::context::calls::PublicCall::<19, 300, Field>::new(self.target_contract, selector, "fn_w_large_calldata", serialized_params) + } + + pub fn get_address(self) -> aztec::context::calls::PublicCall<11, 0, AztecAddress> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1968200506_Field); + aztec::context::calls::PublicCall::<11, 0, AztecAddress>::new(self.target_contract, selector, "get_address", serialized_params) + } + + pub fn set_storage_map(self, to: AztecAddress, amount: u32) -> aztec::context::calls::PublicCall<15, 2, Field> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = to.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = amount.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1756672898_Field); + aztec::context::calls::PublicCall::<15, 2, Field>::new(self.target_contract, selector, "set_storage_map", serialized_params) + } + + pub fn get_version(self) -> aztec::context::calls::PublicCall<11, 0, Field> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(421038220_Field); + aztec::context::calls::PublicCall::<11, 0, Field>::new(self.target_contract, selector, "get_version", serialized_params) + } + + pub fn nested_static_call_to_set_storage(self) -> aztec::context::calls::PublicCall<33, 0, ()> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3861896907_Field); + aztec::context::calls::PublicCall::<33, 0, ()>::new(self.target_contract, selector, "nested_static_call_to_set_storage", serialized_params) + } + + pub fn create_same_nullifier_in_nested_call(self, nestedAddress: AztecAddress, nullifier: Field) -> aztec::context::calls::PublicCall<36, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = nestedAddress.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = nullifier.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1050471208_Field); + aztec::context::calls::PublicCall::<36, 2, ()>::new(self.target_contract, selector, "create_same_nullifier_in_nested_call", serialized_params) + } + + pub fn set_opcode_big_field(self) -> aztec::context::calls::PublicCall<20, 0, Field> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(497423715_Field); + aztec::context::calls::PublicCall::<20, 0, Field>::new(self.target_contract, selector, "set_opcode_big_field", serialized_params) + } + + pub fn u128_addition_overflow(self) -> aztec::context::calls::PublicCall<22, 0, u128> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2520497807_Field); + aztec::context::calls::PublicCall::<22, 0, u128>::new(self.target_contract, selector, "u128_addition_overflow", serialized_params) + } + + pub fn add_u128(self, a: u128, b: u128) -> aztec::context::calls::PublicCall<8, 2, u128> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1408352185_Field); + aztec::context::calls::PublicCall::<8, 2, u128>::new(self.target_contract, selector, "add_u128", serialized_params) + } + + pub fn get_fee_per_l2_gas(self) -> aztec::context::calls::PublicCall<18, 0, u128> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(323255525_Field); + aztec::context::calls::PublicCall::<18, 0, u128>::new(self.target_contract, selector, "get_fee_per_l2_gas", serialized_params) + } + + pub fn n_storage_writes(self, num: u32) -> aztec::context::calls::PublicCall<16, 1, ()> { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2323221248_Field); + aztec::context::calls::PublicCall::<16, 1, ()>::new(self.target_contract, selector, "n_storage_writes", serialized_params) + } + + pub fn set_opcode_u8(self) -> aztec::context::calls::PublicCall<13, 0, u8> { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3068438800_Field); + aztec::context::calls::PublicCall::<13, 0, u8>::new(self.target_contract, selector, "set_opcode_u8", serialized_params) + } + + pub fn n_new_note_hashes(self, num: u32) -> aztec::context::calls::PublicCall<17, 1, ()> { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1938641640_Field); + aztec::context::calls::PublicCall::<17, 1, ()>::new(self.target_contract, selector, "n_new_note_hashes", serialized_params) + } + + pub fn nested_call_to_add_n_times_different_addresses(self, addrs: [AztecAddress; 23]) -> aztec::context::calls::PublicCall<46, 23, ()> { + let serialized_params: [Field; 23] = addrs.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2936248969_Field); + aztec::context::calls::PublicCall::<46, 23, ()>::new(self.target_contract, selector, "nested_call_to_add_n_times_different_addresses", serialized_params) + } + + pub fn offchain_receive(self, messages: BoundedVec) -> aztec::context::calls::UtilityCall<16, 321, ()> { + let serialized_params: [Field; 321] = messages.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1396850735_Field); + aztec::context::calls::UtilityCall::<16, 321, ()>::new(self.target_contract, selector, "offchain_receive", serialized_params) + } + } + + #[contract_library_method] + pub fn storage_layout() -> StorageLayoutFields { + STORAGE_LAYOUT_AvmTest.fields + } + + #[contract_library_method] + pub fn at(addr: AztecAddress) -> AvmTest { + AvmTest { target_contract: addr} + } + + #[contract_library_method] + pub fn interface() -> AvmTest { + AvmTest { target_contract: AztecAddress::zero()} + } + + pub struct sync_state_parameters { + pub scope: AztecAddress, + } + + #[abi(functions)] + pub struct sync_state_abi { + parameters: sync_state_parameters, + } + + unconstrained fn sync_state(scope: AztecAddress) { + let address: AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::discovery::do_sync_state(address, _compute_note_hash, _compute_note_nullifier, Option::>::none(), Option:: aztec::ephemeral::EphemeralArray>::some(aztec::messages::processing::offchain::sync_inbox), scope); + } + + pub struct offchain_receive_parameters { + pub messages: BoundedVec, + } + + #[abi(functions)] + pub struct offchain_receive_abi { + parameters: offchain_receive_parameters, + } + + pub struct CallSelf { + pub address: AztecAddress, + pub context: Context, + } + + impl CallSelf { + pub fn assert_calldata_copy(self, args: [Field; 3], with_selector: bool) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3 * 1] = args.serialize(); + let serialized_member_len: u32 = <[Field; 3] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = with_selector.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3853740100_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<20, 4, ()>::new(self.address, selector, "assert_calldata_copy", serialized_params).call(self.context) + } + } + + pub fn get_chain_id(self) -> Field { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1458572288_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<12, 0, Field>::new(self.address, selector, "get_chain_id", serialized_params).call(self.context) + } + } + + pub fn get_args_hash(self, _a: u8, _fields: [Field; 3]) -> Field { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = _a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 3 * 1] = _fields.serialize(); + let serialized_member_len: u32 = <[Field; 3] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1608415988_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 4, Field>::new(self.address, selector, "get_args_hash", serialized_params).call(self.context) + } + } + + pub fn external_call_to_divide_by_zero(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3880450065_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<31, 0, ()>::new(self.address, selector, "external_call_to_divide_by_zero", serialized_params).call(self.context) + } + } + + pub fn n_new_nullifiers(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(592684400_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 1, ()>::new(self.address, selector, "n_new_nullifiers", serialized_params).call(self.context) + } + } + + pub fn new_note_hash(self, note_hash: Field) { + let serialized_params: [Field; 1] = note_hash.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1524332459_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 1, ()>::new(self.address, selector, "new_note_hash", serialized_params).call(self.context) + } + } + + pub fn nullifier_collision(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2417179850_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<19, 1, ()>::new(self.address, selector, "nullifier_collision", serialized_params).call(self.context) + } + } + + pub fn get_l2_gas_left(self) -> u32 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1635524210_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 0, u32>::new(self.address, selector, "get_l2_gas_left", serialized_params).call(self.context) + } + } + + pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> bool { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = msg_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = msg_leaf_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3972971575_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<19, 2, bool>::new(self.address, selector, "l1_to_l2_msg_exists", serialized_params).call(self.context) + } + } + + pub fn add_storage_map(self, to: AztecAddress, amount: u32) -> Field { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = to.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = amount.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2606877757_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 2, Field>::new(self.address, selector, "add_storage_map", serialized_params).call(self.context) + } + } + + pub fn bulk_testing(self, args_field: [Field; 10], args_u8: [u8; 10], get_instance_for_address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field, skip_strictly_limited_side_effects: bool) { + let mut serialized_params: [Field; 25] = [0_Field; 25]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 10 * 1] = args_field.serialize(); + let serialized_member_len: u32 = <[Field; 10] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 10 * 1] = args_u8.serialize(); + let serialized_member_len: u32 = <[u8; 10] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = get_instance_for_address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_deployer.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_class_id.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_initialization_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = skip_strictly_limited_side_effects.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_6: u32 = i + offset; + serialized_params[i_6] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(43639379_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<12, 25, ()>::new(self.address, selector, "bulk_testing", serialized_params).call(self.context) + } + } + + pub fn add_args_return(self, arg_a: Field, arg_b: Field) -> Field { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2858633377_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 2, Field>::new(self.address, selector, "add_args_return", serialized_params).call(self.context) + } + } + + pub fn variable_base_msm(self, scalar_lo: Field, scalar_hi: Field, scalar2_lo: Field, scalar2_hi: Field) -> Point { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = scalar_lo.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar_hi.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar2_lo.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar2_hi.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2931784034_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<17, 4, Point>::new(self.address, selector, "variable_base_msm", serialized_params).call(self.context) + } + } + + pub fn test_get_contract_instance_matches(self, address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_deployer.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_class_id.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_initialization_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2723912183_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<34, 4, ()>::new(self.address, selector, "test_get_contract_instance_matches", serialized_params).call(self.context) + } + } + + pub fn get_sender(self) -> AztecAddress { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(301170519_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<10, 0, AztecAddress>::new(self.address, selector, "get_sender", serialized_params).call(self.context) + } + } + + pub fn n_new_l2_to_l1_msgs(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3921925917_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<19, 1, ()>::new(self.address, selector, "n_new_l2_to_l1_msgs", serialized_params).call(self.context) + } + } + + pub fn set_storage_list(self, a: Field, b: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1745164739_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 2, ()>::new(self.address, selector, "set_storage_list", serialized_params).call(self.context) + } + } + + pub fn pedersen_commit(self, x: Field, y: Field) -> Point { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = x.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = y.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2484465428_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 2, Point>::new(self.address, selector, "pedersen_commit", serialized_params).call(self.context) + } + } + + pub fn nullifier_exists(self, nullifier: Field) -> bool { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2051407563_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 1, bool>::new(self.address, selector, "nullifier_exists", serialized_params).call(self.context) + } + } + + pub fn read_storage_list(self) -> [Field; 2] { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1727615163_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<17, 0, [Field; 2]>::new(self.address, selector, "read_storage_list", serialized_params).call(self.context) + } + } + + pub fn emit_nullifier_and_check(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2367487025_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<24, 1, ()>::new(self.address, selector, "emit_nullifier_and_check", serialized_params).call(self.context) + } + } + + pub fn assert_same(self, arg_a: Field, arg_b: Field) -> Field { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(290442984_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<11, 2, Field>::new(self.address, selector, "assert_same", serialized_params).call(self.context) + } + } + + pub fn get_fee_per_da_gas(self) -> u128 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(514475538_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<18, 0, u128>::new(self.address, selector, "get_fee_per_da_gas", serialized_params).call(self.context) + } + } + + pub fn modulo2(self, a: u64) -> u64 { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(222531562_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<7, 1, u64>::new(self.address, selector, "modulo2", serialized_params).call(self.context) + } + } + + pub fn nested_static_call_to_add(self, arg_a: Field, arg_b: Field) -> Field { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1362946309_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<25, 2, Field>::new(self.address, selector, "nested_static_call_to_add", serialized_params).call(self.context) + } + } + + pub fn to_le_bits(self, input: Field) -> [bool; 16] { + let serialized_params: [Field; 1] = input.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2961959597_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<10, 1, [bool; 16]>::new(self.address, selector, "to_le_bits", serialized_params).call(self.context) + } + } + + pub fn call_auth_registry(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1225767423_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<18, 0, ()>::new(self.address, selector, "call_auth_registry", serialized_params).call(self.context) + } + } + + pub fn set_opcode_u64(self) -> u64 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1435480431_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 0, u64>::new(self.address, selector, "set_opcode_u64", serialized_params).call(self.context) + } + } + + pub fn return_oracle(self) -> [Field; 3] { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3794636397_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 0, [Field; 3]>::new(self.address, selector, "return_oracle", serialized_params).call(self.context) + } + } + + pub fn test_get_contract_instance(self, address: AztecAddress) { + let serialized_params: [Field; 1] = address.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2488367864_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<26, 1, ()>::new(self.address, selector, "test_get_contract_instance", serialized_params).call(self.context) + } + } + + pub fn get_timestamp(self) -> u64 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(448989811_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 0, u64>::new(self.address, selector, "get_timestamp", serialized_params).call(self.context) + } + } + + pub fn to_le_bytes(self, input: Field) -> [u8; 10] { + let serialized_params: [Field; 1] = input.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1975931334_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<11, 1, [u8; 10]>::new(self.address, selector, "to_le_bytes", serialized_params).call(self.context) + } + } + + pub fn external_call_to_assertion_failure(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(294808228_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<34, 0, ()>::new(self.address, selector, "external_call_to_assertion_failure", serialized_params).call(self.context) + } + } + + pub fn new_nullifier(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3648851082_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 1, ()>::new(self.address, selector, "new_nullifier", serialized_params).call(self.context) + } + } + + pub fn divide_by_zero(self, denominator: u8) -> u8 { + let serialized_params: [Field; 1] = denominator.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(815932481_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 1, u8>::new(self.address, selector, "divide_by_zero", serialized_params).call(self.context) + } + } + + pub fn emit_public_log(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2033426724_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 0, ()>::new(self.address, selector, "emit_public_log", serialized_params).call(self.context) + } + } + + pub fn raw_l2_to_l1_msg(self, recipient: EthAddress, content: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = recipient.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = content.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3409962923_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 2, ()>::new(self.address, selector, "raw_l2_to_l1_msg", serialized_params).call(self.context) + } + } + + pub fn nested_call_to_nothing_recovers(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1843532057_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<31, 0, ()>::new(self.address, selector, "nested_call_to_nothing_recovers", serialized_params).call(self.context) + } + } + + pub fn assert_calldata_copy_large(self, args: [Field; 300], with_selector: bool) { + let mut serialized_params: [Field; 301] = [0_Field; 301]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 300 * 1] = args.serialize(); + let serialized_member_len: u32 = <[Field; 300] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = with_selector.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2293565755_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<26, 301, ()>::new(self.address, selector, "assert_calldata_copy_large", serialized_params).call(self.context) + } + } + + pub fn set_opcode_really_big_field(self) -> Field { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4095821182_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<27, 0, Field>::new(self.address, selector, "set_opcode_really_big_field", serialized_params).call(self.context) + } + } + + pub fn elliptic_curve_add(self, lhs: Point, rhs: Point) -> Point { + let mut serialized_params: [Field; 6] = [0_Field; 6]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = lhs.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 3] = rhs.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1700026912_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<18, 6, Point>::new(self.address, selector, "elliptic_curve_add", serialized_params).call(self.context) + } + } + + pub fn returndata_copy_oracle(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4172530660_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<22, 0, ()>::new(self.address, selector, "returndata_copy_oracle", serialized_params).call(self.context) + } + } + + pub fn set_read_storage_single(self, a: Field) -> Field { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1932358992_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<23, 1, Field>::new(self.address, selector, "set_read_storage_single", serialized_params).call(self.context) + } + } + + pub fn n_new_public_logs(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2907114368_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<17, 1, ()>::new(self.address, selector, "n_new_public_logs", serialized_params).call(self.context) + } + } + + pub fn conditional_move(self, x: [Field; 1], y: [Field; 1], b: bool) -> [Field; 1] { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1 * 1] = x.serialize(); + let serialized_member_len: u32 = <[Field; 1] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1 * 1] = y.serialize(); + let serialized_member_len: u32 = <[Field; 1] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2633971407_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 3, [Field; 1]>::new(self.address, selector, "conditional_move", serialized_params).call(self.context) + } + } + + pub fn set_opcode_small_field(self) -> Field { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3464175345_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<22, 0, Field>::new(self.address, selector, "set_opcode_small_field", serialized_params).call(self.context) + } + } + + pub fn nested_call_to_nothing(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1183868090_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<22, 0, ()>::new(self.address, selector, "nested_call_to_nothing", serialized_params).call(self.context) + } + } + + pub fn nested_call_to_add_with_gas(self, arg_a: Field, arg_b: Field, l2_gas: u32, da_gas: u32) -> Field { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = l2_gas.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = da_gas.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3561659563_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<27, 4, Field>::new(self.address, selector, "nested_call_to_add_with_gas", serialized_params).call(self.context) + } + } + + pub fn create_different_nullifier_in_nested_call(self, nestedAddress: AztecAddress, nullifier: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = nestedAddress.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = nullifier.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1630216043_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<41, 2, ()>::new(self.address, selector, "create_different_nullifier_in_nested_call", serialized_params).call(self.context) + } + } + + pub fn call_fee_juice(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2734888597_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 0, ()>::new(self.address, selector, "call_fee_juice", serialized_params).call(self.context) + } + } + + pub fn get_da_gas_left(self) -> u32 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2319460898_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 0, u32>::new(self.address, selector, "get_da_gas_left", serialized_params).call(self.context) + } + } + + pub fn get_transaction_fee(self) -> Field { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2524054657_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<19, 0, Field>::new(self.address, selector, "get_transaction_fee", serialized_params).call(self.context) + } + } + + pub fn read_storage_single(self) -> Field { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3140392744_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<19, 0, Field>::new(self.address, selector, "read_storage_single", serialized_params).call(self.context) + } + } + + pub fn assert_nullifier_exists(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2810255355_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<23, 1, ()>::new(self.address, selector, "assert_nullifier_exists", serialized_params).call(self.context) + } + } + + pub fn assertion_failure(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3276887878_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<17, 0, ()>::new(self.address, selector, "assertion_failure", serialized_params).call(self.context) + } + } + + pub fn debug_logging(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3667472301_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 0, ()>::new(self.address, selector, "debug_logging", serialized_params).call(self.context) + } + } + + pub fn nested_call_large_calldata(self, arr: [Field; 300]) -> Field { + let serialized_params: [Field; 300 * 1] = arr.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(14812432_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<26, 300 * 1, Field>::new(self.address, selector, "nested_call_large_calldata", serialized_params).call(self.context) + } + } + + pub fn external_call_to_divide_by_zero_recovers(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2245930342_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<40, 0, ()>::new(self.address, selector, "external_call_to_divide_by_zero_recovers", serialized_params).call(self.context) + } + } + + pub fn set_opcode_u32(self) -> u32 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4045556597_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 0, u32>::new(self.address, selector, "set_opcode_u32", serialized_params).call(self.context) + } + } + + pub fn call_instance_registry(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2336742722_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<22, 0, ()>::new(self.address, selector, "call_instance_registry", serialized_params).call(self.context) + } + } + + pub fn set_storage_single(self, a: Field) { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2230419055_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<18, 1, ()>::new(self.address, selector, "set_storage_single", serialized_params).call(self.context) + } + } + + pub fn nested_call_to_add(self, arg_a: Field, arg_b: Field) -> Field { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(94115833_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<18, 2, Field>::new(self.address, selector, "nested_call_to_add", serialized_params).call(self.context) + } + } + + pub fn revert_oracle(self) -> [Field; 3] { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4147614534_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 0, [Field; 3]>::new(self.address, selector, "revert_oracle", serialized_params).call(self.context) + } + } + + pub fn send_l2_to_l1_msg(self, recipient: EthAddress, content: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = recipient.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = content.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2709402942_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<17, 2, ()>::new(self.address, selector, "send_l2_to_l1_msg", serialized_params).call(self.context) + } + } + + pub fn note_hash_exists(self, note_hash: Field, leaf_index: u64) -> bool { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = note_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = leaf_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(671085844_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 2, bool>::new(self.address, selector, "note_hash_exists", serialized_params).call(self.context) + } + } + + pub fn read_storage_map(self, address: AztecAddress) -> u32 { + let serialized_params: [Field; 1] = address.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(711888726_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 1, u32>::new(self.address, selector, "read_storage_map", serialized_params).call(self.context) + } + } + + pub fn elliptic_curve_add_and_double(self) -> Point { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1891218722_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<29, 0, Point>::new(self.address, selector, "elliptic_curve_add_and_double", serialized_params).call(self.context) + } + } + + pub fn read_assert_storage_single(self, a: Field) { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1067389427_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<26, 1, ()>::new(self.address, selector, "read_assert_storage_single", serialized_params).call(self.context) + } + } + + pub fn get_block_number(self) -> u32 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3223336515_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 0, u32>::new(self.address, selector, "get_block_number", serialized_params).call(self.context) + } + } + + pub fn nested_call_to_assert_same(self, arg_a: Field, arg_b: Field) -> Field { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1563037608_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<26, 2, Field>::new(self.address, selector, "nested_call_to_assert_same", serialized_params).call(self.context) + } + } + + pub fn fn_w_large_calldata(self, _arr: [Field; 300]) -> Field { + let serialized_params: [Field; 300 * 1] = _arr.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3786762676_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<19, 300 * 1, Field>::new(self.address, selector, "fn_w_large_calldata", serialized_params).call(self.context) + } + } + + pub fn get_address(self) -> AztecAddress { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1968200506_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<11, 0, AztecAddress>::new(self.address, selector, "get_address", serialized_params).call(self.context) + } + } + + pub fn set_storage_map(self, to: AztecAddress, amount: u32) -> Field { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = to.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = amount.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1756672898_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<15, 2, Field>::new(self.address, selector, "set_storage_map", serialized_params).call(self.context) + } + } + + pub fn get_version(self) -> Field { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(421038220_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<11, 0, Field>::new(self.address, selector, "get_version", serialized_params).call(self.context) + } + } + + pub fn nested_static_call_to_set_storage(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3861896907_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<33, 0, ()>::new(self.address, selector, "nested_static_call_to_set_storage", serialized_params).call(self.context) + } + } + + pub fn create_same_nullifier_in_nested_call(self, nestedAddress: AztecAddress, nullifier: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = nestedAddress.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = nullifier.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1050471208_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<36, 2, ()>::new(self.address, selector, "create_same_nullifier_in_nested_call", serialized_params).call(self.context) + } + } + + pub fn set_opcode_big_field(self) -> Field { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(497423715_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<20, 0, Field>::new(self.address, selector, "set_opcode_big_field", serialized_params).call(self.context) + } + } + + pub fn u128_addition_overflow(self) -> u128 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2520497807_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<22, 0, u128>::new(self.address, selector, "u128_addition_overflow", serialized_params).call(self.context) + } + } + + pub fn add_u128(self, a: u128, b: u128) -> u128 { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1408352185_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<8, 2, u128>::new(self.address, selector, "add_u128", serialized_params).call(self.context) + } + } + + pub fn get_fee_per_l2_gas(self) -> u128 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(323255525_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<18, 0, u128>::new(self.address, selector, "get_fee_per_l2_gas", serialized_params).call(self.context) + } + } + + pub fn n_storage_writes(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2323221248_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<16, 1, ()>::new(self.address, selector, "n_storage_writes", serialized_params).call(self.context) + } + } + + pub fn set_opcode_u8(self) -> u8 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3068438800_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<13, 0, u8>::new(self.address, selector, "set_opcode_u8", serialized_params).call(self.context) + } + } + + pub fn n_new_note_hashes(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1938641640_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<17, 1, ()>::new(self.address, selector, "n_new_note_hashes", serialized_params).call(self.context) + } + } + + pub fn nested_call_to_add_n_times_different_addresses(self, addrs: [AztecAddress; 23]) { + let serialized_params: [Field; 23 * 1] = addrs.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2936248969_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<46, 23 * 1, ()>::new(self.address, selector, "nested_call_to_add_n_times_different_addresses", serialized_params).call(self.context) + } + } + } + + impl CallSelf<&mut aztec::context::PrivateContext> { + pub fn enqueue_public_from_private(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2771384488_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + } + + pub struct CallSelfStatic { + pub address: AztecAddress, + pub context: Context, + } + + impl CallSelfStatic { + pub fn set_opcode_u8_view(self) -> u8 { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(643109956_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<18, 0, u8>::new(self.address, selector, "set_opcode_u8_view", serialized_params).view(self.context) + } + } + } + + pub struct EnqueueSelf { + pub address: AztecAddress, + pub context: Context, + } + + impl EnqueueSelf<&mut aztec::context::PrivateContext> { + pub fn assert_calldata_copy(self, args: [Field; 3], with_selector: bool) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3 * 1] = args.serialize(); + let serialized_member_len: u32 = <[Field; 3] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = with_selector.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3853740100_Field); + let calldata: [Field; 1 + 4] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_chain_id(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1458572288_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_args_hash(self, _a: u8, _fields: [Field; 3]) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = _a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 3 * 1] = _fields.serialize(); + let serialized_member_len: u32 = <[Field; 3] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1608415988_Field); + let calldata: [Field; 1 + 4] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn external_call_to_divide_by_zero(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3880450065_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn n_new_nullifiers(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(592684400_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn new_note_hash(self, note_hash: Field) { + let serialized_params: [Field; 1] = note_hash.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1524332459_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nullifier_collision(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2417179850_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_l2_gas_left(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1635524210_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = msg_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = msg_leaf_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3972971575_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn add_storage_map(self, to: AztecAddress, amount: u32) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = to.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = amount.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2606877757_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn bulk_testing(self, args_field: [Field; 10], args_u8: [u8; 10], get_instance_for_address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field, skip_strictly_limited_side_effects: bool) { + let mut serialized_params: [Field; 25] = [0_Field; 25]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 10 * 1] = args_field.serialize(); + let serialized_member_len: u32 = <[Field; 10] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 10 * 1] = args_u8.serialize(); + let serialized_member_len: u32 = <[u8; 10] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = get_instance_for_address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_deployer.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_class_id.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_initialization_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = skip_strictly_limited_side_effects.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_6: u32 = i + offset; + serialized_params[i_6] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(43639379_Field); + let calldata: [Field; 1 + 25] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn add_args_return(self, arg_a: Field, arg_b: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2858633377_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn variable_base_msm(self, scalar_lo: Field, scalar_hi: Field, scalar2_lo: Field, scalar2_hi: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = scalar_lo.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar_hi.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar2_lo.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = scalar2_hi.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2931784034_Field); + let calldata: [Field; 1 + 4] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn test_get_contract_instance_matches(self, address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_deployer.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_class_id.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = expected_initialization_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2723912183_Field); + let calldata: [Field; 1 + 4] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_sender(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(301170519_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn n_new_l2_to_l1_msgs(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3921925917_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_storage_list(self, a: Field, b: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1745164739_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn pedersen_commit(self, x: Field, y: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = x.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = y.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2484465428_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nullifier_exists(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2051407563_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn read_storage_list(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1727615163_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn emit_nullifier_and_check(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2367487025_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn assert_same(self, arg_a: Field, arg_b: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(290442984_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_fee_per_da_gas(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(514475538_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn modulo2(self, a: u64) { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(222531562_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_static_call_to_add(self, arg_a: Field, arg_b: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1362946309_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn to_le_bits(self, input: Field) { + let serialized_params: [Field; 1] = input.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2961959597_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn call_auth_registry(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1225767423_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_opcode_u64(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1435480431_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn return_oracle(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3794636397_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn test_get_contract_instance(self, address: AztecAddress) { + let serialized_params: [Field; 1] = address.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2488367864_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_timestamp(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(448989811_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn to_le_bytes(self, input: Field) { + let serialized_params: [Field; 1] = input.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1975931334_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn external_call_to_assertion_failure(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(294808228_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn new_nullifier(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3648851082_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn divide_by_zero(self, denominator: u8) { + let serialized_params: [Field; 1] = denominator.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(815932481_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn emit_public_log(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2033426724_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn raw_l2_to_l1_msg(self, recipient: EthAddress, content: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = recipient.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = content.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3409962923_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_call_to_nothing_recovers(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1843532057_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn assert_calldata_copy_large(self, args: [Field; 300], with_selector: bool) { + let mut serialized_params: [Field; 301] = [0_Field; 301]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 300 * 1] = args.serialize(); + let serialized_member_len: u32 = <[Field; 300] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = with_selector.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2293565755_Field); + let calldata: [Field; 1 + 301] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_opcode_really_big_field(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4095821182_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn elliptic_curve_add(self, lhs: Point, rhs: Point) { + let mut serialized_params: [Field; 6] = [0_Field; 6]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 3] = lhs.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 3] = rhs.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1700026912_Field); + let calldata: [Field; 1 + 6] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn returndata_copy_oracle(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4172530660_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_read_storage_single(self, a: Field) { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1932358992_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn n_new_public_logs(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2907114368_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn conditional_move(self, x: [Field; 1], y: [Field; 1], b: bool) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1 * 1] = x.serialize(); + let serialized_member_len: u32 = <[Field; 1] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1 * 1] = y.serialize(); + let serialized_member_len: u32 = <[Field; 1] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2633971407_Field); + let calldata: [Field; 1 + 3] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_opcode_small_field(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3464175345_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_call_to_nothing(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1183868090_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_call_to_add_with_gas(self, arg_a: Field, arg_b: Field, l2_gas: u32, da_gas: u32) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = l2_gas.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = da_gas.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(3561659563_Field); + let calldata: [Field; 1 + 4] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn create_different_nullifier_in_nested_call(self, nestedAddress: AztecAddress, nullifier: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = nestedAddress.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = nullifier.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1630216043_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn call_fee_juice(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2734888597_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_da_gas_left(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2319460898_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_transaction_fee(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2524054657_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn read_storage_single(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3140392744_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn assert_nullifier_exists(self, nullifier: Field) { + let serialized_params: [Field; 1] = nullifier.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2810255355_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn assertion_failure(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3276887878_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn debug_logging(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3667472301_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_call_large_calldata(self, arr: [Field; 300]) { + let serialized_params: [Field; 300 * 1] = arr.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(14812432_Field); + let calldata: [Field; 1 + (300 * 1)] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn external_call_to_divide_by_zero_recovers(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2245930342_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_opcode_u32(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4045556597_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn call_instance_registry(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2336742722_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_storage_single(self, a: Field) { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2230419055_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_call_to_add(self, arg_a: Field, arg_b: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(94115833_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn revert_oracle(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(4147614534_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn send_l2_to_l1_msg(self, recipient: EthAddress, content: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = recipient.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = content.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(2709402942_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn note_hash_exists(self, note_hash: Field, leaf_index: u64) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = note_hash.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = leaf_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(671085844_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn read_storage_map(self, address: AztecAddress) { + let serialized_params: [Field; 1] = address.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(711888726_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn elliptic_curve_add_and_double(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1891218722_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn read_assert_storage_single(self, a: Field) { + let serialized_params: [Field; 1] = a.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1067389427_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_block_number(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3223336515_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_call_to_assert_same(self, arg_a: Field, arg_b: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = arg_a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = arg_b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1563037608_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn fn_w_large_calldata(self, _arr: [Field; 300]) { + let serialized_params: [Field; 300 * 1] = _arr.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(3786762676_Field); + let calldata: [Field; 1 + (300 * 1)] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_address(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(1968200506_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_storage_map(self, to: AztecAddress, amount: u32) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = to.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = amount.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1756672898_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_version(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(421038220_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_static_call_to_set_storage(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3861896907_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn create_same_nullifier_in_nested_call(self, nestedAddress: AztecAddress, nullifier: Field) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = nestedAddress.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = nullifier.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1050471208_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_opcode_big_field(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(497423715_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn u128_addition_overflow(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(2520497807_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn add_u128(self, a: u128, b: u128) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = a.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = b.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: FunctionSelector = FunctionSelector::from_field(1408352185_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn get_fee_per_l2_gas(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(323255525_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn n_storage_writes(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2323221248_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_opcode_u8(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(3068438800_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn n_new_note_hashes(self, num: u32) { + let serialized_params: [Field; 1] = num.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(1938641640_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn nested_call_to_add_n_times_different_addresses(self, addrs: [AztecAddress; 23]) { + let serialized_params: [Field; 23 * 1] = addrs.serialize(); + let selector: FunctionSelector = FunctionSelector::from_field(2936248969_Field); + let calldata: [Field; 1 + (23 * 1)] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + } + + pub struct EnqueueSelfStatic { + pub address: AztecAddress, + pub context: Context, + } + + impl EnqueueSelfStatic<&mut aztec::context::PrivateContext> { + pub fn set_opcode_u8_view(self) { + let serialized_params: [Field; 0] = []; + let selector: FunctionSelector = FunctionSelector::from_field(643109956_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + } + + pub struct CallSelfUtility { + pub address: AztecAddress, + } + + pub struct CallInternal { + pub context: Context, + } + + pub unconstrained fn public_dispatch(selector: Field) { + if selector == 2230419055_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__set_storage_single(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3140392744_Field { + let return_value: [Field; 1] = __aztec_nr_internals__read_storage_single().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1067389427_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__read_assert_storage_single(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1932358992_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__set_read_storage_single(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1745164739_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__set_storage_list(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1727615163_Field { + let return_value: [Field; 2 * 1] = __aztec_nr_internals__read_storage_list().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1756672898_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: u32 = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__set_storage_map(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2606877757_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: u32 = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__add_storage_map(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 711888726_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__read_storage_map(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2858633377_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__add_args_return(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3068438800_Field { + let return_value: [Field; 1] = __aztec_nr_internals__set_opcode_u8().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 643109956_Field { + let return_value: [Field; 1] = __aztec_nr_internals__set_opcode_u8_view().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 4045556597_Field { + let return_value: [Field; 1] = __aztec_nr_internals__set_opcode_u32().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1435480431_Field { + let return_value: [Field; 1] = __aztec_nr_internals__set_opcode_u64().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3464175345_Field { + let return_value: [Field; 1] = __aztec_nr_internals__set_opcode_small_field().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 497423715_Field { + let return_value: [Field; 1] = __aztec_nr_internals__set_opcode_big_field().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 4095821182_Field { + let return_value: [Field; 1] = __aztec_nr_internals__set_opcode_really_big_field().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1408352185_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: u128 = ::stream_deserialize(&mut reader); + let arg1: u128 = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__add_u128(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 222531562_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: u64 = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__modulo2(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1700026912_Field { + let input_calldata: [Field; 6] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<6> = aztec::protocol::utils::reader::Reader::<6>::new(input_calldata); + let arg0: Point = ::stream_deserialize(&mut reader); + let arg1: Point = ::stream_deserialize(&mut reader); + let return_value: [Field; 3] = __aztec_nr_internals__elliptic_curve_add(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1891218722_Field { + let return_value: [Field; 3] = __aztec_nr_internals__elliptic_curve_add_and_double().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2931784034_Field { + let input_calldata: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<4> = aztec::protocol::utils::reader::Reader::<4>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let arg2: Field = ::stream_deserialize(&mut reader); + let arg3: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 3] = __aztec_nr_internals__variable_base_msm(arg0, arg1, arg2, arg3).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2484465428_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 3] = __aztec_nr_internals__pedersen_commit(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2633971407_Field { + let input_calldata: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (<[Field; 1] as Serialize>::N + <[Field; 1] as Serialize>::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<3> = aztec::protocol::utils::reader::Reader::<3>::new(input_calldata); + let arg0: [Field; 1] = <[Field; 1] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let arg1: [Field; 1] = <[Field; 1] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let arg2: bool = ::stream_deserialize(&mut reader); + let return_value: [Field; 1 * 1] = __aztec_nr_internals__conditional_move(arg0, arg1, arg2).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2520497807_Field { + let return_value: [Field; 1] = __aztec_nr_internals__u128_addition_overflow().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1975931334_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 10 * 1] = __aztec_nr_internals__to_le_bytes(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2961959597_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 16 * 1] = __aztec_nr_internals__to_le_bits(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3276887878_Field { + __aztec_nr_internals__assertion_failure(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 294808228_Field { + __aztec_nr_internals__external_call_to_assertion_failure(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 815932481_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: u8 = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__divide_by_zero(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3880450065_Field { + __aztec_nr_internals__external_call_to_divide_by_zero(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2245930342_Field { + __aztec_nr_internals__external_call_to_divide_by_zero_recovers(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3667472301_Field { + __aztec_nr_internals__debug_logging(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 290442984_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__assert_same(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3853740100_Field { + let input_calldata: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 3] as Serialize>::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<4> = aztec::protocol::utils::reader::Reader::<4>::new(input_calldata); + let arg0: [Field; 3] = <[Field; 3] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let arg1: bool = ::stream_deserialize(&mut reader); + __aztec_nr_internals__assert_calldata_copy(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2293565755_Field { + let input_calldata: [Field; 301] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 300] as Serialize>::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<301> = aztec::protocol::utils::reader::Reader::<301>::new(input_calldata); + let arg0: [Field; 300] = <[Field; 300] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let arg1: bool = ::stream_deserialize(&mut reader); + __aztec_nr_internals__assert_calldata_copy_large(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 4172530660_Field { + __aztec_nr_internals__returndata_copy_oracle(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3794636397_Field { + let return_value: [Field; 3 * 1] = __aztec_nr_internals__return_oracle().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 4147614534_Field { + let return_value: [Field; 3 * 1] = __aztec_nr_internals__revert_oracle().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2488367864_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + __aztec_nr_internals__test_get_contract_instance(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2723912183_Field { + let input_calldata: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<4> = aztec::protocol::utils::reader::Reader::<4>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: AztecAddress = ::stream_deserialize(&mut reader); + let arg2: ContractClassId = ::stream_deserialize(&mut reader); + let arg3: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__test_get_contract_instance_matches(arg0, arg1, arg2, arg3); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1968200506_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_address().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 301170519_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_sender().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2524054657_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_transaction_fee().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1458572288_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_chain_id().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 421038220_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_version().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3223336515_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_block_number().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 448989811_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_timestamp().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 323255525_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_fee_per_l2_gas().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 514475538_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_fee_per_da_gas().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1635524210_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_l2_gas_left().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2319460898_Field { + let return_value: [Field; 1] = __aztec_nr_internals__get_da_gas_left().serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1608415988_Field { + let input_calldata: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ::N + <[Field; 3] as Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<4> = aztec::protocol::utils::reader::Reader::<4>::new(input_calldata); + let arg0: u8 = ::stream_deserialize(&mut reader); + let arg1: [Field; 3] = <[Field; 3] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__get_args_hash(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2033426724_Field { + __aztec_nr_internals__emit_public_log(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 671085844_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: u64 = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__note_hash_exists(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1524332459_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__new_note_hash(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3648851082_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__new_nullifier(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2323221248_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: u32 = ::stream_deserialize(&mut reader); + __aztec_nr_internals__n_storage_writes(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1938641640_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: u32 = ::stream_deserialize(&mut reader); + __aztec_nr_internals__n_new_note_hashes(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 592684400_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: u32 = ::stream_deserialize(&mut reader); + __aztec_nr_internals__n_new_nullifiers(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3921925917_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: u32 = ::stream_deserialize(&mut reader); + __aztec_nr_internals__n_new_l2_to_l1_msgs(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3409962923_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: EthAddress = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__raw_l2_to_l1_msg(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2907114368_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: u32 = ::stream_deserialize(&mut reader); + __aztec_nr_internals__n_new_public_logs(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2051407563_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__nullifier_exists(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2810255355_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__assert_nullifier_exists(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2367487025_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__emit_nullifier_and_check(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2417179850_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__nullifier_collision(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3972971575_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__l1_to_l2_msg_exists(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2709402942_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: EthAddress = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__send_l2_to_l1_msg(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1183868090_Field { + __aztec_nr_internals__nested_call_to_nothing(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1843532057_Field { + __aztec_nr_internals__nested_call_to_nothing_recovers(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3561659563_Field { + let input_calldata: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<4> = aztec::protocol::utils::reader::Reader::<4>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let arg2: u32 = ::stream_deserialize(&mut reader); + let arg3: u32 = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__nested_call_to_add_with_gas(arg0, arg1, arg2, arg3).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 94115833_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__nested_call_to_add(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2936248969_Field { + let input_calldata: [Field; 23 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[AztecAddress; 23] as Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<23 * 1> = aztec::protocol::utils::reader::Reader::<23 * 1>::new(input_calldata); + let arg0: [AztecAddress; 23] = <[AztecAddress; 23] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + __aztec_nr_internals__nested_call_to_add_n_times_different_addresses(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1362946309_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__nested_static_call_to_add(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3861896907_Field { + __aztec_nr_internals__nested_static_call_to_set_storage(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1050471208_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__create_same_nullifier_in_nested_call(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1630216043_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__create_different_nullifier_in_nested_call(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1563037608_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: Field = ::stream_deserialize(&mut reader); + let arg1: Field = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__nested_call_to_assert_same(arg0, arg1).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3786762676_Field { + let input_calldata: [Field; 300 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 300] as Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<300 * 1> = aztec::protocol::utils::reader::Reader::<300 * 1>::new(input_calldata); + let arg0: [Field; 300] = <[Field; 300] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__fn_w_large_calldata(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 14812432_Field { + let input_calldata: [Field; 300 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 300] as Serialize>::N); + let mut reader: aztec::protocol::utils::reader::Reader<300 * 1> = aztec::protocol::utils::reader::Reader::<300 * 1>::new(input_calldata); + let arg0: [Field; 300] = <[Field; 300] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let return_value: [Field; 1] = __aztec_nr_internals__nested_call_large_calldata(arg0).serialize(); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2734888597_Field { + __aztec_nr_internals__call_fee_juice(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1225767423_Field { + __aztec_nr_internals__call_auth_registry(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2336742722_Field { + __aztec_nr_internals__call_instance_registry(); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 43639379_Field { + let input_calldata: [Field; 25] = aztec::oracle::avm::calldata_copy(1_u32, (((((<[Field; 10] as Serialize>::N + <[u8; 10] as Serialize>::N) + ::N) + ::N) + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<25> = aztec::protocol::utils::reader::Reader::<25>::new(input_calldata); + let arg0: [Field; 10] = <[Field; 10] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let arg1: [u8; 10] = <[u8; 10] as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let arg2: AztecAddress = ::stream_deserialize(&mut reader); + let arg3: AztecAddress = ::stream_deserialize(&mut reader); + let arg4: ContractClassId = ::stream_deserialize(&mut reader); + let arg5: Field = ::stream_deserialize(&mut reader); + let arg6: bool = ::stream_deserialize(&mut reader); + __aztec_nr_internals__bulk_testing(arg0, arg1, arg2, arg3, arg4, arg5, arg6); + aztec::oracle::avm::avm_return([].as_slice()); + }; + panic(f"Unknown selector {selector}") + } + + pub struct add_args_return_parameters { + pub arg_a: Field, + pub arg_b: Field, + } + + pub struct add_storage_map_parameters { + pub to: AztecAddress, + pub amount: u32, + } + + pub struct add_u128_parameters { + pub a: u128, + pub b: u128, + } + + pub struct assert_calldata_copy_large_parameters { + pub args: [Field; 300], + pub with_selector: bool, + } + + pub struct assert_calldata_copy_parameters { + pub args: [Field; 3], + pub with_selector: bool, + } + + pub struct assert_nullifier_exists_parameters { + pub nullifier: Field, + } + + pub struct assert_same_parameters { + pub arg_a: Field, + pub arg_b: Field, + } + + pub struct assertion_failure_parameters { + } + + pub struct bulk_testing_parameters { + pub args_field: [Field; 10], + pub args_u8: [u8; 10], + pub get_instance_for_address: AztecAddress, + pub expected_deployer: AztecAddress, + pub expected_class_id: ContractClassId, + pub expected_initialization_hash: Field, + pub skip_strictly_limited_side_effects: bool, + } + + pub struct call_auth_registry_parameters { + } + + pub struct call_fee_juice_parameters { + } + + pub struct call_instance_registry_parameters { + } + + pub struct conditional_move_parameters { + pub x: [Field; 1], + pub y: [Field; 1], + pub b: bool, + } + + pub struct create_different_nullifier_in_nested_call_parameters { + pub nestedAddress: AztecAddress, + pub nullifier: Field, + } + + pub struct create_same_nullifier_in_nested_call_parameters { + pub nestedAddress: AztecAddress, + pub nullifier: Field, + } + + pub struct debug_logging_parameters { + } + + pub struct divide_by_zero_parameters { + pub denominator: u8, + } + + pub struct elliptic_curve_add_and_double_parameters { + } + + pub struct elliptic_curve_add_parameters { + pub lhs: Point, + pub rhs: Point, + } + + pub struct emit_nullifier_and_check_parameters { + pub nullifier: Field, + } + + pub struct emit_public_log_parameters { + } + + pub struct enqueue_public_from_private_parameters { + } + + pub struct external_call_to_assertion_failure_parameters { + } + + pub struct external_call_to_divide_by_zero_parameters { + } + + pub struct external_call_to_divide_by_zero_recovers_parameters { + } + + pub struct fn_w_large_calldata_parameters { + pub _arr: [Field; 300], + } + + pub struct get_address_parameters { + } + + pub struct get_args_hash_parameters { + pub _a: u8, + pub _fields: [Field; 3], + } + + pub struct get_block_number_parameters { + } + + pub struct get_chain_id_parameters { + } + + pub struct get_da_gas_left_parameters { + } + + pub struct get_fee_per_da_gas_parameters { + } + + pub struct get_fee_per_l2_gas_parameters { + } + + pub struct get_l2_gas_left_parameters { + } + + pub struct get_sender_parameters { + } + + pub struct get_timestamp_parameters { + } + + pub struct get_transaction_fee_parameters { + } + + pub struct get_version_parameters { + } + + pub struct l1_to_l2_msg_exists_parameters { + pub msg_hash: Field, + pub msg_leaf_index: Field, + } + + pub struct modulo2_parameters { + pub a: u64, + } + + pub struct n_new_l2_to_l1_msgs_parameters { + pub num: u32, + } + + pub struct n_new_note_hashes_parameters { + pub num: u32, + } + + pub struct n_new_nullifiers_parameters { + pub num: u32, + } + + pub struct n_new_public_logs_parameters { + pub num: u32, + } + + pub struct n_storage_writes_parameters { + pub num: u32, + } + + pub struct nested_call_large_calldata_parameters { + pub arr: [Field; 300], + } + + pub struct nested_call_to_add_n_times_different_addresses_parameters { + pub addrs: [AztecAddress; 23], + } + + pub struct nested_call_to_add_parameters { + pub arg_a: Field, + pub arg_b: Field, + } + + pub struct nested_call_to_add_with_gas_parameters { + pub arg_a: Field, + pub arg_b: Field, + pub l2_gas: u32, + pub da_gas: u32, + } + + pub struct nested_call_to_assert_same_parameters { + pub arg_a: Field, + pub arg_b: Field, + } + + pub struct nested_call_to_nothing_parameters { + } + + pub struct nested_call_to_nothing_recovers_parameters { + } + + pub struct nested_static_call_to_add_parameters { + pub arg_a: Field, + pub arg_b: Field, + } + + pub struct nested_static_call_to_set_storage_parameters { + } + + pub struct new_note_hash_parameters { + pub note_hash: Field, + } + + pub struct new_nullifier_parameters { + pub nullifier: Field, + } + + pub struct note_hash_exists_parameters { + pub note_hash: Field, + pub leaf_index: u64, + } + + pub struct nullifier_collision_parameters { + pub nullifier: Field, + } + + pub struct nullifier_exists_parameters { + pub nullifier: Field, + } + + pub struct pedersen_commit_parameters { + pub x: Field, + pub y: Field, + } + + pub struct raw_l2_to_l1_msg_parameters { + pub recipient: EthAddress, + pub content: Field, + } + + pub struct read_assert_storage_single_parameters { + pub a: Field, + } + + pub struct read_storage_list_parameters { + } + + pub struct read_storage_map_parameters { + pub address: AztecAddress, + } + + pub struct read_storage_single_parameters { + } + + pub struct return_oracle_parameters { + } + + pub struct returndata_copy_oracle_parameters { + } + + pub struct revert_oracle_parameters { + } + + pub struct send_l2_to_l1_msg_parameters { + pub recipient: EthAddress, + pub content: Field, + } + + pub struct set_opcode_big_field_parameters { + } + + pub struct set_opcode_really_big_field_parameters { + } + + pub struct set_opcode_small_field_parameters { + } + + pub struct set_opcode_u32_parameters { + } + + pub struct set_opcode_u64_parameters { + } + + pub struct set_opcode_u8_parameters { + } + + pub struct set_opcode_u8_view_parameters { + } + + pub struct set_read_storage_single_parameters { + pub a: Field, + } + + pub struct set_storage_list_parameters { + pub a: Field, + pub b: Field, + } + + pub struct set_storage_map_parameters { + pub to: AztecAddress, + pub amount: u32, + } + + pub struct set_storage_single_parameters { + pub a: Field, + } + + pub struct test_get_contract_instance_matches_parameters { + pub address: AztecAddress, + pub expected_deployer: AztecAddress, + pub expected_class_id: ContractClassId, + pub expected_initialization_hash: Field, + } + + pub struct test_get_contract_instance_parameters { + pub address: AztecAddress, + } + + pub struct to_le_bits_parameters { + pub input: Field, + } + + pub struct to_le_bytes_parameters { + pub input: Field, + } + + pub struct u128_addition_overflow_parameters { + } + + pub struct variable_base_msm_parameters { + pub scalar_lo: Field, + pub scalar_hi: Field, + pub scalar2_lo: Field, + pub scalar2_hi: Field, + } + + #[abi(functions)] + pub struct add_args_return_abi { + parameters: add_args_return_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct add_storage_map_abi { + parameters: add_storage_map_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct add_u128_abi { + parameters: add_u128_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct assert_calldata_copy_abi { + parameters: assert_calldata_copy_parameters, + } + + #[abi(functions)] + pub struct assert_calldata_copy_large_abi { + parameters: assert_calldata_copy_large_parameters, + } + + #[abi(functions)] + pub struct assert_nullifier_exists_abi { + parameters: assert_nullifier_exists_parameters, + } + + #[abi(functions)] + pub struct assert_same_abi { + parameters: assert_same_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct assertion_failure_abi { + parameters: assertion_failure_parameters, + } + + #[abi(functions)] + pub struct bulk_testing_abi { + parameters: bulk_testing_parameters, + } + + #[abi(functions)] + pub struct call_auth_registry_abi { + parameters: call_auth_registry_parameters, + } + + #[abi(functions)] + pub struct call_fee_juice_abi { + parameters: call_fee_juice_parameters, + } + + #[abi(functions)] + pub struct call_instance_registry_abi { + parameters: call_instance_registry_parameters, + } + + #[abi(functions)] + pub struct conditional_move_abi { + parameters: conditional_move_parameters, + return_type: [Field; 1], + } + + #[abi(functions)] + pub struct create_different_nullifier_in_nested_call_abi { + parameters: create_different_nullifier_in_nested_call_parameters, + } + + #[abi(functions)] + pub struct create_same_nullifier_in_nested_call_abi { + parameters: create_same_nullifier_in_nested_call_parameters, + } + + #[abi(functions)] + pub struct debug_logging_abi { + parameters: debug_logging_parameters, + } + + #[abi(functions)] + pub struct divide_by_zero_abi { + parameters: divide_by_zero_parameters, + return_type: u8, + } + + #[abi(functions)] + pub struct elliptic_curve_add_abi { + parameters: elliptic_curve_add_parameters, + return_type: Point, + } + + #[abi(functions)] + pub struct elliptic_curve_add_and_double_abi { + parameters: elliptic_curve_add_and_double_parameters, + return_type: Point, + } + + #[abi(functions)] + pub struct emit_nullifier_and_check_abi { + parameters: emit_nullifier_and_check_parameters, + } + + #[abi(functions)] + pub struct emit_public_log_abi { + parameters: emit_public_log_parameters, + } + + #[abi(functions)] + pub struct enqueue_public_from_private_abi { + parameters: enqueue_public_from_private_parameters, + } + + #[abi(functions)] + pub struct external_call_to_assertion_failure_abi { + parameters: external_call_to_assertion_failure_parameters, + } + + #[abi(functions)] + pub struct external_call_to_divide_by_zero_abi { + parameters: external_call_to_divide_by_zero_parameters, + } + + #[abi(functions)] + pub struct external_call_to_divide_by_zero_recovers_abi { + parameters: external_call_to_divide_by_zero_recovers_parameters, + } + + #[abi(functions)] + pub struct fn_w_large_calldata_abi { + parameters: fn_w_large_calldata_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct get_address_abi { + parameters: get_address_parameters, + return_type: AztecAddress, + } + + #[abi(functions)] + pub struct get_args_hash_abi { + parameters: get_args_hash_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct get_block_number_abi { + parameters: get_block_number_parameters, + return_type: u32, + } + + #[abi(functions)] + pub struct get_chain_id_abi { + parameters: get_chain_id_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct get_da_gas_left_abi { + parameters: get_da_gas_left_parameters, + return_type: u32, + } + + #[abi(functions)] + pub struct get_fee_per_da_gas_abi { + parameters: get_fee_per_da_gas_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct get_fee_per_l2_gas_abi { + parameters: get_fee_per_l2_gas_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct get_l2_gas_left_abi { + parameters: get_l2_gas_left_parameters, + return_type: u32, + } + + #[abi(functions)] + pub struct get_sender_abi { + parameters: get_sender_parameters, + return_type: AztecAddress, + } + + #[abi(functions)] + pub struct get_timestamp_abi { + parameters: get_timestamp_parameters, + return_type: u64, + } + + #[abi(functions)] + pub struct get_transaction_fee_abi { + parameters: get_transaction_fee_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct get_version_abi { + parameters: get_version_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct l1_to_l2_msg_exists_abi { + parameters: l1_to_l2_msg_exists_parameters, + return_type: bool, + } + + #[abi(functions)] + pub struct modulo2_abi { + parameters: modulo2_parameters, + return_type: u64, + } + + #[abi(functions)] + pub struct n_new_l2_to_l1_msgs_abi { + parameters: n_new_l2_to_l1_msgs_parameters, + } + + #[abi(functions)] + pub struct n_new_note_hashes_abi { + parameters: n_new_note_hashes_parameters, + } + + #[abi(functions)] + pub struct n_new_nullifiers_abi { + parameters: n_new_nullifiers_parameters, + } + + #[abi(functions)] + pub struct n_new_public_logs_abi { + parameters: n_new_public_logs_parameters, + } + + #[abi(functions)] + pub struct n_storage_writes_abi { + parameters: n_storage_writes_parameters, + } + + #[abi(functions)] + pub struct nested_call_large_calldata_abi { + parameters: nested_call_large_calldata_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct nested_call_to_add_abi { + parameters: nested_call_to_add_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct nested_call_to_add_n_times_different_addresses_abi { + parameters: nested_call_to_add_n_times_different_addresses_parameters, + } + + #[abi(functions)] + pub struct nested_call_to_add_with_gas_abi { + parameters: nested_call_to_add_with_gas_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct nested_call_to_assert_same_abi { + parameters: nested_call_to_assert_same_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct nested_call_to_nothing_abi { + parameters: nested_call_to_nothing_parameters, + } + + #[abi(functions)] + pub struct nested_call_to_nothing_recovers_abi { + parameters: nested_call_to_nothing_recovers_parameters, + } + + #[abi(functions)] + pub struct nested_static_call_to_add_abi { + parameters: nested_static_call_to_add_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct nested_static_call_to_set_storage_abi { + parameters: nested_static_call_to_set_storage_parameters, + } + + #[abi(functions)] + pub struct new_note_hash_abi { + parameters: new_note_hash_parameters, + } + + #[abi(functions)] + pub struct new_nullifier_abi { + parameters: new_nullifier_parameters, + } + + #[abi(functions)] + pub struct note_hash_exists_abi { + parameters: note_hash_exists_parameters, + return_type: bool, + } + + #[abi(functions)] + pub struct nullifier_collision_abi { + parameters: nullifier_collision_parameters, + } + + #[abi(functions)] + pub struct nullifier_exists_abi { + parameters: nullifier_exists_parameters, + return_type: bool, + } + + #[abi(functions)] + pub struct pedersen_commit_abi { + parameters: pedersen_commit_parameters, + return_type: Point, + } + + #[abi(functions)] + pub struct raw_l2_to_l1_msg_abi { + parameters: raw_l2_to_l1_msg_parameters, + } + + #[abi(functions)] + pub struct read_assert_storage_single_abi { + parameters: read_assert_storage_single_parameters, + } + + #[abi(functions)] + pub struct read_storage_list_abi { + parameters: read_storage_list_parameters, + return_type: [Field; 2], + } + + #[abi(functions)] + pub struct read_storage_map_abi { + parameters: read_storage_map_parameters, + return_type: u32, + } + + #[abi(functions)] + pub struct read_storage_single_abi { + parameters: read_storage_single_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct return_oracle_abi { + parameters: return_oracle_parameters, + return_type: [Field; 3], + } + + #[abi(functions)] + pub struct returndata_copy_oracle_abi { + parameters: returndata_copy_oracle_parameters, + } + + #[abi(functions)] + pub struct revert_oracle_abi { + parameters: revert_oracle_parameters, + return_type: [Field; 3], + } + + #[abi(functions)] + pub struct send_l2_to_l1_msg_abi { + parameters: send_l2_to_l1_msg_parameters, + } + + #[abi(functions)] + pub struct set_opcode_big_field_abi { + parameters: set_opcode_big_field_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct set_opcode_really_big_field_abi { + parameters: set_opcode_really_big_field_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct set_opcode_small_field_abi { + parameters: set_opcode_small_field_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct set_opcode_u32_abi { + parameters: set_opcode_u32_parameters, + return_type: u32, + } + + #[abi(functions)] + pub struct set_opcode_u64_abi { + parameters: set_opcode_u64_parameters, + return_type: u64, + } + + #[abi(functions)] + pub struct set_opcode_u8_abi { + parameters: set_opcode_u8_parameters, + return_type: u8, + } + + #[abi(functions)] + pub struct set_opcode_u8_view_abi { + parameters: set_opcode_u8_view_parameters, + return_type: u8, + } + + #[abi(functions)] + pub struct set_read_storage_single_abi { + parameters: set_read_storage_single_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct set_storage_list_abi { + parameters: set_storage_list_parameters, + } + + #[abi(functions)] + pub struct set_storage_map_abi { + parameters: set_storage_map_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct set_storage_single_abi { + parameters: set_storage_single_parameters, + } + + #[abi(functions)] + pub struct test_get_contract_instance_abi { + parameters: test_get_contract_instance_parameters, + } + + #[abi(functions)] + pub struct test_get_contract_instance_matches_abi { + parameters: test_get_contract_instance_matches_parameters, + } + + #[abi(functions)] + pub struct to_le_bits_abi { + parameters: to_le_bits_parameters, + return_type: [bool; 16], + } + + #[abi(functions)] + pub struct to_le_bytes_abi { + parameters: to_le_bytes_parameters, + return_type: [u8; 10], + } + + #[abi(functions)] + pub struct u128_addition_overflow_abi { + parameters: u128_addition_overflow_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct variable_base_msm_abi { + parameters: variable_base_msm_parameters, + return_type: Point, + } + + fn __aztec_nr_internals__enqueue_public_from_private(inputs: aztec::context::inputs::PrivateContextInputs) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility> = { + let serialized_params: [Field; 0] = []; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut aztec::context::PrivateContext> = Storage::<&mut aztec::context::PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut aztec::context::PrivateContext> = CallSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut aztec::context::PrivateContext> = EnqueueSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal::<&mut aztec::context::PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + self.enqueue_self_static.set_opcode_u8_view(); + self.enqueue_self.set_read_storage_single(5_Field); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + unconstrained fn __aztec_nr_internals__add_args_return(arg_a: Field, arg_b: Field) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + add(arg_a, arg_b) + } + } + + unconstrained fn __aztec_nr_internals__add_storage_map(to: AztecAddress, amount: u32) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _add_storage_map(self.storage, to, amount) + } + } + + unconstrained fn __aztec_nr_internals__add_u128(a: u128, b: u128) -> pub u128 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + a + b + } + } + + unconstrained fn __aztec_nr_internals__assert_calldata_copy(args: [Field; 3], with_selector: bool) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 3] as Serialize>::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let offset: u32 = with_selector as u32; + let cd: [Field; 3] = aztec::oracle::avm::calldata_copy(offset, 3_u32); + assert(cd == args, "Calldata copy failed"); + } + } + + unconstrained fn __aztec_nr_internals__assert_calldata_copy_large(args: [Field; 300], with_selector: bool) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 301] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 300] as Serialize>::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let offset: u32 = with_selector as u32; + let cd: [Field; 300] = aztec::oracle::avm::calldata_copy(offset, 300_u32); + assert(cd == args, "Calldata copy failed"); + } + } + + unconstrained fn __aztec_nr_internals__assert_nullifier_exists(nullifier: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + assert(self.context.nullifier_exists_unsafe(nullifier, self.address), "Nullifier doesn't exist!"); + } + } + + unconstrained fn __aztec_nr_internals__assert_same(arg_a: Field, arg_b: Field) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + assert(arg_a == arg_b, "Values are not equal"); + 1_Field + } + } + + unconstrained fn __aztec_nr_internals__assertion_failure() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + helper_with_failed_assertion() + } + } + + unconstrained fn __aztec_nr_internals__bulk_testing(args_field: [Field; 10], args_u8: [u8; 10], get_instance_for_address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field, skip_strictly_limited_side_effects: bool) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 25] = aztec::oracle::avm::calldata_copy(1_u32, (((((<[Field; 10] as Serialize>::N + <[u8; 10] as Serialize>::N) + ::N) + ::N) + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + aztec::oracle::logging::debug_log("biwise_ops"); + let num: u32 = self.context.block_number(); + let _: u32 = bitwise_ops(num, num); + aztec::oracle::logging::debug_log("set_storage_single"); + _set_storage_single(self.storage, 30_Field); + aztec::oracle::logging::debug_log("set_storage_list"); + _set_storage_list(self.storage, 40_Field, 50_Field); + aztec::oracle::logging::debug_log("read_storage_list"); + let _: Field = _set_storage_map(self.storage, self.address, 60_u32); + aztec::oracle::logging::debug_log("add_storage_map"); + let _: Field = _add_storage_map(self.storage, self.address, 10_u32); + aztec::oracle::logging::debug_log("read_storage_map"); + let _: u32 = _read_storage_map(self.storage, self.address); + aztec::oracle::logging::debug_log("keccak_hash"); + let _: [u8; 32] = keccak256::keccak256(args_u8, args_u8.len()); + aztec::oracle::logging::debug_log("sha256_hash"); + let _: [u8; 32] = sha256::sha256_var(args_u8, args_u8.len()); + aztec::oracle::logging::debug_log("poseidon2_hash"); + let _: Field = poseidon::poseidon2::Poseidon2::hash(args_field, args_field.len()); + aztec::oracle::logging::debug_log("pedersen_hash"); + let _: Field = std::hash::pedersen_hash(args_field); + aztec::oracle::logging::debug_log("pedersen_hash_with_index"); + let _: Field = std::hash::pedersen_hash_with_separator(args_field, 20_u32); + aztec::oracle::logging::debug_log("integer_division"); + let _: u8 = integer_division(args_u8[0_u32], args_u8[1_u32]); + aztec::oracle::logging::debug_log("field_division"); + let _: Field = field_division(args_field[0_u32], args_field[1_u32]); + aztec::oracle::logging::debug_log("test_get_contract_instance"); + _test_get_contract_instance_matches(get_instance_for_address, expected_deployer, expected_class_id, expected_initialization_hash); + aztec::oracle::logging::debug_log("get_address"); + let _: AztecAddress = _get_address(self.address); + aztec::oracle::logging::debug_log("get_sender"); + let _: AztecAddress = _get_sender(self.context); + aztec::oracle::logging::debug_log("get_transaction_fee"); + let _: Field = _get_transaction_fee(self.context); + aztec::oracle::logging::debug_log("get_chain_id"); + let _: Field = _get_chain_id(self.context); + aztec::oracle::logging::debug_log("get_version"); + let _: Field = _get_version(self.context); + aztec::oracle::logging::debug_log("get_block_number"); + let _: u32 = _get_block_number(self.context); + aztec::oracle::logging::debug_log("get_timestamp"); + let _: u64 = _get_timestamp(self.context); + aztec::oracle::logging::debug_log("get_fee_per_l2_gas"); + let _: u128 = _get_fee_per_l2_gas(self.context); + aztec::oracle::logging::debug_log("get_fee_per_da_gas"); + let _: u128 = _get_fee_per_da_gas(self.context); + aztec::oracle::logging::debug_log("get_l2_gas_left"); + let _: u32 = _get_l2_gas_left(self.context); + aztec::oracle::logging::debug_log("get_da_gas_left"); + let _: u32 = _get_da_gas_left(self.context); + if !skip_strictly_limited_side_effects { + aztec::oracle::logging::debug_log("emit_public_log"); + _emit_public_log(self.context); + }; + aztec::oracle::logging::debug_log("note_hash_exists"); + let _: bool = _note_hash_exists(self.context, 1_Field, 2_u64); + aztec::oracle::logging::debug_log("new_note_hash"); + _new_note_hash(self.context, 1_Field); + aztec::oracle::logging::debug_log("new_nullifier"); + _new_nullifier(self.context, args_field[0_u32]); + aztec::oracle::logging::debug_log("nullifier_exists"); + let _: bool = _nullifier_exists(self.context, self.address, 1_Field); + aztec::oracle::logging::debug_log("l1_to_l2_msg_exists"); + let _: bool = _l1_to_l2_msg_exists(self.context, 1_Field, 2_Field); + if !skip_strictly_limited_side_effects { + aztec::oracle::logging::debug_log("send_l2_to_l1_msg"); + _send_l2_to_l1_msg(self.context, EthAddress::from_field(8224_Field), 1_Field); + }; + aztec::oracle::logging::debug_log("storage_read_and_write"); + _set_storage_single(self.storage, _read_storage_single(self.storage)); + aztec::oracle::logging::debug_log("nested_call_to_add"); + let _: Field = _nested_call_to_add(self.context, self.address, 1_Field, 2_Field); + aztec::oracle::logging::debug_log("nested_static_call_to_add"); + let _: Field = _nested_static_call_to_add(self.context, self.address, 1_Field, 2_Field); + aztec::oracle::logging::debug_log("nested_call_to_protocol_contract"); + _call_fee_juice(self.context, self.address); + aztec::oracle::logging::debug_log("to_le_bytes"); + let first_byte: u8 = _to_le_bytes(args_field[0_u32])[0_u32]; + assert(first_byte != 0_u8); + aztec::oracle::logging::debug_log("to_le_bits"); + let first_bit: bool = _to_le_bits(args_field[0_u32])[0_u32]; + assert(first_bit); + } + } + + unconstrained fn __aztec_nr_internals__call_auth_registry() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let _: bool = AuthRegistry::at(CANONICAL_AUTH_REGISTRY_ADDRESS).is_reject_all(self.address).view(self.context); + } + } + + unconstrained fn __aztec_nr_internals__call_fee_juice() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _call_fee_juice(self.context, self.address); + } + } + + unconstrained fn __aztec_nr_internals__call_instance_registry() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let _: u64 = self.view(ContractInstanceRegistry::at(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS).get_update_delay()); + } + } + + unconstrained fn __aztec_nr_internals__conditional_move(x: [Field; 1], y: [Field; 1], b: bool) -> pub [Field; 1] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (<[Field; 1] as Serialize>::N + <[Field; 1] as Serialize>::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + if b { + x + } else { + y + } + } + } + + unconstrained fn __aztec_nr_internals__create_different_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.context.push_nullifier(nullifier); + self.call(AvmTest::at(nestedAddress).new_nullifier(nullifier + 1_Field)); + } + } + + unconstrained fn __aztec_nr_internals__create_same_nullifier_in_nested_call(nestedAddress: AztecAddress, nullifier: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.context.push_nullifier(nullifier); + self.call(AvmTest::at(nestedAddress).new_nullifier(nullifier)); + } + } + + unconstrained fn __aztec_nr_internals__debug_logging() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + aztec::oracle::logging::debug_log("just text"); + aztec::oracle::logging::debug_log_format("second: {1}", [1_Field, 2_Field, 3_Field, 4_Field]); + aztec::oracle::logging::debug_log_format("whole array: {}", [1_Field, 2_Field, 3_Field, 4_Field]); + aztec::oracle::logging::debug_log("tabs and newlines\n\t- first\n\t- second"); + aztec::oracle::logging::fatal_log("fatal error"); + aztec::oracle::logging::trace_log_format("trace format: {}", [1_Field, 3_Field, 3_Field, 7_Field]); + } + } + + unconstrained fn __aztec_nr_internals__divide_by_zero(denominator: u8) -> pub u8 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + 1_u8 / denominator + } + } + + unconstrained fn __aztec_nr_internals__elliptic_curve_add(lhs: Point, rhs: Point) -> pub Point { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 6] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + lhs + rhs + } + } + + unconstrained fn __aztec_nr_internals__elliptic_curve_add_and_double() -> pub Point { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let g: Point = Point { x: GRUMPKIN_ONE_X, y: GRUMPKIN_ONE_Y, is_infinite: false}; + let doubled: Point = g + g; + let added: Point = g + doubled; + added + } + } + + unconstrained fn __aztec_nr_internals__emit_nullifier_and_check(nullifier: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.context.push_nullifier(nullifier); + let exists: bool = self.context.nullifier_exists_unsafe(nullifier, self.address); + assert(exists, "Nullifier was just created, but its existence wasn't detected!"); + } + } + + unconstrained fn __aztec_nr_internals__emit_public_log() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _emit_public_log(self.context); + } + } + + unconstrained fn __aztec_nr_internals__external_call_to_assertion_failure() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.call_self.assertion_failure(); + } + } + + unconstrained fn __aztec_nr_internals__external_call_to_divide_by_zero() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let _: u8 = self.call_self.divide_by_zero(0_u8); + } + } + + unconstrained fn __aztec_nr_internals__external_call_to_divide_by_zero_recovers() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let l2_gas_left: u32 = self.context.l2_gas_left(); + let da_gas_left: u32 = self.context.da_gas_left(); + let selector: FunctionSelector = FunctionSelector::from_signature("divide_by_zero(u8)"); + call(l2_gas_left - 200000_u32, da_gas_left - 200000_u32, self.address, [selector.to_field(), 0_Field]); + let success: bool = success_copy(); + assert(!success, "Nested CALL instruction should return failure on exceptional halt"); + assert(returndata_size() == 0_u32, "Returndata should be empty when nested call exceptionally halts"); + } + } + + unconstrained fn __aztec_nr_internals__fn_w_large_calldata(_arr: [Field; 300]) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 300 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 300] as Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + 5_Field + } + } + + unconstrained fn __aztec_nr_internals__get_address() -> pub AztecAddress { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_address(self.address) + } + } + + unconstrained fn __aztec_nr_internals__get_args_hash(_a: u8, _fields: [Field; 3]) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ::N + <[Field; 3] as Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.context.get_args_hash() + } + } + + unconstrained fn __aztec_nr_internals__get_block_number() -> pub u32 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_block_number(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_chain_id() -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_chain_id(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_da_gas_left() -> pub u32 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_da_gas_left(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_fee_per_da_gas() -> pub u128 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_fee_per_da_gas(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_fee_per_l2_gas() -> pub u128 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_fee_per_l2_gas(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_l2_gas_left() -> pub u32 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_l2_gas_left(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_sender() -> pub AztecAddress { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_sender(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_timestamp() -> pub u64 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_timestamp(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_transaction_fee() -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_transaction_fee(self.context) + } + } + + unconstrained fn __aztec_nr_internals__get_version() -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _get_version(self.context) + } + } + + unconstrained fn __aztec_nr_internals__l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> pub bool { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _l1_to_l2_msg_exists(self.context, msg_hash, msg_leaf_index) + } + } + + unconstrained fn __aztec_nr_internals__modulo2(a: u64) -> pub u64 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + a % 2_u64 + } + } + + unconstrained fn __aztec_nr_internals__n_new_l2_to_l1_msgs(num: u32) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + for i in 0_u32..num { + self.context.message_portal(EthAddress::from_field(i as Field), i as Field) + } + } + } + + unconstrained fn __aztec_nr_internals__n_new_note_hashes(num: u32) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + for i in 0_u32..num { + self.context.push_note_hash(i as Field); + } + } + } + + unconstrained fn __aztec_nr_internals__n_new_nullifiers(num: u32) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + for i in 0_u32..num { + self.context.push_nullifier(i as Field); + } + } + } + + unconstrained fn __aztec_nr_internals__n_new_public_logs(num: u32) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + for i in 0_u32..num { + self.context.emit_public_log_unsafe(0_Field, [i as Field]); + } + } + } + + unconstrained fn __aztec_nr_internals__n_storage_writes(num: u32) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + for i in 0_u32..num { + self.storage.map.at(AztecAddress::from_field(i as Field)).write(i); + } + } + } + + unconstrained fn __aztec_nr_internals__nested_call_large_calldata(arr: [Field; 300]) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 300 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[Field; 300] as Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.call_self.fn_w_large_calldata(arr) + } + } + + unconstrained fn __aztec_nr_internals__nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _nested_call_to_add(self.context, self.address, arg_a, arg_b) + } + } + + unconstrained fn __aztec_nr_internals__nested_call_to_add_n_times_different_addresses(addrs: [AztecAddress; 23]) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 23 * 1] = aztec::oracle::avm::calldata_copy(1_u32, <[AztecAddress; 23] as Serialize>::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + for i in 0_u32..MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS + 2_u32 { + let addr: AztecAddress = addrs[i]; + if addr != AztecAddress::empty() { + let _: Field = self.call(AvmTest::at(addr).add_args_return(1_Field, 2_Field)); + } + } + } + } + + unconstrained fn __aztec_nr_internals__nested_call_to_add_with_gas(arg_a: Field, arg_b: Field, l2_gas: u32, da_gas: u32) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.call(AvmTest::at(self.address).add_args_return(arg_a, arg_b).with_gas(GasOpts::new(l2_gas, da_gas))) + } + } + + unconstrained fn __aztec_nr_internals__nested_call_to_assert_same(arg_a: Field, arg_b: Field) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.call_self.assert_same(arg_a, arg_b) + } + } + + unconstrained fn __aztec_nr_internals__nested_call_to_nothing() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let garbageAddress: AztecAddress = AztecAddress::from_field(42_Field); + self.call(AvmTest::at(garbageAddress).nested_call_to_nothing()) + } + } + + unconstrained fn __aztec_nr_internals__nested_call_to_nothing_recovers() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let garbageAddress: AztecAddress = AztecAddress::from_field(42_Field); + call(1_u32, 1_u32, garbageAddress, []); + let success: bool = success_copy(); + assert(!success, "Nested CALL instruction should return failure if target contract does not exist"); + } + } + + unconstrained fn __aztec_nr_internals__nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _nested_static_call_to_add(self.context, self.address, arg_a, arg_b) + } + } + + unconstrained fn __aztec_nr_internals__nested_static_call_to_set_storage() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let selector: FunctionSelector = FunctionSelector { inner: 2230419055_u32}; + let args: [Field; 1] = [20_Field as Field]; + let _: [Field] = self.context.static_call_public_function(self.address, selector, args, GasOpts::default()); + } + } + + unconstrained fn __aztec_nr_internals__new_note_hash(note_hash: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _new_note_hash(self.context, note_hash); + } + } + + unconstrained fn __aztec_nr_internals__new_nullifier(nullifier: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _new_nullifier(self.context, nullifier); + } + } + + unconstrained fn __aztec_nr_internals__note_hash_exists(note_hash: Field, leaf_index: u64) -> pub bool { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _note_hash_exists(self.context, note_hash, leaf_index) + } + } + + unconstrained fn __aztec_nr_internals__nullifier_collision(nullifier: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.context.push_nullifier(nullifier); + self.context.push_nullifier(nullifier); + } + } + + unconstrained fn __aztec_nr_internals__nullifier_exists(nullifier: Field) -> pub bool { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _nullifier_exists(self.context, self.address, nullifier) + } + } + + unconstrained fn __aztec_nr_internals__pedersen_commit(x: Field, y: Field) -> pub Point { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let commitment: std::embedded_curve_ops::EmbeddedCurvePoint = std::hash::pedersen_commitment_with_separator([x, y], 20_u32); + commitment.into() + } + } + + unconstrained fn __aztec_nr_internals__raw_l2_to_l1_msg(recipient: EthAddress, content: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.context.message_portal(recipient, content) + } + } + + unconstrained fn __aztec_nr_internals__read_assert_storage_single(a: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + assert(a == self.storage.single.read(), "Storage value does not match input"); + } + } + + unconstrained fn __aztec_nr_internals__read_storage_list() -> pub [Field; 2] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _read_storage_list(self.storage) + } + } + + unconstrained fn __aztec_nr_internals__read_storage_map(address: AztecAddress) -> pub u32 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _read_storage_map(self.storage, address) + } + } + + unconstrained fn __aztec_nr_internals__read_storage_single() -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _read_storage_single(self.storage) + } + } + + unconstrained fn __aztec_nr_internals__return_oracle() -> pub [Field; 3] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + avm_return([1_Field, 2_Field, 3_Field].as_slice()); + [4_Field, 5_Field, 6_Field] + } + } + + unconstrained fn __aztec_nr_internals__returndata_copy_oracle() { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let _: [Field; 3] = self.call_self.return_oracle(); + let returndatasize: u32 = returndata_size(); + let returndata: [Field] = returndata_copy(0_u32, returndatasize); + assert(returndata == @[1_Field, 2_Field, 3_Field], "Returndata copy failed"); + } + } + + unconstrained fn __aztec_nr_internals__revert_oracle() -> pub [Field; 3] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + revert([1_Field, 2_Field, 3_Field].as_slice()); + [4_Field, 5_Field, 6_Field] + } + } + + unconstrained fn __aztec_nr_internals__send_l2_to_l1_msg(recipient: EthAddress, content: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _send_l2_to_l1_msg(self.context, recipient, content); + } + } + + unconstrained fn __aztec_nr_internals__set_opcode_big_field() -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + big_field_136_bits + } + } + + unconstrained fn __aztec_nr_internals__set_opcode_really_big_field() -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + big_field_254_bits + } + } + + unconstrained fn __aztec_nr_internals__set_opcode_small_field() -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + big_field_128_bits + } + } + + unconstrained fn __aztec_nr_internals__set_opcode_u32() -> pub u32 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + 1_u32 << 30_u32 + } + } + + unconstrained fn __aztec_nr_internals__set_opcode_u64() -> pub u64 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + 1_u64 << 60_u64 + } + } + + unconstrained fn __aztec_nr_internals__set_opcode_u8() -> pub u8 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + 8_u8 + } + } + + unconstrained fn __aztec_nr_internals__set_opcode_u8_view() -> pub u8 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.context.is_static_call(), "Function set_opcode_u8_view can only be called statically"); + { + 8_u8 + } + } + + unconstrained fn __aztec_nr_internals__set_read_storage_single(a: Field) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + self.storage.single.write(a); + self.storage.single.read() + } + } + + unconstrained fn __aztec_nr_internals__set_storage_list(a: Field, b: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _set_storage_list(self.storage, a, b); + } + } + + unconstrained fn __aztec_nr_internals__set_storage_map(to: AztecAddress, amount: u32) -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _set_storage_map(self.storage, to, amount) + } + } + + unconstrained fn __aztec_nr_internals__set_storage_single(a: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _set_storage_single(self.storage, a); + } + } + + unconstrained fn __aztec_nr_internals__test_get_contract_instance(address: AztecAddress) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let deployer: Option = get_contract_instance_deployer_avm(address); + let class_id: Option = get_contract_instance_class_id_avm(address); + let initialization_hash: Option = get_contract_instance_initialization_hash_avm(address); + assert(deployer.is_some(), "Contract instance not found when getting DEPLOYER!"); + assert(class_id.is_some(), "Contract instance not found when getting CLASS_ID!"); + assert(initialization_hash.is_some(), "Contract instance not found when getting INIT_HASH!"); + assert(deployer.unwrap().eq(AztecAddress::from_field(1110_Field))); + assert(class_id.unwrap().eq(ContractClassId::from_field(1929_Field))); + assert(initialization_hash.unwrap() == 1052946_Field); + } + } + + unconstrained fn __aztec_nr_internals__test_get_contract_instance_matches(address: AztecAddress, expected_deployer: AztecAddress, expected_class_id: ContractClassId, expected_initialization_hash: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _test_get_contract_instance_matches(address, expected_deployer, expected_class_id, expected_initialization_hash); + } + } + + unconstrained fn __aztec_nr_internals__to_le_bits(input: Field) -> pub [bool; 16] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _to_le_bits(input) + } + } + + unconstrained fn __aztec_nr_internals__to_le_bytes(input: Field) -> pub [u8; 10] { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + _to_le_bytes(input) + } + } + + unconstrained fn __aztec_nr_internals__u128_addition_overflow() -> pub u128 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let max_u128: u128 = 340282366920938463463374607431768211455_u128; + let one: u128 = 1_u128; + max_u128 + one + } + } + + unconstrained fn __aztec_nr_internals__variable_base_msm(scalar_lo: Field, scalar_hi: Field, scalar2_lo: Field, scalar2_hi: Field) -> pub Point { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: PublicContext = PublicContext::new(|| -> Field { + let serialized_args: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let g: Point = Point { x: GRUMPKIN_ONE_X, y: GRUMPKIN_ONE_Y, is_infinite: false}; + let triple_g: std::embedded_curve_ops::EmbeddedCurvePoint = multi_scalar_mul([g.to_embedded(), g.to_embedded()], [Scalar { lo: scalar_lo, hi: scalar_hi}, Scalar { lo: scalar2_lo, hi: scalar2_hi}]); + triple_g.into() + } + } + + pub struct StorageLayoutFields { + pub single: aztec::state_vars::Storable, + pub list: aztec::state_vars::Storable, + pub map: aztec::state_vars::Storable, + } + + pub struct StorageLayout { + pub contract_name: str, + pub fields: StorageLayoutFields, + } +} + +mod note { + use std::meta::derive; + use aztec::protocol::traits::Deserialize; + use aztec::protocol::traits::Packable; + use aztec::protocol::traits::Serialize; + + pub struct Note { + pub a: Field, + pub b: Field, + } + + impl Packable for Note { + let N: u32 = 2; + + #[inline_always] + fn pack(self) -> [Field; 2] { + let mut result: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let packed_member: [Field; 1] = self.a.pack(); + let packed_member_len: u32 = ::N; + for i in 0_u32..packed_member_len { + { + let i_0: u32 = i + offset; + result[i_0] = packed_member[i]; + } + }; + offset = offset + packed_member_len; + let packed_member: [Field; 1] = self.b.pack(); + let packed_member_len: u32 = ::N; + for i in 0_u32..packed_member_len { + { + let i_1: u32 = i + offset; + result[i_1] = packed_member[i]; + } + }; + offset = offset + packed_member_len; + result + } + + #[inline_always] + fn unpack(packed: [Field; 2]) -> Self { + let mut offset: u32 = 0_u32; + let mut member_fields: [Field; 1] = [0_Field; 1]; + for i in 0_u32..::N { + member_fields[i] = packed[i + offset]; + }; + let a: Field = ::unpack(member_fields); + offset = offset + ::N; + let mut member_fields: [Field; 1] = [0_Field; 1]; + for i in 0_u32..::N { + member_fields[i] = packed[i + offset]; + }; + let b: Field = ::unpack(member_fields); + offset = offset + ::N; + Self { a: a, b: b} + } + } + + impl Serialize for Note { + let N: u32 = 2; + + fn serialize(self) -> [Field; 2] { + let mut writer: aztec::protocol::utils::writer::Writer<2> = aztec::protocol::utils::writer::Writer::<2>::new(); + self.stream_serialize(&mut writer); + writer.finish() + } + + #[inline_always] + fn stream_serialize(self, writer: &mut aztec::protocol::utils::writer::Writer) { + self.a.stream_serialize(writer); + self.b.stream_serialize(writer); + } + } + + impl Deserialize for Note { + let N: u32 = 2; + + fn deserialize(fields: [Field; 2]) -> Self { + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(fields); + let result: Self = Self::stream_deserialize(&mut reader); + reader.finish(); + result + } + + #[inline_always] + fn stream_deserialize(reader: &mut aztec::protocol::utils::reader::Reader) -> Self { + let a: Field = ::stream_deserialize(reader); + let b: Field = ::stream_deserialize(reader); + Self { a: a, b: b} + } + } +} + +// Warning: the generated code has syntax errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap new file mode 100644 index 000000000000..0bb78f0095c8 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap @@ -0,0 +1,2146 @@ +--- +source: tests/snapshots.rs +expression: stdout +--- +use aztec::macros::aztec; +use aztec::macros::aztec; + +contract StorageProofTest { + use crate::storage_proofs::account_hash::compute_account_hash; + use crate::storage_proofs::keccak::keccak256; + use crate::storage_proofs::keccak::KeccakHasher; + use crate::storage_proofs::path_verification::verify_path_section; + use crate::storage_proofs::slot_hash::compute_slot_hash; + use crate::storage_proofs::types::Account; + use crate::storage_proofs::types::Node; + use crate::storage_proofs::types::StorageSlot; + use crate::storage_proofs::utils::to_nibbles; + use aztec::context::calls::PrivateCall; + use aztec::macros::functions::external; + use aztec::macros::functions::internal; + use aztec::macros::functions::only_self; + use aztec::macros::functions::view; + use aztec::oracle::capsules; + use aztec::protocol::address::AztecAddress; + use aztec::protocol::address::EthAddress; + use aztec::protocol::hash::poseidon2_hash; + use aztec::protocol::traits::Deserialize; + use aztec::protocol::traits::Serialize; + use aztec::protocol::traits::ToField; + + global MAX_ACCOUNT_PROOF_LENGTH: u32 = 15; + + global NUM_NODES_VERIFIED_PER_CALL: u32 = 3; + + global ACCOUNT_CAPSULE_KEY_SEPARATOR: u32 = 100; + + global ACCOUNT_PROOF_CAPSULE_KEY_SEPARATOR: u32 = 101; + + global STORAGE_PROOF_CAPSULE_KEY_SEPARATOR: u32 = 102; + + global STORAGE_PROOF_NODE_CAPSULE_KEY_SEPARATOR: u32 = 103; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call account_proof. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn account_proof(account: Account, root: [u64; 4], nodes: [Node; 15], node_length: u32); + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call storage_proof. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn storage_proof(address: EthAddress, slot_key: [u8; 32], slot_contents: StorageSlot, eth_storage_root: [u64; 4]); + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call verify_storage_proof_path_recursively. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn verify_storage_proof_path_recursively(num_processed_nodes: u32, num_total_nodes: u32, start_nibble_index: u32, parent_hash: [u64; 4], storage_trie_key_nibbles: [u8; 64], storage_proof_capsule_key: Field) -> ([u64; 4], u32); + + #[no_predicates] + #[contract_library_method] + fn call_verify_storage_proof_path_recursively(this_address: AztecAddress, num_processed_nodes: u32, num_total_nodes: u32, start_nibble_index: u32, parent_hash: [u64; 4], storage_trie_key_nibbles: [u8; 64], storage_proof_capsule_key: Field) -> PrivateCall<37, 72, ([u64; 4], u32)> { + StorageProofTest::at(this_address).verify_storage_proof_path_recursively(num_processed_nodes, num_total_nodes, start_nibble_index, parent_hash, storage_trie_key_nibbles, storage_proof_capsule_key) + } + + #[contract_library_method] + fn compute_address_capsule_key(eth_storage_root: [u64; 4], address: EthAddress) -> Field { + poseidon2_hash((ACCOUNT_CAPSULE_KEY_SEPARATOR, eth_storage_root, address).serialize()) + } + + #[contract_library_method] + fn compute_account_proof_capsule_key(address_capsule_key: Field) -> Field { + poseidon2_hash((ACCOUNT_PROOF_CAPSULE_KEY_SEPARATOR, address_capsule_key).serialize()) + } + + #[contract_library_method] + fn compute_storage_proof_capsule_key(address_capsule_key: Field, slot_key: [u8; 32]) -> Field { + poseidon2_hash((STORAGE_PROOF_CAPSULE_KEY_SEPARATOR, address_capsule_key, slot_key).serialize()) + } + + #[contract_library_method] + fn compute_node_capsule_key(storage_proof_capsule_key: Field, index: u32) -> Field { + poseidon2_hash((STORAGE_PROOF_NODE_CAPSULE_KEY_SEPARATOR, storage_proof_capsule_key, index).serialize()) + } + + /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + #[allow(dead_code)] + unconstrained fn _compute_note_hash_and_nullifier(packed_note: BoundedVec, owner: AztecAddress, storage_slot: Field, note_type_id: Field, contract_address: AztecAddress, randomness: Field, note_nonce: Field) -> Option { + _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash: Field| -> aztec::messages::discovery::NoteHashAndNullifier { + let siloed_note_hash: Field = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash); + let unique_note_hash: Field = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash); + let inner_nullifier: Option = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness); + aztec::messages::discovery::NoteHashAndNullifier { note_hash: note_hash, inner_nullifier: inner_nullifier} + }) + } + + /// This contract does not use private notes, so this function should never be called as it will unconditionally fail. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_hash(_packed_note: BoundedVec, _owner: AztecAddress, _storage_slot: Field, _note_type_id: Field, _contract_address: AztecAddress, _randomness: Field) -> Option { + panic(f"This contract does not use private notes") + } + + /// This contract does not use private notes, so this function should never be called as it will unconditionally fail. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_nullifier(_unique_note_hash: Field, _packed_note: BoundedVec, _owner: AztecAddress, _storage_slot: Field, _note_type_id: Field, _contract_address: AztecAddress, _randomness: Field) -> Option { + panic(f"This contract does not use private notes") + } + + /// Receives offchain messages into this contract's offchain inbox for subsequent processing. + /// + /// Each message is routed to the inbox scoped to its `recipient` field. + /// + /// For more details, see `aztec::messages::processing::offchain::receive`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + unconstrained fn offchain_receive(messages: BoundedVec) { + let address: AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::processing::offchain::receive(address, messages); + } + + pub struct StorageProofTest { + pub target_contract: AztecAddress, + } + + impl StorageProofTest { + pub fn at(addr: AztecAddress) -> Self { + Self { target_contract: addr} + } + + pub fn interface() -> Self { + Self { target_contract: AztecAddress::zero()} + } + + pub fn verify_storage_proof_path_recursively(self, num_processed_nodes: u32, num_total_nodes: u32, start_nibble_index: u32, parent_hash: [u64; 4], storage_trie_key_nibbles: [u8; 64], storage_proof_capsule_key: Field) -> PrivateCall<37, 72, ([u64; 4], u32)> { + let mut serialized_params: [Field; 72] = [0_Field; 72]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = num_processed_nodes.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = num_total_nodes.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = start_nibble_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = parent_hash.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 64 * 1] = storage_trie_key_nibbles.serialize(); + let serialized_member_len: u32 = <[u8; 64] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = storage_proof_capsule_key.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2237949917_Field); + PrivateCall::<37, 72, ([u64; 4], u32)>::new(self.target_contract, selector, "verify_storage_proof_path_recursively", serialized_params) + } + + pub fn storage_proof(self, address: EthAddress, slot_key: [u8; 32], slot_contents: StorageSlot, eth_storage_root: [u64; 4]) -> PrivateCall<13, 70, ()> { + let mut serialized_params: [Field; 70] = [0_Field; 70]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 32 * 1] = slot_key.serialize(); + let serialized_member_len: u32 = <[u8; 32] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 33] = slot_contents.serialize(); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = eth_storage_root.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2067008734_Field); + PrivateCall::<13, 70, ()>::new(self.target_contract, selector, "storage_proof", serialized_params) + } + + pub fn account_proof(self, account: Account, root: [u64; 4], nodes: [Node; 15], node_length: u32) -> aztec::context::calls::PublicStaticCall<13, 1290, ()> { + let mut serialized_params: [Field; 1290] = [0_Field; 1290]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 70] = account.serialize(); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = root.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 15 * 81] = nodes.serialize(); + let serialized_member_len: u32 = <[Node; 15] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = node_length.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(693284113_Field); + aztec::context::calls::PublicStaticCall::<13, 1290, ()>::new(self.target_contract, selector, "account_proof", serialized_params) + } + + pub fn offchain_receive(self, messages: BoundedVec) -> aztec::context::calls::UtilityCall<16, 321, ()> { + let serialized_params: [Field; 321] = messages.serialize(); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1396850735_Field); + aztec::context::calls::UtilityCall::<16, 321, ()>::new(self.target_contract, selector, "offchain_receive", serialized_params) + } + } + + #[contract_library_method] + pub fn at(addr: AztecAddress) -> StorageProofTest { + StorageProofTest { target_contract: addr} + } + + #[contract_library_method] + pub fn interface() -> StorageProofTest { + StorageProofTest { target_contract: AztecAddress::zero()} + } + + pub struct sync_state_parameters { + pub scope: AztecAddress, + } + + #[abi(functions)] + pub struct sync_state_abi { + parameters: sync_state_parameters, + } + + unconstrained fn sync_state(scope: AztecAddress) { + let address: AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::discovery::do_sync_state(address, _compute_note_hash, _compute_note_nullifier, Option::>::none(), Option:: aztec::ephemeral::EphemeralArray>::some(aztec::messages::processing::offchain::sync_inbox), scope); + } + + pub struct offchain_receive_parameters { + pub messages: BoundedVec, + } + + #[abi(functions)] + pub struct offchain_receive_abi { + parameters: offchain_receive_parameters, + } + + pub struct CallSelf { + pub address: AztecAddress, + pub context: Context, + } + + impl CallSelf<&mut aztec::context::PrivateContext> { + pub fn storage_proof(self, address: EthAddress, slot_key: [u8; 32], slot_contents: StorageSlot, eth_storage_root: [u64; 4]) { + let mut serialized_params: [Field; 70] = [0_Field; 70]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 32 * 1] = slot_key.serialize(); + let serialized_member_len: u32 = <[u8; 32] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 33] = slot_contents.serialize(); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = eth_storage_root.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2067008734_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn verify_storage_proof_path_recursively(self, num_processed_nodes: u32, num_total_nodes: u32, start_nibble_index: u32, parent_hash: [u64; 4], storage_trie_key_nibbles: [u8; 64], storage_proof_capsule_key: Field) -> ([u64; 4], u32) { + let mut serialized_params: [Field; 72] = [0_Field; 72]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = num_processed_nodes.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = num_total_nodes.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = start_nibble_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = parent_hash.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 64 * 1] = storage_trie_key_nibbles.serialize(); + let serialized_member_len: u32 = <[u8; 64] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = storage_proof_capsule_key.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2237949917_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + } + + pub struct CallSelfStatic { + pub address: AztecAddress, + pub context: Context, + } + + impl CallSelfStatic { + pub fn account_proof(self, account: Account, root: [u64; 4], nodes: [Node; 15], node_length: u32) { + let mut serialized_params: [Field; 1290] = [0_Field; 1290]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 70] = account.serialize(); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = root.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 15 * 81] = nodes.serialize(); + let serialized_member_len: u32 = <[Node; 15] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = node_length.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(693284113_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<13, 1290, ()>::new(self.address, selector, "account_proof", serialized_params).view(self.context) + } + } + } + + pub struct EnqueueSelf { + pub address: AztecAddress, + pub context: Context, + } + + pub struct EnqueueSelfStatic { + pub address: AztecAddress, + pub context: Context, + } + + impl EnqueueSelfStatic<&mut aztec::context::PrivateContext> { + pub fn account_proof(self, account: Account, root: [u64; 4], nodes: [Node; 15], node_length: u32) { + let mut serialized_params: [Field; 1290] = [0_Field; 1290]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 70] = account.serialize(); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = root.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 15 * 81] = nodes.serialize(); + let serialized_member_len: u32 = <[Node; 15] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = node_length.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(693284113_Field); + let calldata: [Field; 1 + 1290] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + } + + pub struct CallSelfUtility { + pub address: AztecAddress, + } + + pub struct CallInternal { + pub context: Context, + } + + pub unconstrained fn public_dispatch(selector: Field) { + if selector == 693284113_Field { + let input_calldata: [Field; 1290] = aztec::oracle::avm::calldata_copy(1_u32, ((>::N + <[u64; 4] as Serialize>::N) + <[Node; 15] as Serialize>::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1290> = aztec::protocol::utils::reader::Reader::<1290>::new(input_calldata); + let arg0: Account = >::stream_deserialize(&mut reader); + let arg1: [u64; 4] = <[u64; 4] as Deserialize>::stream_deserialize(&mut reader); + let arg2: [Node; 15] = <[Node; 15] as Deserialize>::stream_deserialize(&mut reader); + let arg3: u32 = ::stream_deserialize(&mut reader); + __aztec_nr_internals__account_proof(arg0, arg1, arg2, arg3); + aztec::oracle::avm::avm_return([].as_slice()); + }; + panic(f"Unknown selector {selector}") + } + + pub struct account_proof_parameters { + pub account: Account, + pub root: [u64; 4], + pub nodes: [Node; 15], + pub node_length: u32, + } + + pub struct storage_proof_parameters { + pub address: EthAddress, + pub slot_key: [u8; 32], + pub slot_contents: StorageSlot, + pub eth_storage_root: [u64; 4], + } + + pub struct verify_storage_proof_path_recursively_parameters { + pub num_processed_nodes: u32, + pub num_total_nodes: u32, + pub start_nibble_index: u32, + pub parent_hash: [u64; 4], + pub storage_trie_key_nibbles: [u8; 64], + pub storage_proof_capsule_key: Field, + } + + #[abi(functions)] + pub struct account_proof_abi { + parameters: account_proof_parameters, + } + + #[abi(functions)] + pub struct storage_proof_abi { + parameters: storage_proof_parameters, + } + + #[abi(functions)] + pub struct verify_storage_proof_path_recursively_abi { + parameters: verify_storage_proof_path_recursively_parameters, + return_type: ([u64; 4], u32), + } + + fn __aztec_nr_internals__storage_proof(inputs: aztec::context::inputs::PrivateContextInputs, address: EthAddress, slot_key: [u8; 32], slot_contents: StorageSlot, eth_storage_root: [u64; 4]) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate<(), CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 70] = [0_Field; 70]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = address.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 32 * 1] = slot_key.serialize(); + let serialized_member_len: u32 = <[u8; 32] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 33] = slot_contents.serialize(); + let serialized_member_len: u32 = >::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = eth_storage_root.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash); + let storage: () = (); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut aztec::context::PrivateContext> = CallSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut aztec::context::PrivateContext> = EnqueueSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal::<&mut aztec::context::PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::<(), CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + let address_capsule_key: Field = compute_address_capsule_key(eth_storage_root, address); + // Safety: comment added by `nargo expand` + let hinted_account: Account = unsafe { + Account::deserialize(capsules::load(self.address, address_capsule_key, AztecAddress::zero()).unwrap()) + }; + assert(hinted_account.address == address.to_field().to_be_bytes::<20>()); + let account_proof_capsule_key: Field = compute_account_proof_capsule_key(address_capsule_key); + // Safety: comment added by `nargo expand` + let (hinted_account_proof_length, hinted_nodes): (u32, [Node; 15]) = unsafe { + <(u32, [Node; 15]) as Deserialize>::deserialize(capsules::load(self.address, account_proof_capsule_key, AztecAddress::zero()).unwrap()) + }; + self.enqueue_self_static.account_proof(hinted_account, eth_storage_root, hinted_nodes, hinted_account_proof_length); + let storage_proof_capsule_key: Field = compute_storage_proof_capsule_key(address_capsule_key, slot_key); + // Safety: comment added by `nargo expand` + let hinted_storage_proof_length: u32 = unsafe { + u32::deserialize(capsules::load(self.address, storage_proof_capsule_key, AztecAddress::zero()).unwrap()) + }; + assert(hinted_storage_proof_length > 0_u32, "Storage proof length must be greater than 0"); + let storage_trie_key: [u8; 32] = keccak256(slot_key, 32_u32); + let (slot_leaf_hash, slot_nibble_index): ([u64; 4], u32) = call_verify_storage_proof_path_recursively(self.address, 0_u32, hinted_storage_proof_length, 0_u32, hinted_account.storage_hash, to_nibbles(storage_trie_key), storage_proof_capsule_key).call(self.context); + assert(slot_leaf_hash == compute_slot_hash(slot_contents, slot_nibble_index, storage_trie_key)); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__verify_storage_proof_path_recursively(inputs: aztec::context::inputs::PrivateContextInputs, num_processed_nodes: u32, num_total_nodes: u32, start_nibble_index: u32, parent_hash: [u64; 4], storage_trie_key_nibbles: [u8; 64], storage_proof_capsule_key: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate<(), CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 72] = [0_Field; 72]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = num_processed_nodes.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = num_total_nodes.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = start_nibble_index.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 4 * 1] = parent_hash.serialize(); + let serialized_member_len: u32 = <[u64; 4] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 64 * 1] = storage_trie_key_nibbles.serialize(); + let serialized_member_len: u32 = <[u8; 64] as Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_4: u32 = i + offset; + serialized_params[i_4] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = storage_proof_capsule_key.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_5: u32 = i + offset; + serialized_params[i_5] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash); + let storage: () = (); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut aztec::context::PrivateContext> = CallSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut aztec::context::PrivateContext> = EnqueueSelf::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut aztec::context::PrivateContext> = CallSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut aztec::context::PrivateContext> = EnqueueSelfStatic::<&mut aztec::context::PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut aztec::context::PrivateContext> = CallInternal::<&mut aztec::context::PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::<(), CallSelf<&mut aztec::context::PrivateContext>, EnqueueSelf<&mut aztec::context::PrivateContext>, CallSelfStatic<&mut aztec::context::PrivateContext>, EnqueueSelfStatic<&mut aztec::context::PrivateContext>, CallInternal<&mut aztec::context::PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + assert(self.msg_sender() == self.address, "Function verify_storage_proof_path_recursively can only be called by the same contract"); + let mut hinted_nodes: [Node; 3] = std::mem::zeroed(); + let num_nodes_remaining: u32 = num_total_nodes - num_processed_nodes; + let num_nodes_to_process: u32 = if num_nodes_remaining > NUM_NODES_VERIFIED_PER_CALL { + NUM_NODES_VERIFIED_PER_CALL + } else { + num_nodes_remaining + }; + for i in 0_u32..NUM_NODES_VERIFIED_PER_CALL { + let node_capsule_key: Field = compute_node_capsule_key(storage_proof_capsule_key, num_processed_nodes + i); + if i < num_nodes_to_process { + // Safety: comment added by `nargo expand` + hinted_nodes[i] = unsafe { + Node::deserialize(capsules::load(self.address, node_capsule_key, AztecAddress::zero()).unwrap()) + }; + } + }; + let (child_hash, end_nibble_index): ([u64; 4], u32) = verify_path_section(hinted_nodes, num_nodes_to_process, start_nibble_index, parent_hash, storage_trie_key_nibbles); + let new_num_processed_nodes: u32 = num_processed_nodes + num_nodes_to_process; + let macro__returned__values: ([u64; 4], u32) = if new_num_processed_nodes == num_total_nodes { + (child_hash, end_nibble_index) + } else { + call_verify_storage_proof_path_recursively(self.address, new_num_processed_nodes, num_total_nodes, end_nibble_index, child_hash, storage_trie_key_nibbles, storage_proof_capsule_key).call(self.context) + }; + let serialized_params: [Field; (4 * 1) + 1] = macro__returned__values.serialize(); + self.context.set_return_hash(serialized_params); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + unconstrained fn __aztec_nr_internals__account_proof(account: Account, root: [u64; 4], nodes: [Node; 15], node_length: u32) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic<(), CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1290] = aztec::oracle::avm::calldata_copy(1_u32, ((>::N + <[u64; 4] as Serialize>::N) + <[Node; 15] as Serialize>::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: () = (); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::<(), CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.context.is_static_call(), "Function account_proof can only be called statically"); + { + let trie_key: [u8; 32] = KeccakHasher::hash_bytes(account.address, 20_u32); + let (leaf_hash, new_index): ([u64; 4], u32) = verify_path_section(nodes, node_length, 0_u32, root, to_nibbles(trie_key)); + assert(leaf_hash == compute_account_hash(account, new_index, trie_key)); + } + } +} + +mod storage_proofs { + pub mod account_hash { + use super::bytes_sink::BytesChecker; + use super::bytes_sink::BytesSink; + use super::bytes_sink::BytesWriter; + use super::keccak::keccak256_limbs; + use super::keccak::KeccakHasher; + use super::types::Account; + use super::utils::get_low_nibble; + use super::utils::get_rlp_length; + use super::utils::runtime_loop; + use super::utils::unroll_loop; + + global ACCOUNT_RLP_MAX_LENGTH: u32 = 147; + + #[inline_always] + fn rlp_encode_to_sink(account: Account, start_nibble_idx: u32, trie_key: [u8; 32], sink: &mut S) where S: BytesSink { + let mut current_nibble_idx: u32 = start_nibble_idx; + let first_key_byte: u8 = if (current_nibble_idx % 2_u32) == 0_u32 { + 32_u8 + } else { + let first_byte: u8 = trie_key[(current_nibble_idx / 2_u32) as u32]; + current_nibble_idx = current_nibble_idx + 1_u32; + 48_u8 + get_low_nibble(first_byte) + }; + let key_length: u8 = (32_u8 - ((current_nibble_idx as u8) / 2_u8)) + 1_u8; + let leaf_key_rlp_length: u8 = get_rlp_length(first_key_byte, key_length); + assert(account.nonce_length <= 8_u8); + let leaf_value_rlp_data_length: u8 = ((get_rlp_length(account.balance[0_u32], account.balance_length) + get_rlp_length(account.nonce[0_u32], account.nonce_length)) + 33_u8) + 33_u8; + let leaf_rlp_total_length: u8 = ((leaf_key_rlp_length + leaf_value_rlp_data_length) + 2_u8) + 2_u8; + sink.add_byte(248_u8); + sink.add_byte(leaf_rlp_total_length); + if (key_length == 1_u8) & (first_key_byte <= 127_u8) { + sink.add_byte(first_key_byte); + } else { + sink.add_byte(128_u8 + key_length); + sink.add_byte(first_key_byte); + let start_byte_idx: u32 = current_nibble_idx / 2_u32; + let end_byte_idx: u32 = start_byte_idx + ((key_length - 1_u8) as u32); + { + assert(start_byte_idx <= end_byte_idx); + assert(end_byte_idx <= trie_key.len()); + if std::runtime::is_unconstrained() { + for i in start_byte_idx..end_byte_idx { + sink.add_byte(trie_key[i]); + () + } + } else { + for i in 0_u32..trie_key.len() { + if (i >= start_byte_idx) & (i < end_byte_idx) { + sink.add_byte(trie_key[i]); + () + } + } + } + }; + }; + sink.add_byte(184_u8); + sink.add_byte(leaf_value_rlp_data_length + 2_u8); + sink.add_byte(248_u8); + sink.add_byte(leaf_value_rlp_data_length); + if account.nonce_length == 0_u8 { + sink.add_byte(128_u8); + } else if (account.nonce_length == 1_u8) & (account.nonce[0_u32] <= 127_u8) { + sink.add_byte(account.nonce[0_u32]); + } else { + sink.add_byte(128_u8 + account.nonce_length); + { + assert(0_u32 <= (account.nonce_length as u32)); + assert((account.nonce_length as u32) <= 32_u32); + if std::runtime::is_unconstrained() { + for i in 0_u32..account.nonce_length as u32 { + sink.add_byte(account.nonce[i]); + () + } + } else { + for i in 0_u32..32_u32 { + if (i >= 0_u32) & (i < (account.nonce_length as u32)) { + sink.add_byte(account.nonce[i]); + () + } + } + } + }; + }; + if account.balance_length == 0_u8 { + sink.add_byte(128_u8); + } else if (account.balance_length == 1_u8) & (account.balance[0_u32] <= 127_u8) { + sink.add_byte(account.balance[0_u32]); + } else { + sink.add_byte(128_u8 + account.balance_length); + { + assert(0_u32 <= (account.balance_length as u32)); + assert((account.balance_length as u32) <= 32_u32); + if std::runtime::is_unconstrained() { + for i in 0_u32..account.balance_length as u32 { + sink.add_byte(account.balance[i]); + () + } + } else { + for i in 0_u32..32_u32 { + if (i >= 0_u32) & (i < (account.balance_length as u32)) { + sink.add_byte(account.balance[i]); + () + } + } + } + }; + }; + sink.add_byte(160_u8); + { + sink.add_u64(account.storage_hash[0_u32]); + sink.add_u64(account.storage_hash[1_u32]); + sink.add_u64(account.storage_hash[2_u32]); + sink.add_u64(account.storage_hash[3_u32]); + }; + sink.add_byte(160_u8); + { + sink.add_u64(account.code_hash[0_u32]); + sink.add_u64(account.code_hash[1_u32]); + sink.add_u64(account.code_hash[2_u32]); + sink.add_u64(account.code_hash[3_u32]); + }; + } + + unconstrained fn rlp_encode_unconstrained(account: Account, start_nibble_idx: u32, trie_key: [u8; 32]) -> ([u8; 147], u32) { + let mut writer: BytesWriter<147> = BytesWriter::<147>::new(); + rlp_encode_to_sink(account, start_nibble_idx, trie_key, &mut writer); + writer.finish() + } + + pub fn compute_account_hash(account: Account, start_nibble_idx: u32, trie_key: [u8; 32]) -> [u64; 4] { + if std::runtime::is_unconstrained() { + let mut hasher: KeccakHasher = KeccakHasher::new(); + rlp_encode_to_sink(account, start_nibble_idx, trie_key, &mut hasher); + hasher.finish_to_limbs() + } else { + // Safety: comment added by `nargo expand` + let (bytes, length): ([u8; 147], u32) = unsafe { + rlp_encode_unconstrained(account, start_nibble_idx, trie_key) + }; + let mut checker: BytesChecker<147> = BytesChecker::<147>::new(bytes, length); + rlp_encode_to_sink(account, start_nibble_idx, trie_key, &mut checker); + checker.finish(); + keccak256_limbs(bytes, length) + } + } + } + + pub mod branch_hash { + use super::bytes_sink::BytesChecker; + use super::bytes_sink::BytesSink; + use super::bytes_sink::BytesWriter; + use super::keccak::keccak256_limbs; + use super::keccak::KeccakHasher; + use super::types::Node; + use super::utils::unroll_loop; + + global BRANCH_RLP_MAX_LENGTH: u32 = 532; + + #[inline_always] + fn compute_rlp_length(node: Node) -> u16 { + let mut len: u16 = 0_u16; + { + if node.row_exist[0_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[1_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[2_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[3_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[4_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[5_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[6_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[7_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[8_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[9_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[10_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[11_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[12_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[13_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[14_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + }; + if node.row_exist[15_u32] { + len = len + 33_u16; + } else { + len = len + 1_u16; + } + }; + len = len + 1_u16; + len + } + + #[inline_always] + fn rlp_encode_to_sink(node: Node, sink: &mut S) where S: BytesSink { + let len: u16 = compute_rlp_length(node); + if len <= 55_u16 { + sink.add_byte(192_u8 + (len as u8)); + } else if len <= 255_u16 { + sink.add_byte(248_u8); + sink.add_byte(len as u8); + } else { + sink.add_byte(249_u8); + sink.add_byte((len >> 8_u16) as u8); + sink.add_byte((len & 255_u16) as u8); + }; + { + if node.row_exist[0_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[0_u32][0_u32]); + sink.add_u64(node.rows[0_u32][1_u32]); + sink.add_u64(node.rows[0_u32][2_u32]); + sink.add_u64(node.rows[0_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[1_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[1_u32][0_u32]); + sink.add_u64(node.rows[1_u32][1_u32]); + sink.add_u64(node.rows[1_u32][2_u32]); + sink.add_u64(node.rows[1_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[2_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[2_u32][0_u32]); + sink.add_u64(node.rows[2_u32][1_u32]); + sink.add_u64(node.rows[2_u32][2_u32]); + sink.add_u64(node.rows[2_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[3_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[3_u32][0_u32]); + sink.add_u64(node.rows[3_u32][1_u32]); + sink.add_u64(node.rows[3_u32][2_u32]); + sink.add_u64(node.rows[3_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[4_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[4_u32][0_u32]); + sink.add_u64(node.rows[4_u32][1_u32]); + sink.add_u64(node.rows[4_u32][2_u32]); + sink.add_u64(node.rows[4_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[5_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[5_u32][0_u32]); + sink.add_u64(node.rows[5_u32][1_u32]); + sink.add_u64(node.rows[5_u32][2_u32]); + sink.add_u64(node.rows[5_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[6_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[6_u32][0_u32]); + sink.add_u64(node.rows[6_u32][1_u32]); + sink.add_u64(node.rows[6_u32][2_u32]); + sink.add_u64(node.rows[6_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[7_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[7_u32][0_u32]); + sink.add_u64(node.rows[7_u32][1_u32]); + sink.add_u64(node.rows[7_u32][2_u32]); + sink.add_u64(node.rows[7_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[8_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[8_u32][0_u32]); + sink.add_u64(node.rows[8_u32][1_u32]); + sink.add_u64(node.rows[8_u32][2_u32]); + sink.add_u64(node.rows[8_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[9_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[9_u32][0_u32]); + sink.add_u64(node.rows[9_u32][1_u32]); + sink.add_u64(node.rows[9_u32][2_u32]); + sink.add_u64(node.rows[9_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[10_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[10_u32][0_u32]); + sink.add_u64(node.rows[10_u32][1_u32]); + sink.add_u64(node.rows[10_u32][2_u32]); + sink.add_u64(node.rows[10_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[11_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[11_u32][0_u32]); + sink.add_u64(node.rows[11_u32][1_u32]); + sink.add_u64(node.rows[11_u32][2_u32]); + sink.add_u64(node.rows[11_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[12_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[12_u32][0_u32]); + sink.add_u64(node.rows[12_u32][1_u32]); + sink.add_u64(node.rows[12_u32][2_u32]); + sink.add_u64(node.rows[12_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[13_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[13_u32][0_u32]); + sink.add_u64(node.rows[13_u32][1_u32]); + sink.add_u64(node.rows[13_u32][2_u32]); + sink.add_u64(node.rows[13_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[14_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[14_u32][0_u32]); + sink.add_u64(node.rows[14_u32][1_u32]); + sink.add_u64(node.rows[14_u32][2_u32]); + sink.add_u64(node.rows[14_u32][3_u32]); + } else { + sink.add_byte(128_u8); + }; + if node.row_exist[15_u32] { + sink.add_byte(160_u8); + sink.add_u64(node.rows[15_u32][0_u32]); + sink.add_u64(node.rows[15_u32][1_u32]); + sink.add_u64(node.rows[15_u32][2_u32]); + sink.add_u64(node.rows[15_u32][3_u32]); + } else { + sink.add_byte(128_u8); + } + }; + sink.add_byte(128_u8); + } + + unconstrained fn rlp_encode_unconstrained(node: Node) -> ([u8; 532], u32) { + let mut writer: BytesWriter<532> = BytesWriter::<532>::new(); + rlp_encode_to_sink(node, &mut writer); + writer.finish() + } + + pub fn rlp_and_hash_branch_node(node: Node) -> [u64; 4] { + if std::runtime::is_unconstrained() { + let mut hasher: KeccakHasher = KeccakHasher::new(); + rlp_encode_to_sink(node, &mut hasher); + hasher.finish_to_limbs() + } else { + // Safety: comment added by `nargo expand` + let (bytes, length): ([u8; 532], u32) = unsafe { + rlp_encode_unconstrained(node) + }; + let mut checker: BytesChecker<532> = BytesChecker::<532>::new(bytes, length); + rlp_encode_to_sink(node, &mut checker); + checker.finish(); + keccak256_limbs(bytes, length) + } + } + } + + pub mod bytes_sink { + use super::keccak::KeccakHasher; + + pub trait BytesSink { + fn add_byte(&mut self, byte: u8); + + fn add_u64(&mut self, value: u64); + } + + /// Writes bytes to an array. + pub struct BytesWriter { + bytes: [u8; N], + index: u32, + } + + impl BytesWriter { + pub fn new() -> Self { + Self { bytes: [0_u8; N], index: 0_u32} + } + + pub fn finish(self) -> ([u8; N], u32) { + (self.bytes, self.index) + } + } + + impl BytesSink for BytesWriter { + fn add_byte(&mut self, byte: u8) { + self.bytes[self.index] = byte; + self.index = self.index + 1_u32; + } + + fn add_u64(&mut self, mut value: u64) { + for _ in 0_u32..8_u32 { + self.add_byte(value as u8); + value = value >> 8_u64; + } + } + } + + /// Checks that a given array matches the expected bytes written, up to a given length. + pub struct BytesChecker { + bytes: [u8; N], + index: u32, + expected_length: u32, + } + + impl BytesChecker { + pub fn new(bytes: [u8; N], expected_length: u32) -> Self { + Self { bytes: bytes, index: 0_u32, expected_length: expected_length} + } + + pub fn finish(self) { + assert(self.index == self.expected_length); + } + } + + impl BytesSink for BytesChecker { + fn add_byte(&mut self, byte: u8) { + assert(self.bytes[self.index] == byte); + self.index = self.index + 1_u32; + } + + fn add_u64(&mut self, mut value: u64) { + for _ in 0_u32..8_u32 { + self.add_byte(value as u8); + value = value >> 8_u64; + } + } + } + } + + pub mod extension_hash { + use super::bytes_sink::BytesChecker; + use super::bytes_sink::BytesSink; + use super::bytes_sink::BytesWriter; + use super::keccak::keccak256_limbs; + use super::keccak::KeccakHasher; + use super::types::ExtensionHeader; + use super::types::Node; + use super::utils::unroll_loop; + + global EXTENSION_RLP_MAX_LENGTH: u32 = 68; + + #[inline_always] + fn rlp_encode_to_sink(node: Node, header: ExtensionHeader, sink: &mut S) where S: BytesSink { + let extension_length_size: u8 = header.extension_length + 1_u8; + let rlp_data_length: u8 = (extension_length_size + 33_u8) + ((extension_length_size != 1_u8) as u8); + if rlp_data_length > 55_u8 { + sink.add_byte(248_u8); + sink.add_byte(rlp_data_length); + } else { + sink.add_byte(192_u8 + rlp_data_length); + }; + if extension_length_size != 1_u8 { + sink.add_byte(128_u8 + extension_length_size); + }; + sink.add_byte(((header.is_odd as u8) << 4_u8) + header.first_nibble); + { + if (0_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 0_u32)); + }; + if (1_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 1_u32)); + }; + if (2_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 2_u32)); + }; + if (3_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 3_u32)); + }; + if (4_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 4_u32)); + }; + if (5_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 5_u32)); + }; + if (6_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 6_u32)); + }; + if (7_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 7_u32)); + }; + if (8_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 8_u32)); + }; + if (9_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 9_u32)); + }; + if (10_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 10_u32)); + }; + if (11_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 11_u32)); + }; + if (12_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 12_u32)); + }; + if (13_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 13_u32)); + }; + if (14_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 14_u32)); + }; + if (15_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 15_u32)); + }; + if (16_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 16_u32)); + }; + if (17_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 17_u32)); + }; + if (18_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 18_u32)); + }; + if (19_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 19_u32)); + }; + if (20_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 20_u32)); + }; + if (21_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 21_u32)); + }; + if (22_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 22_u32)); + }; + if (23_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 23_u32)); + }; + if (24_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 24_u32)); + }; + if (25_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 25_u32)); + }; + if (26_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 26_u32)); + }; + if (27_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 27_u32)); + }; + if (28_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 28_u32)); + }; + if (29_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 29_u32)); + }; + if (30_u32 as u8) < header.extension_length { + sink.add_byte(node.get_row_byte(1_u32, 30_u32)); + } + }; + sink.add_byte(160_u8); + { + sink.add_u64(node.rows[2_u32][0_u32]); + sink.add_u64(node.rows[2_u32][1_u32]); + sink.add_u64(node.rows[2_u32][2_u32]); + sink.add_u64(node.rows[2_u32][3_u32]); + }; + } + + unconstrained fn rlp_encode_unconstrained(node: Node, header: ExtensionHeader) -> ([u8; 68], u32) { + let mut writer: BytesWriter<68> = BytesWriter::<68>::new(); + rlp_encode_to_sink(node, header, &mut writer); + writer.finish() + } + + pub fn rlp_and_hash_extension_node(node: Node, header: ExtensionHeader) -> [u64; 4] { + if std::runtime::is_unconstrained() { + let mut hasher: KeccakHasher = KeccakHasher::new(); + rlp_encode_to_sink(node, header, &mut hasher); + hasher.finish_to_limbs() + } else { + // Safety: comment added by `nargo expand` + let (bytes, length): ([u8; 68], u32) = unsafe { + rlp_encode_unconstrained(node, header) + }; + let mut checker: BytesChecker<68> = BytesChecker::<68>::new(bytes, length); + rlp_encode_to_sink(node, header, &mut checker); + checker.finish(); + keccak256_limbs(bytes, length) + } + } + } + + pub mod keccak { + use keccak256::keccak256 as keccak256lib; + use keccak256::keccak256 as keccak256lib; + use std::hash::keccakf1600; + + global BLOCK_SIZE_IN_BYTES: u32 = 136; + + global WORD_SIZE: u32 = 8; + + global LIMBS_PER_BLOCK: u32 = 17; + + global NUM_KECCAK_LANES: u32 = 25; + + pub struct KeccakHasher { + state: [u64; 25], + limb_index_to_write: u32, + current_limb: u64, + current_limb_shift: u64, + } + + impl KeccakHasher { + pub fn new() -> Self { + Self { state: [0_u64; 25], limb_index_to_write: 0_u32, current_limb: 0_u64, current_limb_shift: 0_u64} + } + + pub fn hash_bytes(bytes: [u8; N], length: u32) -> [u8; 32] { + let mut hasher: Self = Self::new(); + for i in 0_u32..length { + hasher.add_byte(bytes[i]); + }; + hasher.finish() + } + + pub fn hash_bytes_to_limbs(bytes: [u8; N], length: u32) -> [u64; 4] { + let mut hasher: Self = Self::new(); + for i in 0_u32..length { + hasher.add_byte(bytes[i]); + }; + hasher.finish_to_limbs() + } + + pub fn add_byte(&mut self, byte: u8) { + let byte_as_u64: u64 = byte as u64; + let shifted_byte: u64 = byte_as_u64 << self.current_limb_shift; + self.current_limb = self.current_limb + shifted_byte; + if self.current_limb_shift == 56_u64 { + self.finish_limb(); + } else { + self.current_limb_shift = self.current_limb_shift + 8_u64; + } + } + + pub fn add_u64(&mut self, value: u64) { + if self.current_limb_shift == 0_u64 { + self.current_limb = value; + self.finish_limb(); + } else { + let shift: u64 = self.current_limb_shift; + self.current_limb = self.current_limb + (value << shift); + self.finish_limb(); + self.current_limb = value >> (64_u64 - shift); + self.current_limb_shift = shift; + } + } + + #[inline_always] + fn finish_limb(&mut self) { + self.state[self.limb_index_to_write] = self.state[self.limb_index_to_write] ^ self.current_limb; + self.current_limb_shift = 0_u64; + self.current_limb = 0_u64; + if self.limb_index_to_write == (LIMBS_PER_BLOCK - 1_u32) { + self.finish_block(); + } else { + self.limb_index_to_write = self.limb_index_to_write + 1_u32; + } + } + + #[inline_always] + fn finish_block(&mut self) { + self.state = keccakf1600(self.state); + self.limb_index_to_write = 0_u32; + } + + #[inline_always] + fn apply_padding(&mut self) { + self.state[self.limb_index_to_write] = self.state[self.limb_index_to_write] ^ (self.current_limb + (1_u64 << self.current_limb_shift)); + { + let i_0: u32 = LIMBS_PER_BLOCK - 1_u32; + self.state[i_0] = self.state[LIMBS_PER_BLOCK - 1_u32] ^ (128_u64 << 56_u64); + } + } + + pub fn finish_to_limbs(mut self) -> [u64; 4] { + self.apply_padding(); + self.finish_block(); + [self.state[0_u32], self.state[1_u32], self.state[2_u32], self.state[3_u32]] + } + + pub fn finish(mut self) -> [u8; 32] { + self.apply_padding(); + self.finish_block(); + let mut result: [u8; 32] = [0_u8; 32]; + for i in 0_u32..4_u32 { + let lane: Field = self.state[i] as Field; + let lane_le: [u8; 8] = lane.to_be_bytes(); + for j in 0_u32..8_u32 { + { + let i_0: u32 = (8_u32 * i) + j; + result[i_0] = lane_le[7_u32 - j]; + } + } + }; + result + } + } + + impl super::bytes_sink::BytesSink for KeccakHasher { + fn add_byte(&mut self, byte: u8) { + self.add_byte(byte); + } + + fn add_u64(&mut self, mut value: u64) { + self.add_u64(value); + } + } + + pub fn keccak256(input: [u8; N], message_size: u32) -> [u8; 32] { + keccak256lib(input, message_size) + } + + pub fn keccak256_limbs(input: [u8; N], message_size: u32) -> [u64; 4] { + let bytes: [u8; 32] = keccak256lib(input, message_size); + bytes_to_u64(bytes) + } + + fn bytes_to_u64(bytes: [u8; N]) -> [u64; K] { + std::static_assert((K * 8_u32) == N, "Invalid number of u64s for given number of bytes"); + let mut result: [u64; K] = [0_u64; K]; + for i in 0_u32..K { + let mut value: u64 = 0_u64; + for j in 0_u32..8_u32 { + let byte: u8 = bytes[(i * 8_u32) + j]; + value = value + ((byte as u64) << ((8_u32 * j) as u64)); + }; + result[i] = value; + }; + result + } + } + + pub mod path_verification { + use super::branch_hash; + use super::extension_hash; + use super::types::Node; + use super::utils::runtime_loop; + + pub fn verify_path_section(nodes: [Node; MAX_PATH_LENGTH], node_length: u32, start_trie_key_index: u32, mut parent: [u64; 4], trie_key_nibbles: [u8; 64]) -> ([u64; 4], u32) { + let mut current_nibble_idx: u32 = start_trie_key_index; + { + assert(0_u32 <= node_length); + assert(node_length <= MAX_PATH_LENGTH); + if std::runtime::is_unconstrained() { + for i in 0_u32..node_length { + let node: Node = nodes[i]; + if node.is_branch_node() { + let hash: [u64; 4] = branch_hash::rlp_and_hash_branch_node(node); + assert(hash == parent); + let index: u32 = trie_key_nibbles[current_nibble_idx] as u32; + parent = node.rows[index]; + current_nibble_idx = current_nibble_idx + 1_u32; + } else if node.is_extension_node() { + let header: super::types::ExtensionHeader = node.extract_extension_header(); + let hash: [u64; 4] = extension_hash::rlp_and_hash_extension_node(node, header); + assert(hash == parent); + if header.is_odd { + assert(trie_key_nibbles[current_nibble_idx] == header.first_nibble); + current_nibble_idx = current_nibble_idx + 1_u32; + }; + { + assert(0_u32 <= (header.extension_length as u32)); + assert((header.extension_length as u32) <= 32_u32); + if std::runtime::is_unconstrained() { + for j in 0_u32..header.extension_length as u32 { + let high_key_nibble: u8 = trie_key_nibbles[current_nibble_idx]; + let low_key_nibble: u8 = trie_key_nibbles[current_nibble_idx + 1_u32]; + let key_byte: u8 = (high_key_nibble << 4_u8) + low_key_nibble; + current_nibble_idx = current_nibble_idx + 2_u32; + let extension_byte: u8 = node.get_row_byte(1_u32, j); + assert(key_byte == extension_byte); + () + } + } else { + for j in 0_u32..32_u32 { + if (j >= 0_u32) & (j < (header.extension_length as u32)) { + let high_key_nibble: u8 = trie_key_nibbles[current_nibble_idx]; + let low_key_nibble: u8 = trie_key_nibbles[current_nibble_idx + 1_u32]; + let key_byte: u8 = (high_key_nibble << 4_u8) + low_key_nibble; + current_nibble_idx = current_nibble_idx + 2_u32; + let extension_byte: u8 = node.get_row_byte(1_u32, j); + assert(key_byte == extension_byte); + () + } + } + } + }; + parent = node.rows[2_u32]; + } else { + assert(false); + }; + () + } + } else { + for i in 0_u32..MAX_PATH_LENGTH { + if (i >= 0_u32) & (i < node_length) { + let node: Node = nodes[i]; + if node.is_branch_node() { + let hash: [u64; 4] = branch_hash::rlp_and_hash_branch_node(node); + assert(hash == parent); + let index: u32 = trie_key_nibbles[current_nibble_idx] as u32; + parent = node.rows[index]; + current_nibble_idx = current_nibble_idx + 1_u32; + } else if node.is_extension_node() { + let header: super::types::ExtensionHeader = node.extract_extension_header(); + let hash: [u64; 4] = extension_hash::rlp_and_hash_extension_node(node, header); + assert(hash == parent); + if header.is_odd { + assert(trie_key_nibbles[current_nibble_idx] == header.first_nibble); + current_nibble_idx = current_nibble_idx + 1_u32; + }; + { + assert(0_u32 <= (header.extension_length as u32)); + assert((header.extension_length as u32) <= 32_u32); + if std::runtime::is_unconstrained() { + for j in 0_u32..header.extension_length as u32 { + let high_key_nibble: u8 = trie_key_nibbles[current_nibble_idx]; + let low_key_nibble: u8 = trie_key_nibbles[current_nibble_idx + 1_u32]; + let key_byte: u8 = (high_key_nibble << 4_u8) + low_key_nibble; + current_nibble_idx = current_nibble_idx + 2_u32; + let extension_byte: u8 = node.get_row_byte(1_u32, j); + assert(key_byte == extension_byte); + () + } + } else { + for j in 0_u32..32_u32 { + if (j >= 0_u32) & (j < (header.extension_length as u32)) { + let high_key_nibble: u8 = trie_key_nibbles[current_nibble_idx]; + let low_key_nibble: u8 = trie_key_nibbles[current_nibble_idx + 1_u32]; + let key_byte: u8 = (high_key_nibble << 4_u8) + low_key_nibble; + current_nibble_idx = current_nibble_idx + 2_u32; + let extension_byte: u8 = node.get_row_byte(1_u32, j); + assert(key_byte == extension_byte); + () + } + } + } + }; + parent = node.rows[2_u32]; + } else { + assert(false); + }; + () + } + } + } + }; + (parent, current_nibble_idx) + } + } + + pub mod slot_hash { + use super::bytes_sink::BytesChecker; + use super::bytes_sink::BytesSink; + use super::bytes_sink::BytesWriter; + use super::keccak::keccak256_limbs; + use super::keccak::KeccakHasher; + use super::types::StorageSlot; + use super::utils::get_low_nibble; + use super::utils::get_rlp_length; + use super::utils::runtime_loop; + + global SLOT_RLP_MAX_LENGTH: u32 = 69; + + #[inline_always] + fn rlp_encode_to_sink(slot: StorageSlot, start_nibble_idx: u32, trie_key: [u8; 32], sink: &mut S) where S: BytesSink { + let mut current_nibble_idx: u32 = start_nibble_idx; + let first_key_byte: u8 = if (current_nibble_idx % 2_u32) == 0_u32 { + 32_u8 + } else { + let first_byte: u8 = trie_key[(current_nibble_idx / 2_u32) as u32]; + current_nibble_idx = current_nibble_idx + 1_u32; + 48_u8 + get_low_nibble(first_byte) + }; + let key_length: u8 = (32_u8 - ((current_nibble_idx as u8) / 2_u8)) + 1_u8; + let leaf_key_rlp_length: u8 = get_rlp_length(first_key_byte, key_length); + assert(slot.value_length <= 32_u8); + let inner_rlp_length: u8 = get_rlp_length(slot.value[0_u32], slot.value_length); + let inner_first_byte: u8 = if slot.value_length == 0_u8 { + 128_u8 + } else if (slot.value_length == 1_u8) & (slot.value[0_u32] <= 127_u8) { + slot.value[0_u32] + } else { + 128_u8 + slot.value_length + }; + let outer_rlp_length: u8 = get_rlp_length(inner_first_byte, inner_rlp_length); + let leaf_rlp_total_length: u8 = leaf_key_rlp_length + outer_rlp_length; + if leaf_rlp_total_length <= 55_u8 { + sink.add_byte(192_u8 + leaf_rlp_total_length); + } else { + sink.add_byte(248_u8); + sink.add_byte(leaf_rlp_total_length); + }; + if (key_length == 1_u8) & (first_key_byte <= 127_u8) { + sink.add_byte(first_key_byte); + } else { + sink.add_byte(128_u8 + key_length); + sink.add_byte(first_key_byte); + let start_byte_idx: u32 = current_nibble_idx / 2_u32; + let end_byte_idx: u32 = start_byte_idx + ((key_length - 1_u8) as u32); + { + assert(start_byte_idx <= end_byte_idx); + assert(end_byte_idx <= trie_key.len()); + if std::runtime::is_unconstrained() { + for i in start_byte_idx..end_byte_idx { + sink.add_byte(trie_key[i]); + () + } + } else { + for i in 0_u32..trie_key.len() { + if (i >= start_byte_idx) & (i < end_byte_idx) { + sink.add_byte(trie_key[i]); + () + } + } + } + }; + }; + if (inner_rlp_length == 1_u8) & (inner_first_byte <= 127_u8) { + } else { + sink.add_byte(128_u8 + inner_rlp_length); + }; + if slot.value_length == 0_u8 { + sink.add_byte(128_u8); + } else if (slot.value_length == 1_u8) & (slot.value[0_u32] <= 127_u8) { + sink.add_byte(slot.value[0_u32]); + } else { + sink.add_byte(128_u8 + slot.value_length); + { + assert(0_u32 <= (slot.value_length as u32)); + assert((slot.value_length as u32) <= 32_u32); + if std::runtime::is_unconstrained() { + for i in 0_u32..slot.value_length as u32 { + sink.add_byte(slot.value[i]); + () + } + } else { + for i in 0_u32..32_u32 { + if (i >= 0_u32) & (i < (slot.value_length as u32)) { + sink.add_byte(slot.value[i]); + () + } + } + } + }; + } + } + + unconstrained fn rlp_encode_unconstrained(slot: StorageSlot, start_nibble_idx: u32, trie_key: [u8; 32]) -> ([u8; 69], u32) { + let mut writer: BytesWriter<69> = BytesWriter::<69>::new(); + rlp_encode_to_sink(slot, start_nibble_idx, trie_key, &mut writer); + writer.finish() + } + + pub fn compute_slot_hash(slot: StorageSlot, start_nibble_idx: u32, trie_key: [u8; 32]) -> [u64; 4] { + if std::runtime::is_unconstrained() { + let mut hasher: KeccakHasher = KeccakHasher::new(); + rlp_encode_to_sink(slot, start_nibble_idx, trie_key, &mut hasher); + hasher.finish_to_limbs() + } else { + // Safety: comment added by `nargo expand` + let (bytes, length): ([u8; 69], u32) = unsafe { + rlp_encode_unconstrained(slot, start_nibble_idx, trie_key) + }; + let mut checker: BytesChecker<69> = BytesChecker::<69>::new(bytes, length); + rlp_encode_to_sink(slot, start_nibble_idx, trie_key, &mut checker); + checker.finish(); + keccak256_limbs(bytes, length) + } + } + } + + pub mod types { + use super::utils::get_low_nibble; + use aztec::protocol::traits::Deserialize; + use aztec::protocol::traits::Serialize; + + pub struct ExtensionHeader { + pub is_odd: bool, + pub first_nibble: u8, + pub extension_length: u8, + } + + pub struct Node { + pub rows: [[u64; 4]; 16], + pub row_exist: [bool; 16], + pub node_type: u8, + } + + impl Node { + #[inline_always] + pub fn is_branch_node(self) -> bool { + self.node_type == 0_u8 + } + + #[inline_always] + pub fn is_extension_node(self) -> bool { + self.node_type == 1_u8 + } + + #[inline_always] + pub fn get_row_byte(self, row: u32, byte_index: u32) -> u8 { + let limb_index: u32 = byte_index / 8_u32; + let shift: u64 = ((byte_index % 8_u32) * 8_u32) as u64; + (self.rows[row][limb_index] >> shift) as u8 + } + + pub fn extract_extension_header(self) -> ExtensionHeader { + let is_odd: bool = self.rows[0_u32][0_u32] != 0_u64; + let first_nibble: u8 = if is_odd { + get_low_nibble(self.rows[0_u32][1_u32] as u8) + } else { + 0_u8 + }; + let extension_length: u8 = self.rows[0_u32][2_u32] as u8; + ExtensionHeader { is_odd: is_odd, first_nibble: first_nibble, extension_length: extension_length} + } + } + + impl Serialize for Node { + let N: u32 = 81; + + fn serialize(self) -> [Field; 81] { + let mut writer: aztec::protocol::utils::writer::Writer<81> = aztec::protocol::utils::writer::Writer::<81>::new(); + self.stream_serialize(&mut writer); + writer.finish() + } + + #[inline_always] + fn stream_serialize(self, writer: &mut aztec::protocol::utils::writer::Writer) { + self.rows.stream_serialize(writer); + self.row_exist.stream_serialize(writer); + self.node_type.stream_serialize(writer); + } + } + + impl Deserialize for Node { + let N: u32 = 81; + + fn deserialize(fields: [Field; 81]) -> Self { + let mut reader: aztec::protocol::utils::reader::Reader<81> = aztec::protocol::utils::reader::Reader::<81>::new(fields); + let result: Self = Self::stream_deserialize(&mut reader); + reader.finish(); + result + } + + #[inline_always] + fn stream_deserialize(reader: &mut aztec::protocol::utils::reader::Reader) -> Self { + let rows: [[u64; 4]; 16] = <[[u64; 4]; 16] as Deserialize>::stream_deserialize(reader); + let row_exist: [bool; 16] = <[bool; 16] as Deserialize>::stream_deserialize(reader); + let node_type: u8 = ::stream_deserialize(reader); + Self { rows: rows, row_exist: row_exist, node_type: node_type} + } + } + + pub struct Account { + pub nonce: [u8; 8], + pub balance: [u8; 32], + pub address: [u8; 20], + pub nonce_length: u8, + pub balance_length: u8, + pub storage_hash: [u64; 4], + pub code_hash: [u64; 4], + } + + impl Serialize for Account { + let N: u32 = 70; + + fn serialize(self) -> [Field; 70] { + let mut writer: aztec::protocol::utils::writer::Writer<70> = aztec::protocol::utils::writer::Writer::<70>::new(); + self.stream_serialize(&mut writer); + writer.finish() + } + + #[inline_always] + fn stream_serialize(self, writer: &mut aztec::protocol::utils::writer::Writer) { + self.nonce.stream_serialize(writer); + self.balance.stream_serialize(writer); + self.address.stream_serialize(writer); + self.nonce_length.stream_serialize(writer); + self.balance_length.stream_serialize(writer); + self.storage_hash.stream_serialize(writer); + self.code_hash.stream_serialize(writer); + } + } + + impl Deserialize for Account { + let N: u32 = 70; + + fn deserialize(fields: [Field; 70]) -> Self { + let mut reader: aztec::protocol::utils::reader::Reader<70> = aztec::protocol::utils::reader::Reader::<70>::new(fields); + let result: Self = Self::stream_deserialize(&mut reader); + reader.finish(); + result + } + + #[inline_always] + fn stream_deserialize(reader: &mut aztec::protocol::utils::reader::Reader) -> Self { + let nonce: [u8; 8] = <[u8; 8] as Deserialize>::stream_deserialize(reader); + let balance: [u8; 32] = <[u8; 32] as Deserialize>::stream_deserialize(reader); + let address: [u8; 20] = <[u8; 20] as Deserialize>::stream_deserialize(reader); + let nonce_length: u8 = ::stream_deserialize(reader); + let balance_length: u8 = ::stream_deserialize(reader); + let storage_hash: [u64; 4] = <[u64; 4] as Deserialize>::stream_deserialize(reader); + let code_hash: [u64; 4] = <[u64; 4] as Deserialize>::stream_deserialize(reader); + Self { nonce: nonce, balance: balance, address: address, nonce_length: nonce_length, balance_length: balance_length, storage_hash: storage_hash, code_hash: code_hash} + } + } + + pub struct StorageSlot { + pub value: [u8; 32], + pub value_length: u8, + } + + impl Serialize for StorageSlot { + let N: u32 = 33; + + fn serialize(self) -> [Field; 33] { + let mut writer: aztec::protocol::utils::writer::Writer<33> = aztec::protocol::utils::writer::Writer::<33>::new(); + self.stream_serialize(&mut writer); + writer.finish() + } + + #[inline_always] + fn stream_serialize(self, writer: &mut aztec::protocol::utils::writer::Writer) { + self.value.stream_serialize(writer); + self.value_length.stream_serialize(writer); + } + } + + impl Deserialize for StorageSlot { + let N: u32 = 33; + + fn deserialize(fields: [Field; 33]) -> Self { + let mut reader: aztec::protocol::utils::reader::Reader<33> = aztec::protocol::utils::reader::Reader::<33>::new(fields); + let result: Self = Self::stream_deserialize(&mut reader); + reader.finish(); + result + } + + #[inline_always] + fn stream_deserialize(reader: &mut aztec::protocol::utils::reader::Reader) -> Self { + let value: [u8; 32] = <[u8; 32] as Deserialize>::stream_deserialize(reader); + let value_length: u8 = ::stream_deserialize(reader); + Self { value: value, value_length: value_length} + } + } + } + + pub mod utils { + use std::static_assert; + + /// Unrolls a loop at comptime + pub comptime fn unroll_loop(start: u32, end: u32, body: fn(u32) -> Quoted) -> Quoted { + let mut iterations: [Quoted] = @[]; + for i in start..end { + iterations = iterations.push_back(body(i)); + }; + iterations.join(quote { }) + } + + /// Creates a loop that: + /// - In ACIR: iterates from 0 to upper bound, and conditions body on index >= start_variable & index < end_variable + /// - In BRILLIG: iterates from start_variable to end_variable + pub comptime fn runtime_loop(iterator: Quoted, start_variable: Quoted, end_variable: Quoted, upper_bound: Quoted, body: Quoted) -> Quoted { + quote { + assert($start_variable <= $end_variable); + assert($end_variable <= $upper_bound); + if std::runtime::is_unconstrained() { + for $iterator in $start_variable..$end_variable { + $body() + } + } else { + for $iterator in 0..$upper_bound { + if $iterator >= $start_variable & $iterator < $end_variable { + $body() + } + } + } + } + } + + pub fn balance_to_field(balance: [u8; 32], balance_length: u8) -> Field { + let mut result: Field = 0_Field; + { + assert(0_u32 <= (balance_length as u32)); + assert((balance_length as u32) <= 32_u32); + if std::runtime::is_unconstrained() { + for i in 0_u32..balance_length as u32 { + result = result * 256_Field; + result = result + (balance[i] as Field); + () + } + } else { + for i in 0_u32..32_u32 { + if (i >= 0_u32) & (i < (balance_length as u32)) { + result = result * 256_Field; + result = result + (balance[i] as Field); + () + } + } + } + }; + result + } + + pub fn to_nibbles(bytes: [u8; N]) -> [u8; K] { + static_assert((N * 2_u32) == K, "Nibble amount should be double the byte amount"); + let mut nibbles: [u8; K] = [0_u8; K]; + for i in 0_u32..N { + let byte: u8 = bytes[i]; + { + let i_0: u32 = i * 2_u32; + nibbles[i_0] = byte >> 4_u8; + }; + { + let i_1: u32 = (i * 2_u32) + 1_u32; + nibbles[i_1] = (byte << 4_u8) >> 4_u8; + } + }; + nibbles + } + + #[inline_always] + pub fn get_low_nibble(byte: u8) -> u8 { + (byte << 4_u8) >> 4_u8 + } + + #[inline_always] + pub fn get_high_nibble(byte: u8) -> u8 { + byte >> 4_u8 + } + + pub fn get_rlp_length(first_elem: u8, length: u8) -> u8 { + let mut rlp_length: u8 = 0_u8; + if length == 0_u8 { + rlp_length = 1_u8; + } else if length == 1_u8 { + if first_elem <= 127_u8 { + rlp_length = 1_u8; + } else { + rlp_length = 2_u8; + } + } else { + rlp_length = 1_u8 + length; + }; + rlp_length + } + } +} + +// Warning: the generated code has syntax errors diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/token_contract/snapshots__expanded.snap b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/token_contract/snapshots__expanded.snap new file mode 100644 index 000000000000..ca20d6e6efd9 --- /dev/null +++ b/noir-projects/noir-contract-snapshots/tests/snapshots/expand/token_contract/snapshots__expanded.snap @@ -0,0 +1,4965 @@ +--- +source: tests/snapshots.rs +expression: stdout +--- +use aztec::macros::aztec; +use aztec::macros::aztec; + +pub contract Token { + use std::ops::Add; + use std::ops::Sub; + use compressed_string::FieldCompressedString; + use aztec::authwit::auth::compute_authwit_nullifier; + use aztec::context::calls::PrivateCall; + use aztec::context::PrivateContext; + use aztec::macros::events::event; + use aztec::macros::functions::authorize_once; + use aztec::macros::functions::external; + use aztec::macros::functions::initializer; + use aztec::macros::functions::internal; + use aztec::macros::functions::only_self; + use aztec::macros::functions::view; + use aztec::macros::storage::storage; + use aztec::messages::message_delivery::MessageDelivery; + use aztec::protocol::address::AztecAddress; + use aztec::protocol::traits::ToField; + use aztec::state_vars::Map; + use aztec::state_vars::Owned; + use aztec::state_vars::PublicImmutable; + use aztec::state_vars::PublicMutable; + use aztec::state_vars::StateVariable; + use uint_note::PartialUintNote; + use uint_note::UintNote; + use balance_set::BalanceSet; + + global INITIAL_TRANSFER_CALL_MAX_NOTES: u32 = 2; + + global RECURSIVE_TRANSFER_CALL_MAX_NOTES: u32 = 8; + + #[abi(events)] + struct Transfer { + from: AztecAddress, + to: AztecAddress, + amount: u128, + } + + impl aztec::event::event_interface::EventInterface for Transfer { + fn get_event_type_id() -> aztec::event::EventSelector { + ::from_field(1889634638_Field) + } + } + + impl aztec::protocol::traits::Serialize for Transfer { + let N: u32 = 3; + + fn serialize(self) -> [Field; 3] { + let mut writer: aztec::protocol::utils::writer::Writer<3> = aztec::protocol::utils::writer::Writer::<3>::new(); + >::stream_serialize(self, &mut writer); + writer.finish() + } + + #[inline_always] + fn stream_serialize(self, writer: &mut aztec::protocol::utils::writer::Writer) { + ::stream_serialize(self.from, writer); + ::stream_serialize(self.to, writer); + ::stream_serialize(self.amount, writer); + } + } + + struct Storage { + admin: PublicMutable, + minters: Map, Context>, + balances: Owned, Context>, + total_supply: PublicMutable, + public_balances: Map, Context>, + symbol: PublicImmutable, + name: PublicImmutable, + decimals: PublicImmutable, + } + + impl Storage { + fn init(context: Context) -> Self { + Self { admin: as StateVariable<1, Context>>::new(context, 1_Field), minters: , Context> as StateVariable<1, Context>>::new(context, 2_Field), balances: , Context> as StateVariable<1, Context>>::new(context, 3_Field), total_supply: as StateVariable<1, Context>>::new(context, 4_Field), public_balances: , Context> as StateVariable<1, Context>>::new(context, 5_Field), symbol: as StateVariable<2, Context>>::new(context, 6_Field), name: as StateVariable<2, Context>>::new(context, 8_Field), decimals: as StateVariable<2, Context>>::new(context, 10_Field)} + } + } + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call constructor. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_admin. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_admin(new_admin: AztecAddress); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call public_get_name. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn public_get_name() -> FieldCompressedString; + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call private_get_name. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn private_get_name() -> FieldCompressedString; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call public_get_symbol. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn public_get_symbol() -> pub FieldCompressedString; + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call private_get_symbol. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn private_get_symbol() -> pub FieldCompressedString; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call public_get_decimals. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn public_get_decimals() -> pub u8; + + #[abi(storage)] + pub global STORAGE_LAYOUT_Token: StorageLayout<5> = StorageLayout::<5> { + contract_name: "Token", + fields: StorageLayoutFields { + decimals: aztec::state_vars::Storable { + slot: 0x0a, + }, + symbol: aztec::state_vars::Storable { + slot: 0x06, + }, + total_supply: aztec::state_vars::Storable { + slot: 0x04, + }, + minters: aztec::state_vars::Storable { + slot: 0x02, + }, + public_balances: aztec::state_vars::Storable { + slot: 0x05, + }, + admin: aztec::state_vars::Storable { + slot: 0x01, + }, + name: aztec::state_vars::Storable { + slot: 0x08, + }, + balances: aztec::state_vars::Storable { + slot: 0x03, + }, + }, + }; + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call private_get_decimals. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn private_get_decimals() -> pub u8; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call get_admin. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn get_admin() -> Field; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call is_minter. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn is_minter(minter: AztecAddress) -> bool; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call total_supply. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn total_supply() -> u128; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call balance_of_public. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn balance_of_public(owner: AztecAddress) -> u128; + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call set_minter. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn set_minter(minter: AztecAddress, approve: bool); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call mint_to_public. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn mint_to_public(to: AztecAddress, amount: u128); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call transfer_in_public. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn transfer_in_public(from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call burn_public. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn burn_public(from: AztecAddress, amount: u128, authwit_nonce: Field); + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call transfer_to_public. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn transfer_to_public(from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field); + + /// Transfers tokens from private balance of `from` to public balance of `to` and prepares a partial note for + /// receiving change for `from`. + /// + /// This is an optimization that combines two operations into one to reduce contract calls: + /// 1. Transfers `amount` tokens from `from`'s private balance to `to`'s public balance + /// 2. Creates a partial note that can later be used to receive change back to `from`'s private balance + /// + /// This pattern is useful when interacting with contracts that: + /// - Receive tokens from a user's private balance + /// - Need to wait until public execution to determine how many tokens to return (e.g. AMM, FPC) + /// - Will return tokens to the user's private balance + /// + /// The contract can use the returned partial note to complete the transfer back to private + /// once the final amount is known during public execution. + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call transfer_to_public_and_prepare_private_balance_increase. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn transfer_to_public_and_prepare_private_balance_increase(from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> PartialUintNote; + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call transfer. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn transfer(to: AztecAddress, amount: u128); + + #[deprecated(deny, "Direct invocation of private internal functions is not supported. You attempted to call subtract_balance. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn subtract_balance(account: AztecAddress, amount: u128, max_notes: u32) -> u128; + + #[no_predicates] + #[contract_library_method] + fn compute_recurse_subtract_balance_call(context: PrivateContext, account: AztecAddress, remaining: u128) -> PrivateCall<25, 2, u128> { + Token::at(context.this_address())._recurse_subtract_balance(account, remaining) + } + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call _recurse_subtract_balance. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _recurse_subtract_balance(account: AztecAddress, amount: u128) -> u128; + + /// Cancel a private authentication witness. + /// @param inner_hash The inner hash of the authwit to cancel. + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call cancel_authwit. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn cancel_authwit(inner_hash: Field); + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call transfer_in_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn transfer_in_private(from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field); + + /// Mirrors `transfer_in_private` but delivers the resulting notes via offchain messages. + /// + /// Offchain messages are returned to the caller as encrypted payloads. The sender is responsible for getting the + /// recipient's note to them (typically by encoding it into a link, QR code, or direct message). The recipient + /// ingests it by calling `offchain_receive` on their environment. + /// + /// A `Transfer` event is also emitted to be delivered offchain. + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call transfer_in_private_with_offchain_delivery. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn transfer_in_private_with_offchain_delivery(from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field); + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call burn_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn burn_private(from: AztecAddress, amount: u128, authwit_nonce: Field); + + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call transfer_to_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn transfer_to_private(to: AztecAddress, amount: u128); + + /// Prepares an increase of private balance of `to` (partial note). The increase needs to be finalized by calling + /// some of the finalization functions (`finalize_transfer_to_private`, `finalize_mint_to_private`) with the + /// returned partial note. + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call prepare_private_balance_increase. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn prepare_private_balance_increase(to: AztecAddress) -> PartialUintNote; + + /// This function exists separately from `prepare_private_balance_increase` solely as an optimization as it allows + /// us to have it inlined in the `transfer_to_private` function which results in one fewer kernel iteration. Note + /// that in this case we don't pass `completer` as an argument to this function because in all the callsites we + /// want to use the message sender as the completer anyway. + #[deprecated(deny, "Direct invocation of private internal functions is not supported. You attempted to call _prepare_private_balance_increase. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _prepare_private_balance_increase(to: AztecAddress) -> PartialUintNote; + + /// Finalizes a transfer of token `amount` from public balance of `msg_sender` to a private balance of `to`. + /// The transfer must be prepared by calling `prepare_private_balance_increase` from `msg_sender` account and + /// the resulting `partial_note` must be passed as an argument to this function. + /// + /// Note that this contract does not protect against a `partial_note` being used multiple times and it is up to + /// the caller of this function to ensure that it doesn't happen. If the same `partial_note` is used multiple + /// times, the token `amount` would most likely get lost (the partial note log processing functionality would fail + /// to find the pending partial note when trying to complete it). + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call finalize_transfer_to_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn finalize_transfer_to_private(amount: u128, partial_note: PartialUintNote); + + /// Finalizes a transfer of token `amount` from private balance of `from` to a private balance of `to`. + /// The transfer must be prepared by calling `prepare_private_balance_increase` from `from` account and + /// the resulting `partial_note` must be passed as an argument to this function. + /// + /// Note that this contract does not protect against a `partial_note` being used multiple times and it is up to + /// the caller of this function to ensure that it doesn't happen. If the same `partial_note` is used multiple + /// times, the token `amount` would most likely get lost (the partial note log processing functionality would fail + /// to find the pending partial note when trying to complete it). + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call finalize_transfer_to_private_from_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn finalize_transfer_to_private_from_private(from: AztecAddress, partial_note: PartialUintNote, amount: u128, authwit_nonce: Field); + + /// This is a wrapper around `_finalize_transfer_to_private` placed here so that a call + /// to `_finalize_transfer_to_private` can be enqueued. Called unsafe as it does not check `from_and_completer` + /// (this has to be done in the calling function). + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call _finalize_transfer_to_private_unsafe. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _finalize_transfer_to_private_unsafe(from_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote); + + #[deprecated(deny, "Direct invocation of public internal functions is not supported. You attempted to call _finalize_transfer_to_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _finalize_transfer_to_private(from_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote); + + /// Mints token `amount` to a private balance of `to`. Message sender has to have minter permissions (checked + /// in the enqueued call). + #[deprecated(deny, "Direct invocation of private functions is not supported. You attempted to call mint_to_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn mint_to_private(to: AztecAddress, amount: u128); + + /// Finalizes a mint of token `amount` to a private balance of `to`. The mint must be prepared by calling + /// `prepare_private_balance_increase` first and the resulting + /// `partial_note` must be passed as an argument to this function. + /// + /// Note: This function is only an optimization as it could be replaced by a combination of `mint_to_public` + /// and `finalize_transfer_to_private`. It is however used very commonly so it makes sense to optimize it + /// (e.g. used during token bridging, in AMM liquidity token etc.). + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call finalize_mint_to_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn finalize_mint_to_private(amount: u128, partial_note: PartialUintNote); + + /// This is a wrapper around `_finalize_mint_to_private` placed here so that a call + /// to `_finalize_mint_to_private` can be enqueued. Called unsafe as it does not check `minter_and_completer` (this + /// has to be done in the calling function). + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call _finalize_mint_to_private_unsafe. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _finalize_mint_to_private_unsafe(minter_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote); + + #[deprecated(deny, "Direct invocation of public internal functions is not supported. You attempted to call _finalize_mint_to_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _finalize_mint_to_private(completer: AztecAddress, amount: u128, partial_note: PartialUintNote); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call _increase_public_balance. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _increase_public_balance(to: AztecAddress, amount: u128); + + #[deprecated(deny, "Direct invocation of public functions is not supported. You attempted to call _reduce_total_supply. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + fn _reduce_total_supply(amount: u128); + + #[deprecated(deny, "Direct invocation of utility functions is not supported. You attempted to call balance_of_private. See https://docs.aztec.network/errors/6")] + #[contract_library_method] + unconstrained fn balance_of_private(owner: AztecAddress) -> u128; + + /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + #[allow(dead_code)] + unconstrained fn _compute_note_hash_and_nullifier(packed_note: BoundedVec, owner: AztecAddress, storage_slot: Field, note_type_id: Field, contract_address: AztecAddress, randomness: Field, note_nonce: Field) -> Option { + _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash: Field| -> aztec::messages::discovery::NoteHashAndNullifier { + let siloed_note_hash: Field = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash); + let unique_note_hash: Field = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash); + let inner_nullifier: Option = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness); + aztec::messages::discovery::NoteHashAndNullifier { note_hash: note_hash, inner_nullifier: inner_nullifier} + }) + } + + /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed). + /// + /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_hash(packed_note: BoundedVec, owner: AztecAddress, storage_slot: Field, note_type_id: Field, _contract_address: AztecAddress, randomness: Field) -> Option { + if note_type_id == ::get_id() { + let expected_len: u32 = ::N; + let actual_len: u32 = packed_note.len(); + if actual_len != expected_len { + (|args: [Field; 3]| aztec::oracle::logging::warn_log_format("[aztec-nr] Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.", args))([note_type_id, expected_len as Field, actual_len as Field]); + Option::::none() + } else { + let note: UintNote = ::unpack(aztec::utils::array::subarray::subarray(packed_note.storage(), 0_u32)); + Option::::some(::compute_note_hash(note, owner, storage_slot, randomness)) + } + } else { + (|args: [Field; 1]| aztec::oracle::logging::warn_log_format("[aztec-nr] Unknown note type id {0}. Skipping note.", args))([note_type_id]); + Option::::none() + } + } + + /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data. + /// + /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + #[contract_library_method] + unconstrained fn _compute_note_nullifier(unique_note_hash: Field, packed_note: BoundedVec, owner: AztecAddress, _storage_slot: Field, note_type_id: Field, _contract_address: AztecAddress, _randomness: Field) -> Option { + if note_type_id == ::get_id() { + let expected_len: u32 = ::N; + let actual_len: u32 = packed_note.len(); + if actual_len != expected_len { + (|args: [Field; 3]| aztec::oracle::logging::warn_log_format("[aztec-nr] Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.", args))([note_type_id, expected_len as Field, actual_len as Field]); + Option::::none() + } else { + let note: UintNote = ::unpack(aztec::utils::array::subarray::subarray(packed_note.storage(), 0_u32)); + ::compute_nullifier_unconstrained(note, owner, unique_note_hash) + } + } else { + (|args: [Field; 1]| aztec::oracle::logging::warn_log_format("[aztec-nr] Unknown note type id {0}. Skipping note.", args))([note_type_id]); + Option::::none() + } + } + + /// Receives offchain messages into this contract's offchain inbox for subsequent processing. + /// + /// Each message is routed to the inbox scoped to its `recipient` field. + /// + /// For more details, see `aztec::messages::processing::offchain::receive`. + /// + /// This function is automatically injected by the `#[aztec]` macro. + unconstrained fn offchain_receive(messages: BoundedVec) { + let address: AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::processing::offchain::receive(address, messages); + } + + pub struct Token { + pub target_contract: AztecAddress, + } + + impl Token { + pub fn storage_layout() -> StorageLayoutFields { + STORAGE_LAYOUT_Token.fields + } + + pub fn at(addr: AztecAddress) -> Self { + Self { target_contract: addr} + } + + pub fn interface() -> Self { + Self { target_contract: AztecAddress::zero()} + } + + pub fn burn_public(self, from: AztecAddress, amount: u128, authwit_nonce: Field) -> aztec::context::calls::PublicCall<11, 3, ()> { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3323048133_Field); + aztec::context::calls::PublicCall::<11, 3, ()>::new(self.target_contract, selector, "burn_public", serialized_params) + } + + pub fn transfer(self, to: AztecAddress, amount: u128) -> PrivateCall<8, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1968158567_Field); + PrivateCall::<8, 2, ()>::new(self.target_contract, selector, "transfer", serialized_params) + } + + pub fn finalize_transfer_to_private_from_private(self, from: AztecAddress, partial_note: PartialUintNote, amount: u128, authwit_nonce: Field) -> PrivateCall<41, 4, ()> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4221842038_Field); + PrivateCall::<41, 4, ()>::new(self.target_contract, selector, "finalize_transfer_to_private_from_private", serialized_params) + } + + pub fn mint_to_public(self, to: AztecAddress, amount: u128) -> aztec::context::calls::PublicCall<14, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1159421870_Field); + aztec::context::calls::PublicCall::<14, 2, ()>::new(self.target_contract, selector, "mint_to_public", serialized_params) + } + + pub fn is_minter(self, minter: AztecAddress) -> aztec::context::calls::PublicStaticCall<9, 1, bool> { + let serialized_params: [Field; 1] = ::serialize(minter); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3315237398_Field); + aztec::context::calls::PublicStaticCall::<9, 1, bool>::new(self.target_contract, selector, "is_minter", serialized_params) + } + + pub fn cancel_authwit(self, inner_hash: Field) -> PrivateCall<14, 1, ()> { + let serialized_params: [Field; 1] = ::serialize(inner_hash); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3755840242_Field); + PrivateCall::<14, 1, ()>::new(self.target_contract, selector, "cancel_authwit", serialized_params) + } + + pub fn set_admin(self, new_admin: AztecAddress) -> aztec::context::calls::PublicCall<9, 1, ()> { + let serialized_params: [Field; 1] = ::serialize(new_admin); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2519591682_Field); + aztec::context::calls::PublicCall::<9, 1, ()>::new(self.target_contract, selector, "set_admin", serialized_params) + } + + pub fn total_supply(self) -> aztec::context::calls::PublicStaticCall<12, 0, u128> { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2379449068_Field); + aztec::context::calls::PublicStaticCall::<12, 0, u128>::new(self.target_contract, selector, "total_supply", serialized_params) + } + + pub fn private_get_decimals(self) -> aztec::context::calls::PrivateStaticCall<20, 0, u8> { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2520508119_Field); + aztec::context::calls::PrivateStaticCall::<20, 0, u8>::new(self.target_contract, selector, "private_get_decimals", serialized_params) + } + + pub fn get_admin(self) -> aztec::context::calls::PublicStaticCall<9, 0, Field> { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(722579866_Field); + aztec::context::calls::PublicStaticCall::<9, 0, Field>::new(self.target_contract, selector, "get_admin", serialized_params) + } + + pub fn transfer_to_public(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> PrivateCall<18, 4, ()> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3880081865_Field); + PrivateCall::<18, 4, ()>::new(self.target_contract, selector, "transfer_to_public", serialized_params) + } + + pub fn transfer_in_private_with_offchain_delivery(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> PrivateCall<42, 4, ()> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2994585803_Field); + PrivateCall::<42, 4, ()>::new(self.target_contract, selector, "transfer_in_private_with_offchain_delivery", serialized_params) + } + + pub fn mint_to_private(self, to: AztecAddress, amount: u128) -> PrivateCall<15, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4177019161_Field); + PrivateCall::<15, 2, ()>::new(self.target_contract, selector, "mint_to_private", serialized_params) + } + + pub fn transfer_to_private(self, to: AztecAddress, amount: u128) -> PrivateCall<19, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2306181952_Field); + PrivateCall::<19, 2, ()>::new(self.target_contract, selector, "transfer_to_private", serialized_params) + } + + pub fn public_get_name(self) -> aztec::context::calls::PublicStaticCall<15, 0, FieldCompressedString> { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3367753652_Field); + aztec::context::calls::PublicStaticCall::<15, 0, FieldCompressedString>::new(self.target_contract, selector, "public_get_name", serialized_params) + } + + pub fn _recurse_subtract_balance(self, account: AztecAddress, amount: u128) -> PrivateCall<25, 2, u128> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(account); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1536394406_Field); + PrivateCall::<25, 2, u128>::new(self.target_contract, selector, "_recurse_subtract_balance", serialized_params) + } + + pub fn _finalize_transfer_to_private_unsafe(self, from_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) -> aztec::context::calls::PublicCall<36, 3, ()> { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from_and_completer); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1930102437_Field); + aztec::context::calls::PublicCall::<36, 3, ()>::new(self.target_contract, selector, "_finalize_transfer_to_private_unsafe", serialized_params) + } + + pub fn constructor(self, admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) -> aztec::context::calls::PublicCall<11, 64, ()> { + let mut serialized_params: [Field; 64] = [0_Field; 64]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(admin); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 31] = as aztec::protocol::traits::Serialize>::serialize(name); + let serialized_member_len: u32 = as aztec::protocol::traits::Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 31] = as aztec::protocol::traits::Serialize>::serialize(symbol); + let serialized_member_len: u32 = as aztec::protocol::traits::Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(decimals); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1578322623_Field); + aztec::context::calls::PublicCall::<11, 64, ()>::new(self.target_contract, selector, "constructor", serialized_params) + } + + pub fn finalize_transfer_to_private(self, amount: u128, partial_note: PartialUintNote) -> aztec::context::calls::PublicCall<28, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2599745508_Field); + aztec::context::calls::PublicCall::<28, 2, ()>::new(self.target_contract, selector, "finalize_transfer_to_private", serialized_params) + } + + pub fn finalize_mint_to_private(self, amount: u128, partial_note: PartialUintNote) -> aztec::context::calls::PublicCall<24, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1065137297_Field); + aztec::context::calls::PublicCall::<24, 2, ()>::new(self.target_contract, selector, "finalize_mint_to_private", serialized_params) + } + + pub fn _reduce_total_supply(self, amount: u128) -> aztec::context::calls::PublicCall<20, 1, ()> { + let serialized_params: [Field; 1] = ::serialize(amount); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2253390209_Field); + aztec::context::calls::PublicCall::<20, 1, ()>::new(self.target_contract, selector, "_reduce_total_supply", serialized_params) + } + + pub fn transfer_in_public(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> aztec::context::calls::PublicCall<18, 4, ()> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2359186546_Field); + aztec::context::calls::PublicCall::<18, 4, ()>::new(self.target_contract, selector, "transfer_in_public", serialized_params) + } + + pub fn prepare_private_balance_increase(self, to: AztecAddress) -> PrivateCall<32, 1, PartialUintNote> { + let serialized_params: [Field; 1] = ::serialize(to); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1824243228_Field); + PrivateCall::<32, 1, PartialUintNote>::new(self.target_contract, selector, "prepare_private_balance_increase", serialized_params) + } + + pub fn transfer_to_public_and_prepare_private_balance_increase(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> PrivateCall<55, 4, PartialUintNote> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2936463891_Field); + PrivateCall::<55, 4, PartialUintNote>::new(self.target_contract, selector, "transfer_to_public_and_prepare_private_balance_increase", serialized_params) + } + + pub fn balance_of_public(self, owner: AztecAddress) -> aztec::context::calls::PublicStaticCall<17, 1, u128> { + let serialized_params: [Field; 1] = ::serialize(owner); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4286138866_Field); + aztec::context::calls::PublicStaticCall::<17, 1, u128>::new(self.target_contract, selector, "balance_of_public", serialized_params) + } + + pub fn set_minter(self, minter: AztecAddress, approve: bool) -> aztec::context::calls::PublicCall<10, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(minter); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(approve); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1957439757_Field); + aztec::context::calls::PublicCall::<10, 2, ()>::new(self.target_contract, selector, "set_minter", serialized_params) + } + + pub fn _finalize_mint_to_private_unsafe(self, minter_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) -> aztec::context::calls::PublicCall<32, 3, ()> { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(minter_and_completer); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4058507562_Field); + aztec::context::calls::PublicCall::<32, 3, ()>::new(self.target_contract, selector, "_finalize_mint_to_private_unsafe", serialized_params) + } + + pub fn private_get_symbol(self) -> aztec::context::calls::PrivateStaticCall<18, 0, FieldCompressedString> { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1295669651_Field); + aztec::context::calls::PrivateStaticCall::<18, 0, FieldCompressedString>::new(self.target_contract, selector, "private_get_symbol", serialized_params) + } + + pub fn private_get_name(self) -> aztec::context::calls::PrivateStaticCall<16, 0, FieldCompressedString> { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3516522363_Field); + aztec::context::calls::PrivateStaticCall::<16, 0, FieldCompressedString>::new(self.target_contract, selector, "private_get_name", serialized_params) + } + + pub fn transfer_in_private(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> PrivateCall<19, 4, ()> { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3610465468_Field); + PrivateCall::<19, 4, ()>::new(self.target_contract, selector, "transfer_in_private", serialized_params) + } + + pub fn public_get_decimals(self) -> aztec::context::calls::PublicStaticCall<19, 0, u8> { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1613003496_Field); + aztec::context::calls::PublicStaticCall::<19, 0, u8>::new(self.target_contract, selector, "public_get_decimals", serialized_params) + } + + pub fn burn_private(self, from: AztecAddress, amount: u128, authwit_nonce: Field) -> PrivateCall<12, 3, ()> { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3263360377_Field); + PrivateCall::<12, 3, ()>::new(self.target_contract, selector, "burn_private", serialized_params) + } + + pub fn _increase_public_balance(self, to: AztecAddress, amount: u128) -> aztec::context::calls::PublicCall<24, 2, ()> { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3891283455_Field); + aztec::context::calls::PublicCall::<24, 2, ()>::new(self.target_contract, selector, "_increase_public_balance", serialized_params) + } + + pub fn public_get_symbol(self) -> aztec::context::calls::PublicStaticCall<17, 0, FieldCompressedString> { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3454394185_Field); + aztec::context::calls::PublicStaticCall::<17, 0, FieldCompressedString>::new(self.target_contract, selector, "public_get_symbol", serialized_params) + } + + pub fn balance_of_private(self, owner: AztecAddress) -> aztec::context::calls::UtilityCall<18, 1, u128> { + let serialized_params: [Field; 1] = ::serialize(owner); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1131770492_Field); + aztec::context::calls::UtilityCall::<18, 1, u128>::new(self.target_contract, selector, "balance_of_private", serialized_params) + } + + pub fn offchain_receive(self, messages: BoundedVec) -> aztec::context::calls::UtilityCall<16, 321, ()> { + let serialized_params: [Field; 321] = as aztec::protocol::traits::Serialize>::serialize(messages); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1396850735_Field); + aztec::context::calls::UtilityCall::<16, 321, ()>::new(self.target_contract, selector, "offchain_receive", serialized_params) + } + } + + #[contract_library_method] + pub fn storage_layout() -> StorageLayoutFields { + STORAGE_LAYOUT_Token.fields + } + + #[contract_library_method] + pub fn at(addr: AztecAddress) -> Token { + Token { target_contract: addr} + } + + #[contract_library_method] + pub fn interface() -> Token { + Token { target_contract: AztecAddress::zero()} + } + + pub struct sync_state_parameters { + pub scope: AztecAddress, + } + + #[abi(functions)] + pub struct sync_state_abi { + parameters: sync_state_parameters, + } + + unconstrained fn sync_state(scope: AztecAddress) { + let address: AztecAddress = aztec::context::UtilityContext::new().this_address(); + aztec::messages::discovery::do_sync_state(address, _compute_note_hash, _compute_note_nullifier, Option::>::none(), Option:: aztec::ephemeral::EphemeralArray>::some(aztec::messages::processing::offchain::sync_inbox), scope); + } + + pub struct offchain_receive_parameters { + pub messages: BoundedVec, + } + + #[abi(functions)] + pub struct offchain_receive_abi { + parameters: offchain_receive_parameters, + } + + pub struct CallSelf { + pub address: AztecAddress, + pub context: Context, + } + + impl CallSelf { + pub fn burn_public(self, from: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3323048133_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<11, 3, ()>::new(self.address, selector, "burn_public", serialized_params).call(self.context) + } + } + + pub fn _finalize_transfer_to_private_unsafe(self, from_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from_and_completer); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1930102437_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<36, 3, ()>::new(self.address, selector, "_finalize_transfer_to_private_unsafe", serialized_params).call(self.context) + } + } + + pub fn constructor(self, admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { + let mut serialized_params: [Field; 64] = [0_Field; 64]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(admin); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 31] = as aztec::protocol::traits::Serialize>::serialize(name); + let serialized_member_len: u32 = as aztec::protocol::traits::Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 31] = as aztec::protocol::traits::Serialize>::serialize(symbol); + let serialized_member_len: u32 = as aztec::protocol::traits::Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(decimals); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1578322623_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<11, 64, ()>::new(self.address, selector, "constructor", serialized_params).call(self.context) + } + } + + pub fn mint_to_public(self, to: AztecAddress, amount: u128) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1159421870_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<14, 2, ()>::new(self.address, selector, "mint_to_public", serialized_params).call(self.context) + } + } + + pub fn finalize_transfer_to_private(self, amount: u128, partial_note: PartialUintNote) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2599745508_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<28, 2, ()>::new(self.address, selector, "finalize_transfer_to_private", serialized_params).call(self.context) + } + } + + pub fn finalize_mint_to_private(self, amount: u128, partial_note: PartialUintNote) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1065137297_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<24, 2, ()>::new(self.address, selector, "finalize_mint_to_private", serialized_params).call(self.context) + } + } + + pub fn transfer_in_public(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2359186546_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<18, 4, ()>::new(self.address, selector, "transfer_in_public", serialized_params).call(self.context) + } + } + + pub fn _reduce_total_supply(self, amount: u128) { + let serialized_params: [Field; 1] = ::serialize(amount); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2253390209_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<20, 1, ()>::new(self.address, selector, "_reduce_total_supply", serialized_params).call(self.context) + } + } + + pub fn set_admin(self, new_admin: AztecAddress) { + let serialized_params: [Field; 1] = ::serialize(new_admin); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2519591682_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<9, 1, ()>::new(self.address, selector, "set_admin", serialized_params).call(self.context) + } + } + + pub fn set_minter(self, minter: AztecAddress, approve: bool) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(minter); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(approve); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1957439757_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<10, 2, ()>::new(self.address, selector, "set_minter", serialized_params).call(self.context) + } + } + + pub fn _finalize_mint_to_private_unsafe(self, minter_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(minter_and_completer); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4058507562_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<32, 3, ()>::new(self.address, selector, "_finalize_mint_to_private_unsafe", serialized_params).call(self.context) + } + } + + pub fn _increase_public_balance(self, to: AztecAddress, amount: u128) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3891283455_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicCall::<24, 2, ()>::new(self.address, selector, "_increase_public_balance", serialized_params).call(self.context) + } + } + } + + impl CallSelf<&mut PrivateContext> { + pub fn _recurse_subtract_balance(self, account: AztecAddress, amount: u128) -> u128 { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(account); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1536394406_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn transfer(self, to: AztecAddress, amount: u128) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1968158567_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn finalize_transfer_to_private_from_private(self, from: AztecAddress, partial_note: PartialUintNote, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4221842038_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn prepare_private_balance_increase(self, to: AztecAddress) -> PartialUintNote { + let serialized_params: [Field; 1] = ::serialize(to); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1824243228_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn transfer_to_public_and_prepare_private_balance_increase(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> PartialUintNote { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2936463891_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn cancel_authwit(self, inner_hash: Field) { + let serialized_params: [Field; 1] = ::serialize(inner_hash); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3755840242_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn transfer_in_private(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3610465468_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn burn_private(self, from: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3263360377_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn transfer_to_public(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3880081865_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn transfer_in_private_with_offchain_delivery(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2994585803_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn mint_to_private(self, to: AztecAddress, amount: u128) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4177019161_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + + pub fn transfer_to_private(self, to: AztecAddress, amount: u128) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2306181952_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, false); + returns_hash.get_preimage() + } + } + + pub struct CallSelfStatic { + pub address: AztecAddress, + pub context: Context, + } + + impl CallSelfStatic { + pub fn balance_of_public(self, owner: AztecAddress) -> u128 { + let serialized_params: [Field; 1] = ::serialize(owner); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4286138866_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<17, 1, u128>::new(self.address, selector, "balance_of_public", serialized_params).view(self.context) + } + } + + pub fn total_supply(self) -> u128 { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2379449068_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<12, 0, u128>::new(self.address, selector, "total_supply", serialized_params).view(self.context) + } + } + + pub fn public_get_name(self) -> FieldCompressedString { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3367753652_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<15, 0, FieldCompressedString>::new(self.address, selector, "public_get_name", serialized_params).view(self.context) + } + } + + pub fn public_get_decimals(self) -> u8 { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1613003496_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<19, 0, u8>::new(self.address, selector, "public_get_decimals", serialized_params).view(self.context) + } + } + + pub fn get_admin(self) -> Field { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(722579866_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<9, 0, Field>::new(self.address, selector, "get_admin", serialized_params).view(self.context) + } + } + + pub fn public_get_symbol(self) -> FieldCompressedString { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3454394185_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<17, 0, FieldCompressedString>::new(self.address, selector, "public_get_symbol", serialized_params).view(self.context) + } + } + + pub fn is_minter(self, minter: AztecAddress) -> bool { + let serialized_params: [Field; 1] = ::serialize(minter); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3315237398_Field); + // Safety: comment added by `nargo expand` + unsafe { + aztec::context::calls::PublicStaticCall::<9, 1, bool>::new(self.address, selector, "is_minter", serialized_params).view(self.context) + } + } + } + + impl CallSelfStatic<&mut PrivateContext> { + pub fn private_get_name(self) -> FieldCompressedString { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3516522363_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, true); + returns_hash.get_preimage() + } + + pub fn private_get_symbol(self) -> FieldCompressedString { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1295669651_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, true); + returns_hash.get_preimage() + } + + pub fn private_get_decimals(self) -> u8 { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2520508119_Field); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + aztec::oracle::execution_cache::store(serialized_params, args_hash); + let returns_hash: aztec::context::ReturnsHash = self.context.call_private_function_with_args_hash(self.address, selector, args_hash, true); + returns_hash.get_preimage() + } + } + + pub struct EnqueueSelf { + pub address: AztecAddress, + pub context: Context, + } + + impl EnqueueSelf<&mut PrivateContext> { + pub fn set_minter(self, minter: AztecAddress, approve: bool) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(minter); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(approve); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1957439757_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn burn_public(self, from: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3323048133_Field); + let calldata: [Field; 1 + 3] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn _finalize_transfer_to_private_unsafe(self, from_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from_and_completer); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1930102437_Field); + let calldata: [Field; 1 + 3] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn _finalize_mint_to_private_unsafe(self, minter_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(minter_and_completer); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4058507562_Field); + let calldata: [Field; 1 + 3] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn mint_to_public(self, to: AztecAddress, amount: u128) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1159421870_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn finalize_transfer_to_private(self, amount: u128, partial_note: PartialUintNote) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2599745508_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn constructor(self, admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { + let mut serialized_params: [Field; 64] = [0_Field; 64]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(admin); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 31] = as aztec::protocol::traits::Serialize>::serialize(name); + let serialized_member_len: u32 = as aztec::protocol::traits::Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 31] = as aztec::protocol::traits::Serialize>::serialize(symbol); + let serialized_member_len: u32 = as aztec::protocol::traits::Serialize>::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(decimals); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1578322623_Field); + let calldata: [Field; 1 + 64] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn finalize_mint_to_private(self, amount: u128, partial_note: PartialUintNote) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1065137297_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn _increase_public_balance(self, to: AztecAddress, amount: u128) { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3891283455_Field); + let calldata: [Field; 1 + 2] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn transfer_in_public(self, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2359186546_Field); + let calldata: [Field; 1 + 4] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn _reduce_total_supply(self, amount: u128) { + let serialized_params: [Field; 1] = ::serialize(amount); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2253390209_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + + pub fn set_admin(self, new_admin: AztecAddress) { + let serialized_params: [Field; 1] = ::serialize(new_admin); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2519591682_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, false, false); + } + } + + pub struct EnqueueSelfStatic { + pub address: AztecAddress, + pub context: Context, + } + + impl EnqueueSelfStatic<&mut PrivateContext> { + pub fn public_get_name(self) { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3367753652_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + + pub fn public_get_decimals(self) { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1613003496_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + + pub fn get_admin(self) { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(722579866_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + + pub fn balance_of_public(self, owner: AztecAddress) { + let serialized_params: [Field; 1] = ::serialize(owner); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(4286138866_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + + pub fn total_supply(self) { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(2379449068_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + + pub fn public_get_symbol(self) { + let serialized_params: [Field; 0] = []; + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3454394185_Field); + let calldata: [Field; 1 + 0] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + + pub fn is_minter(self, minter: AztecAddress) { + let serialized_params: [Field; 1] = ::serialize(minter); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(3315237398_Field); + let calldata: [Field; 1 + 1] = [selector.to_field()].concat(serialized_params); + let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata); + aztec::oracle::execution_cache::store(calldata, calldata_hash); + self.context.call_public_function_with_calldata_hash(self.address, calldata_hash, true, false); + } + } + + pub struct CallSelfUtility { + pub address: AztecAddress, + } + + impl CallSelfUtility { + pub unconstrained fn balance_of_private(self, owner: AztecAddress) -> u128 { + let serialized_params: [Field; 1] = ::serialize(owner); + let selector: aztec::protocol::abis::function_selector::FunctionSelector = ::from_field(1131770492_Field); + let returns: [Field; 1] = aztec::oracle::call_utility_function::call_utility_function(self.address, selector, serialized_params); + ::deserialize(returns) + } + } + + pub struct CallInternal { + pub context: Context, + } + + impl CallInternal { + pub unconstrained fn _finalize_mint_to_private(self, completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + __aztec_nr_internals___finalize_mint_to_private(self.context, completer, amount, partial_note) + } + + pub unconstrained fn _finalize_transfer_to_private(self, from_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + __aztec_nr_internals___finalize_transfer_to_private(self.context, from_and_completer, amount, partial_note) + } + } + + impl CallInternal<&mut PrivateContext> { + pub fn subtract_balance(self, account: AztecAddress, amount: u128, max_notes: u32) -> u128 { + __aztec_nr_internals__subtract_balance(self.context, account, amount, max_notes) + } + + pub fn _prepare_private_balance_increase(self, to: AztecAddress) -> PartialUintNote { + __aztec_nr_internals___prepare_private_balance_increase(self.context, to) + } + } + + pub unconstrained fn public_dispatch(selector: Field) { + if selector == 1578322623_Field { + let input_calldata: [Field; 64] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + as aztec::protocol::traits::Serialize>::N) + as aztec::protocol::traits::Serialize>::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<64> = aztec::protocol::utils::reader::Reader::<64>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: str<31> = as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let arg2: str<31> = as aztec::protocol::traits::Deserialize>::stream_deserialize(&mut reader); + let arg3: u8 = ::stream_deserialize(&mut reader); + __aztec_nr_internals__constructor(arg0, arg1, arg2, arg3); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2519591682_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + __aztec_nr_internals__set_admin(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3367753652_Field { + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__public_get_name()); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3454394185_Field { + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__public_get_symbol()); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1613003496_Field { + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__public_get_decimals()); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 722579866_Field { + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__get_admin()); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 3315237398_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__is_minter(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 2379449068_Field { + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__total_supply()); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 4286138866_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let return_value: [Field; 1] = ::serialize(__aztec_nr_internals__balance_of_public(arg0)); + aztec::oracle::avm::avm_return(return_value.as_vector()); + }; + if selector == 1957439757_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: bool = ::stream_deserialize(&mut reader); + __aztec_nr_internals__set_minter(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1159421870_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: u128 = ::stream_deserialize(&mut reader); + __aztec_nr_internals__mint_to_public(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2359186546_Field { + let input_calldata: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + ::N) + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<4> = aztec::protocol::utils::reader::Reader::<4>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: AztecAddress = ::stream_deserialize(&mut reader); + let arg2: u128 = ::stream_deserialize(&mut reader); + let arg3: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__transfer_in_public(arg0, arg1, arg2, arg3); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3323048133_Field { + let input_calldata: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (::N + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<3> = aztec::protocol::utils::reader::Reader::<3>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: u128 = ::stream_deserialize(&mut reader); + let arg2: Field = ::stream_deserialize(&mut reader); + __aztec_nr_internals__burn_public(arg0, arg1, arg2); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2599745508_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: u128 = ::stream_deserialize(&mut reader); + let arg1: PartialUintNote = ::stream_deserialize(&mut reader); + __aztec_nr_internals__finalize_transfer_to_private(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1930102437_Field { + let input_calldata: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (::N + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<3> = aztec::protocol::utils::reader::Reader::<3>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: u128 = ::stream_deserialize(&mut reader); + let arg2: PartialUintNote = ::stream_deserialize(&mut reader); + __aztec_nr_internals___finalize_transfer_to_private_unsafe(arg0, arg1, arg2); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 1065137297_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: u128 = ::stream_deserialize(&mut reader); + let arg1: PartialUintNote = ::stream_deserialize(&mut reader); + __aztec_nr_internals__finalize_mint_to_private(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 4058507562_Field { + let input_calldata: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (::N + ::N) + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<3> = aztec::protocol::utils::reader::Reader::<3>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: u128 = ::stream_deserialize(&mut reader); + let arg2: PartialUintNote = ::stream_deserialize(&mut reader); + __aztec_nr_internals___finalize_mint_to_private_unsafe(arg0, arg1, arg2); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 3891283455_Field { + let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + let mut reader: aztec::protocol::utils::reader::Reader<2> = aztec::protocol::utils::reader::Reader::<2>::new(input_calldata); + let arg0: AztecAddress = ::stream_deserialize(&mut reader); + let arg1: u128 = ::stream_deserialize(&mut reader); + __aztec_nr_internals___increase_public_balance(arg0, arg1); + aztec::oracle::avm::avm_return([].as_slice()); + }; + if selector == 2253390209_Field { + let input_calldata: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + let mut reader: aztec::protocol::utils::reader::Reader<1> = aztec::protocol::utils::reader::Reader::<1>::new(input_calldata); + let arg0: u128 = ::stream_deserialize(&mut reader); + __aztec_nr_internals___reduce_total_supply(arg0); + aztec::oracle::avm::avm_return([].as_slice()); + }; + panic(f"Unknown selector {selector}") + } + + pub struct _finalize_mint_to_private_unsafe_parameters { + pub minter_and_completer: AztecAddress, + pub amount: u128, + pub partial_note: PartialUintNote, + } + + pub struct _finalize_transfer_to_private_unsafe_parameters { + pub from_and_completer: AztecAddress, + pub amount: u128, + pub partial_note: PartialUintNote, + } + + pub struct _increase_public_balance_parameters { + pub to: AztecAddress, + pub amount: u128, + } + + pub struct _recurse_subtract_balance_parameters { + pub account: AztecAddress, + pub amount: u128, + } + + pub struct _reduce_total_supply_parameters { + pub amount: u128, + } + + pub struct balance_of_private_parameters { + pub owner: AztecAddress, + } + + pub struct balance_of_public_parameters { + pub owner: AztecAddress, + } + + pub struct burn_private_parameters { + pub from: AztecAddress, + pub amount: u128, + pub authwit_nonce: Field, + } + + pub struct burn_public_parameters { + pub from: AztecAddress, + pub amount: u128, + pub authwit_nonce: Field, + } + + pub struct cancel_authwit_parameters { + pub inner_hash: Field, + } + + pub struct constructor_parameters { + pub admin: AztecAddress, + pub name: str<31>, + pub symbol: str<31>, + pub decimals: u8, + } + + pub struct finalize_mint_to_private_parameters { + pub amount: u128, + pub partial_note: PartialUintNote, + } + + pub struct finalize_transfer_to_private_from_private_parameters { + pub from: AztecAddress, + pub partial_note: PartialUintNote, + pub amount: u128, + pub authwit_nonce: Field, + } + + pub struct finalize_transfer_to_private_parameters { + pub amount: u128, + pub partial_note: PartialUintNote, + } + + pub struct get_admin_parameters { + } + + pub struct is_minter_parameters { + pub minter: AztecAddress, + } + + pub struct mint_to_private_parameters { + pub to: AztecAddress, + pub amount: u128, + } + + pub struct mint_to_public_parameters { + pub to: AztecAddress, + pub amount: u128, + } + + pub struct prepare_private_balance_increase_parameters { + pub to: AztecAddress, + } + + pub struct private_get_decimals_parameters { + } + + pub struct private_get_name_parameters { + } + + pub struct private_get_symbol_parameters { + } + + pub struct public_get_decimals_parameters { + } + + pub struct public_get_name_parameters { + } + + pub struct public_get_symbol_parameters { + } + + pub struct set_admin_parameters { + pub new_admin: AztecAddress, + } + + pub struct set_minter_parameters { + pub minter: AztecAddress, + pub approve: bool, + } + + pub struct total_supply_parameters { + } + + pub struct transfer_in_private_parameters { + pub from: AztecAddress, + pub to: AztecAddress, + pub amount: u128, + pub authwit_nonce: Field, + } + + pub struct transfer_in_private_with_offchain_delivery_parameters { + pub from: AztecAddress, + pub to: AztecAddress, + pub amount: u128, + pub authwit_nonce: Field, + } + + pub struct transfer_in_public_parameters { + pub from: AztecAddress, + pub to: AztecAddress, + pub amount: u128, + pub authwit_nonce: Field, + } + + pub struct transfer_parameters { + pub to: AztecAddress, + pub amount: u128, + } + + pub struct transfer_to_private_parameters { + pub to: AztecAddress, + pub amount: u128, + } + + pub struct transfer_to_public_and_prepare_private_balance_increase_parameters { + pub from: AztecAddress, + pub to: AztecAddress, + pub amount: u128, + pub authwit_nonce: Field, + } + + pub struct transfer_to_public_parameters { + pub from: AztecAddress, + pub to: AztecAddress, + pub amount: u128, + pub authwit_nonce: Field, + } + + #[abi(functions)] + pub struct _finalize_mint_to_private_unsafe_abi { + parameters: _finalize_mint_to_private_unsafe_parameters, + } + + #[abi(functions)] + pub struct _finalize_transfer_to_private_unsafe_abi { + parameters: _finalize_transfer_to_private_unsafe_parameters, + } + + #[abi(functions)] + pub struct _increase_public_balance_abi { + parameters: _increase_public_balance_parameters, + } + + #[abi(functions)] + pub struct _recurse_subtract_balance_abi { + parameters: _recurse_subtract_balance_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct _reduce_total_supply_abi { + parameters: _reduce_total_supply_parameters, + } + + #[abi(functions)] + pub struct balance_of_private_abi { + parameters: balance_of_private_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct balance_of_public_abi { + parameters: balance_of_public_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct burn_private_abi { + parameters: burn_private_parameters, + } + + #[abi(functions)] + pub struct burn_public_abi { + parameters: burn_public_parameters, + } + + #[abi(functions)] + pub struct cancel_authwit_abi { + parameters: cancel_authwit_parameters, + } + + #[abi(functions)] + pub struct constructor_abi { + parameters: constructor_parameters, + } + + #[abi(functions)] + pub struct finalize_mint_to_private_abi { + parameters: finalize_mint_to_private_parameters, + } + + #[abi(functions)] + pub struct finalize_transfer_to_private_abi { + parameters: finalize_transfer_to_private_parameters, + } + + #[abi(functions)] + pub struct finalize_transfer_to_private_from_private_abi { + parameters: finalize_transfer_to_private_from_private_parameters, + } + + #[abi(functions)] + pub struct get_admin_abi { + parameters: get_admin_parameters, + return_type: Field, + } + + #[abi(functions)] + pub struct is_minter_abi { + parameters: is_minter_parameters, + return_type: bool, + } + + #[abi(functions)] + pub struct mint_to_private_abi { + parameters: mint_to_private_parameters, + } + + #[abi(functions)] + pub struct mint_to_public_abi { + parameters: mint_to_public_parameters, + } + + #[abi(functions)] + pub struct prepare_private_balance_increase_abi { + parameters: prepare_private_balance_increase_parameters, + return_type: PartialUintNote, + } + + #[abi(functions)] + pub struct private_get_decimals_abi { + parameters: private_get_decimals_parameters, + return_type: u8, + } + + #[abi(functions)] + pub struct private_get_name_abi { + parameters: private_get_name_parameters, + return_type: FieldCompressedString, + } + + #[abi(functions)] + pub struct private_get_symbol_abi { + parameters: private_get_symbol_parameters, + return_type: FieldCompressedString, + } + + #[abi(functions)] + pub struct public_get_decimals_abi { + parameters: public_get_decimals_parameters, + return_type: u8, + } + + #[abi(functions)] + pub struct public_get_name_abi { + parameters: public_get_name_parameters, + return_type: FieldCompressedString, + } + + #[abi(functions)] + pub struct public_get_symbol_abi { + parameters: public_get_symbol_parameters, + return_type: FieldCompressedString, + } + + #[abi(functions)] + pub struct set_admin_abi { + parameters: set_admin_parameters, + } + + #[abi(functions)] + pub struct set_minter_abi { + parameters: set_minter_parameters, + } + + #[abi(functions)] + pub struct total_supply_abi { + parameters: total_supply_parameters, + return_type: u128, + } + + #[abi(functions)] + pub struct transfer_abi { + parameters: transfer_parameters, + } + + #[abi(functions)] + pub struct transfer_in_private_abi { + parameters: transfer_in_private_parameters, + } + + #[abi(functions)] + pub struct transfer_in_private_with_offchain_delivery_abi { + parameters: transfer_in_private_with_offchain_delivery_parameters, + } + + #[abi(functions)] + pub struct transfer_in_public_abi { + parameters: transfer_in_public_parameters, + } + + #[abi(functions)] + pub struct transfer_to_private_abi { + parameters: transfer_to_private_parameters, + } + + #[abi(functions)] + pub struct transfer_to_public_abi { + parameters: transfer_to_public_parameters, + } + + #[abi(functions)] + pub struct transfer_to_public_and_prepare_private_balance_increase_abi { + parameters: transfer_to_public_and_prepare_private_balance_increase_parameters, + return_type: PartialUintNote, + } + + fn __aztec_nr_internals___recurse_subtract_balance(inputs: aztec::context::inputs::PrivateContextInputs, account: AztecAddress, amount: u128) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(account); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + assert(self.msg_sender() == self.address, "Function _recurse_subtract_balance can only be called by the same contract"); + let macro__returned__values: u128 = self.internal.subtract_balance(account, amount, RECURSIVE_TRANSFER_CALL_MAX_NOTES); + let serialized_params: [Field; 1] = ::serialize(macro__returned__values); + self.context.set_return_hash(serialized_params); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__burn_private(inputs: aztec::context::inputs::PrivateContextInputs, from: AztecAddress, amount: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 3] = [0_Field; 3]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + if !from.eq(self.msg_sender()) { + aztec::authwit::auth::assert_current_call_valid_authwit::<3>(self.context, from); + } else { + assert(authwit_nonce == 0_Field, "Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"); + }; + self.storage.balances.at(from).sub(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED); + self.enqueue_self._reduce_total_supply(amount); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__cancel_authwit(inputs: aztec::context::inputs::PrivateContextInputs, inner_hash: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let serialized_params: [Field; 1] = ::serialize(inner_hash); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + let on_behalf_of: AztecAddress = self.msg_sender(); + let nullifier: Field = compute_authwit_nullifier(on_behalf_of, inner_hash); + self.context.push_nullifier(nullifier); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__finalize_transfer_to_private_from_private(inputs: aztec::context::inputs::PrivateContextInputs, from: AztecAddress, partial_note: PartialUintNote, amount: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(partial_note); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + if !from.eq(self.msg_sender()) { + aztec::authwit::auth::assert_current_call_valid_authwit::<4>(self.context, from); + } else { + assert(authwit_nonce == 0_Field, "Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"); + }; + self.storage.balances.at(from).sub(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED); + partial_note.complete_from_private(self.context, self.msg_sender(), self.storage.balances.get_storage_slot(), amount); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__mint_to_private(inputs: aztec::context::inputs::PrivateContextInputs, to: AztecAddress, amount: u128) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + let partial_note: PartialUintNote = self.internal._prepare_private_balance_increase(to); + self.enqueue_self._finalize_mint_to_private_unsafe(self.msg_sender(), amount, partial_note); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__prepare_private_balance_increase(inputs: aztec::context::inputs::PrivateContextInputs, to: AztecAddress) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let serialized_params: [Field; 1] = ::serialize(to); + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + let macro__returned__values: PartialUintNote = self.internal._prepare_private_balance_increase(to); + let serialized_params: [Field; 1] = ::serialize(macro__returned__values); + self.context.set_return_hash(serialized_params); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__private_get_decimals(inputs: aztec::context::inputs::PrivateContextInputs) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let serialized_params: [Field; 0] = []; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + assert(self.context.inputs.call_context.is_static_call, "Function private_get_decimals can only be called statically"); + let macro__returned__values: u8 = self.storage.decimals.read(); + let serialized_params: [Field; 1] = ::serialize(macro__returned__values); + self.context.set_return_hash(serialized_params); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__private_get_name(inputs: aztec::context::inputs::PrivateContextInputs) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let serialized_params: [Field; 0] = []; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + assert(self.context.inputs.call_context.is_static_call, "Function private_get_name can only be called statically"); + let macro__returned__values: FieldCompressedString = self.storage.name.read(); + let serialized_params: [Field; 1] = ::serialize(macro__returned__values); + self.context.set_return_hash(serialized_params); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__private_get_symbol(inputs: aztec::context::inputs::PrivateContextInputs) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let serialized_params: [Field; 0] = []; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + assert(self.context.inputs.call_context.is_static_call, "Function private_get_symbol can only be called statically"); + let macro__returned__values: FieldCompressedString = self.storage.symbol.read(); + let serialized_params: [Field; 1] = ::serialize(macro__returned__values); + self.context.set_return_hash(serialized_params); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__transfer(inputs: aztec::context::inputs::PrivateContextInputs, to: AztecAddress, amount: u128) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + let from: AztecAddress = self.msg_sender(); + let change: u128 = self.internal.subtract_balance(from, amount, INITIAL_TRANSFER_CALL_MAX_NOTES); + self.storage.balances.at(from).add(change).deliver(MessageDelivery.ONCHAIN_UNCONSTRAINED); + self.storage.balances.at(to).add(amount).deliver(MessageDelivery.ONCHAIN_UNCONSTRAINED); + self.emit(Transfer { from: from, to: to, amount: amount}).deliver_to(to, MessageDelivery.ONCHAIN_UNCONSTRAINED); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__transfer_in_private(inputs: aztec::context::inputs::PrivateContextInputs, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + if !from.eq(self.msg_sender()) { + aztec::authwit::auth::assert_current_call_valid_authwit::<4>(self.context, from); + } else { + assert(authwit_nonce == 0_Field, "Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"); + }; + self.storage.balances.at(from).sub(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED); + self.storage.balances.at(to).add(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__transfer_in_private_with_offchain_delivery(inputs: aztec::context::inputs::PrivateContextInputs, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + if !from.eq(self.msg_sender()) { + aztec::authwit::auth::assert_current_call_valid_authwit::<4>(self.context, from); + } else { + assert(authwit_nonce == 0_Field, "Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"); + }; + self.storage.balances.at(from).sub(amount).deliver(MessageDelivery.OFFCHAIN); + self.storage.balances.at(to).add(amount).deliver(MessageDelivery.OFFCHAIN); + self.emit(Transfer { from: from, to: to, amount: amount}).deliver_to(to, MessageDelivery.OFFCHAIN); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__transfer_to_private(inputs: aztec::context::inputs::PrivateContextInputs, to: AztecAddress, amount: u128) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 2] = [0_Field; 2]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + let from: AztecAddress = self.msg_sender(); + let partial_note: PartialUintNote = self.internal._prepare_private_balance_increase(to); + self.enqueue_self._finalize_transfer_to_private_unsafe(from, amount, partial_note); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__transfer_to_public(inputs: aztec::context::inputs::PrivateContextInputs, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + if !from.eq(self.msg_sender()) { + aztec::authwit::auth::assert_current_call_valid_authwit::<4>(self.context, from); + } else { + assert(authwit_nonce == 0_Field, "Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"); + }; + self.storage.balances.at(from).sub(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED); + self.enqueue_self._increase_public_balance(to, amount); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + fn __aztec_nr_internals__transfer_to_public_and_prepare_private_balance_increase(inputs: aztec::context::inputs::PrivateContextInputs, from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let mut serialized_params: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = ::serialize(from); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_0: u32 = i + offset; + serialized_params[i_0] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(to); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_1: u32 = i + offset; + serialized_params[i_1] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(amount); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_2: u32 = i + offset; + serialized_params[i_2] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let serialized_member: [Field; 1] = ::serialize(authwit_nonce); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + { + let i_3: u32 = i + offset; + serialized_params[i_3] = serialized_member[i]; + } + }; + offset = offset + serialized_member_len; + let args_hash: Field = aztec::hash::hash_args(serialized_params); + let mut context: PrivateContext = PrivateContext::new(inputs, args_hash); + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(&mut context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: &mut context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: &mut context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: &mut context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(&mut context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + let within_revertible_phase: bool = self.context.in_revertible_phase(); + aztec::macros::functions::initialization_utils::assert_is_initialized_private(self.context); + if !from.eq(self.msg_sender()) { + aztec::authwit::auth::assert_current_call_valid_authwit::<4>(self.context, from); + } else { + assert(authwit_nonce == 0_Field, "Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"); + }; + self.storage.balances.at(from).sub(amount).deliver(MessageDelivery.ONCHAIN_CONSTRAINED); + self.enqueue_self._increase_public_balance(to, amount); + let macro__returned__values: PartialUintNote = self.internal._prepare_private_balance_increase(from); + let serialized_params: [Field; 1] = ::serialize(macro__returned__values); + self.context.set_return_hash(serialized_params); + assert(within_revertible_phase == self.context.in_revertible_phase(), f"Phase change detected on function with phase check. If this is expected, use #[allow_phase_change]"); + self.context.finish() + } + + unconstrained fn __aztec_nr_internals___finalize_mint_to_private_unsafe(minter_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (::N + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.msg_sender() == self.address, "Function _finalize_mint_to_private_unsafe can only be called by the same contract"); + { + assert(self.storage.minters.at(minter_and_completer).read(), "caller is not minter"); + self.internal._finalize_mint_to_private(minter_and_completer, amount, partial_note); + } + } + + unconstrained fn __aztec_nr_internals___finalize_transfer_to_private_unsafe(from_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (::N + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.msg_sender() == self.address, "Function _finalize_transfer_to_private_unsafe can only be called by the same contract"); + { + self.internal._finalize_transfer_to_private(from_and_completer, amount, partial_note); + } + } + + unconstrained fn __aztec_nr_internals___increase_public_balance(to: AztecAddress, amount: u128) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.msg_sender() == self.address, "Function _increase_public_balance can only be called by the same contract"); + { + let to_balance: PublicMutable = self.storage.public_balances.at(to); + let new_balance: u128 = to_balance.read().add(amount); + to_balance.write(new_balance); + } + } + + unconstrained fn __aztec_nr_internals___reduce_total_supply(amount: u128) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + assert(self.msg_sender() == self.address, "Function _reduce_total_supply can only be called by the same contract"); + { + let new_supply: u128 = self.storage.total_supply.read().sub(amount); + self.storage.total_supply.write(new_supply); + } + } + + unconstrained fn __aztec_nr_internals__balance_of_public(owner: AztecAddress) -> pub u128 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + assert(self.context.is_static_call(), "Function balance_of_public can only be called statically"); + { + self.storage.public_balances.at(owner).read() + } + } + + unconstrained fn __aztec_nr_internals__burn_public(from: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 3] = aztec::oracle::avm::calldata_copy(1_u32, (::N + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + if !from.eq(self.msg_sender()) { + aztec::authwit::auth::assert_current_call_valid_authwit_public(self.context, from); + } else { + assert(authwit_nonce == 0_Field, "Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"); + }; + { + let from_balance: u128 = self.storage.public_balances.at(from).read().sub(amount); + self.storage.public_balances.at(from).write(from_balance); + let new_supply: u128 = self.storage.total_supply.read().sub(amount); + self.storage.total_supply.write(new_supply); + } + } + + unconstrained fn __aztec_nr_internals__constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 64] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + as aztec::protocol::traits::Serialize>::N) + as aztec::protocol::traits::Serialize>::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_public(self.context); + { + assert(!admin.is_zero(), "invalid admin"); + self.storage.admin.write(admin); + self.storage.minters.at(admin).write(true); + self.storage.name.initialize(FieldCompressedString::from_string(name)); + self.storage.symbol.initialize(FieldCompressedString::from_string(symbol)); + self.storage.decimals.initialize(decimals); + }; + aztec::macros::functions::initialization_utils::mark_as_initialized_from_public_initializer(self.context); + } + + unconstrained fn __aztec_nr_internals__finalize_mint_to_private(amount: u128, partial_note: PartialUintNote) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + { + let minter_and_completer: AztecAddress = self.msg_sender(); + assert(self.storage.minters.at(minter_and_completer).read(), "caller is not minter"); + self.internal._finalize_mint_to_private(minter_and_completer, amount, partial_note); + } + } + + unconstrained fn __aztec_nr_internals__finalize_transfer_to_private(amount: u128, partial_note: PartialUintNote) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + { + let from_and_completer: AztecAddress = self.msg_sender(); + self.internal._finalize_transfer_to_private(from_and_completer, amount, partial_note); + } + } + + unconstrained fn __aztec_nr_internals__get_admin() -> pub Field { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + assert(self.context.is_static_call(), "Function get_admin can only be called statically"); + { + self.storage.admin.read().to_field() + } + } + + unconstrained fn __aztec_nr_internals__is_minter(minter: AztecAddress) -> pub bool { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + assert(self.context.is_static_call(), "Function is_minter can only be called statically"); + { + self.storage.minters.at(minter).read() + } + } + + unconstrained fn __aztec_nr_internals__mint_to_public(to: AztecAddress, amount: u128) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + { + assert(self.storage.minters.at(self.msg_sender()).read(), "caller is not minter"); + let new_balance: u128 = self.storage.public_balances.at(to).read().add(amount); + let supply: u128 = self.storage.total_supply.read().add(amount); + self.storage.public_balances.at(to).write(new_balance); + self.storage.total_supply.write(supply); + } + } + + unconstrained fn __aztec_nr_internals__public_get_decimals() -> pub u8 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + assert(self.context.is_static_call(), "Function public_get_decimals can only be called statically"); + { + self.storage.decimals.read() + } + } + + unconstrained fn __aztec_nr_internals__public_get_name() -> pub FieldCompressedString { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + assert(self.context.is_static_call(), "Function public_get_name can only be called statically"); + { + self.storage.name.read() + } + } + + unconstrained fn __aztec_nr_internals__public_get_symbol() -> pub FieldCompressedString { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + assert(self.context.is_static_call(), "Function public_get_symbol can only be called statically"); + { + self.storage.symbol.read() + } + } + + unconstrained fn __aztec_nr_internals__set_admin(new_admin: AztecAddress) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 1] = aztec::oracle::avm::calldata_copy(1_u32, ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + { + assert(self.storage.admin.read().eq(self.msg_sender()), "caller is not admin"); + self.storage.admin.write(new_admin); + } + } + + unconstrained fn __aztec_nr_internals__set_minter(minter: AztecAddress, approve: bool) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(1_u32, ::N + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + { + assert(self.storage.admin.read().eq(self.msg_sender()), "caller is not admin"); + self.storage.minters.at(minter).write(approve); + } + } + + unconstrained fn __aztec_nr_internals__total_supply() -> pub u128 { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 0] = aztec::oracle::avm::calldata_copy(1_u32, 0_u32); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + assert(self.context.is_static_call(), "Function total_supply can only be called statically"); + { + self.storage.total_supply.read() + } + } + + unconstrained fn __aztec_nr_internals__transfer_in_public(from: AztecAddress, to: AztecAddress, amount: u128, authwit_nonce: Field) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let context: aztec::context::PublicContext = aztec::context::PublicContext::new(|| -> Field { + let serialized_args: [Field; 4] = aztec::oracle::avm::calldata_copy(1_u32, ((::N + ::N) + ::N) + ::N); + aztec::hash::hash_args(serialized_args) + }); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); + if !from.eq(self.msg_sender()) { + aztec::authwit::auth::assert_current_call_valid_authwit_public(self.context, from); + } else { + assert(authwit_nonce == 0_Field, "Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"); + }; + { + let from_balance: u128 = self.storage.public_balances.at(from).read().sub(amount); + self.storage.public_balances.at(from).write(from_balance); + let to_balance: u128 = self.storage.public_balances.at(to).read().add(amount); + self.storage.public_balances.at(to).write(to_balance); + } + } + + unconstrained fn __aztec_nr_internals__balance_of_private(owner: AztecAddress) -> pub u128 { + aztec::oracle::version::assert_compatible_oracle_version(); + let mut self: aztec::contract_self::contract_self_utility::ContractSelfUtility, CallSelfUtility> = { + let context: aztec::context::UtilityContext = aztec::context::UtilityContext::new(); + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelfUtility = CallSelfUtility { address: self_address}; + aztec::contract_self::contract_self_utility::ContractSelfUtility::, CallSelfUtility>::new(context, storage, call_self) + }; + aztec::macros::functions::initialization_utils::assert_is_initialized_utility(self.context); + { + self.storage.balances.at(owner).balance_of() + } + } + + #[contract_library_method] + fn __aztec_nr_internals___prepare_private_balance_increase(context: &mut PrivateContext, to: AztecAddress) -> PartialUintNote { + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + { + let partial_note: PartialUintNote = UintNote::partial(to, self.context, to, self.msg_sender()); + partial_note + } + } + + #[contract_library_method] + fn __aztec_nr_internals__subtract_balance(context: &mut PrivateContext, account: AztecAddress, amount: u128, max_notes: u32) -> u128 { + let mut self: aztec::contract_self::contract_self_private::ContractSelfPrivate, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility> = { + let storage: Storage<&mut PrivateContext> = Storage::<&mut PrivateContext>::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf<&mut PrivateContext> = CallSelf::<&mut PrivateContext> { address: self_address, context: context}; + let enqueue_self: EnqueueSelf<&mut PrivateContext> = EnqueueSelf::<&mut PrivateContext> { address: self_address, context: context}; + let call_self_static: CallSelfStatic<&mut PrivateContext> = CallSelfStatic::<&mut PrivateContext> { address: self_address, context: context}; + let enqueue_self_static: EnqueueSelfStatic<&mut PrivateContext> = EnqueueSelfStatic::<&mut PrivateContext> { address: self_address, context: context}; + let internal: CallInternal<&mut PrivateContext> = CallInternal::<&mut PrivateContext> { context: context}; + let call_self_utility: CallSelfUtility = CallSelfUtility { address: self_address}; + let utility: aztec::contract_self::contract_self_private::PrivateUtilityCalls = aztec::contract_self::contract_self_private::PrivateUtilityCalls:: { call_self: call_self_utility}; + aztec::contract_self::contract_self_private::ContractSelfPrivate::, CallSelf<&mut PrivateContext>, EnqueueSelf<&mut PrivateContext>, CallSelfStatic<&mut PrivateContext>, EnqueueSelfStatic<&mut PrivateContext>, CallInternal<&mut PrivateContext>, CallSelfUtility>::new(context, storage, call_self, enqueue_self, call_self_static, enqueue_self_static, internal, utility) + }; + { + let subtracted: u128 = self.storage.balances.at(account).try_sub(amount, max_notes); + assert(subtracted > (0_Field as u128), "Balance too low"); + if subtracted >= amount { + subtracted - amount + } else { + let remaining: u128 = amount - subtracted; + compute_recurse_subtract_balance_call(*context, account, remaining).call(context) + } + } + } + + #[contract_library_method] + unconstrained fn __aztec_nr_internals___finalize_mint_to_private(context: aztec::context::PublicContext, completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let supply: u128 = self.storage.total_supply.read().add(amount); + self.storage.total_supply.write(supply); + partial_note.complete(self.context, completer, self.storage.balances.get_storage_slot(), amount); + } + } + + #[contract_library_method] + unconstrained fn __aztec_nr_internals___finalize_transfer_to_private(context: aztec::context::PublicContext, from_and_completer: AztecAddress, amount: u128, partial_note: PartialUintNote) { + let mut self: aztec::contract_self::contract_self_public::ContractSelfPublic, CallSelf, CallSelfStatic, CallInternal> = { + let storage: Storage = Storage::::init(context); + let self_address: AztecAddress = context.this_address(); + let call_self: CallSelf = CallSelf:: { address: self_address, context: context}; + let call_self_static: CallSelfStatic = CallSelfStatic:: { address: self_address, context: context}; + let internal: CallInternal = CallInternal:: { context: context}; + aztec::contract_self::contract_self_public::ContractSelfPublic::, CallSelf, CallSelfStatic, CallInternal>::new(context, storage, call_self, call_self_static, internal) + }; + { + let balance_storage: PublicMutable = self.storage.public_balances.at(from_and_completer); + let from_balance: u128 = balance_storage.read().sub(amount); + balance_storage.write(from_balance); + partial_note.complete(self.context, from_and_completer, self.storage.balances.get_storage_slot(), amount); + } + } + + pub struct StorageLayoutFields { + pub admin: aztec::state_vars::Storable, + pub minters: aztec::state_vars::Storable, + pub balances: aztec::state_vars::Storable, + pub total_supply: aztec::state_vars::Storable, + pub public_balances: aztec::state_vars::Storable, + pub symbol: aztec::state_vars::Storable, + pub name: aztec::state_vars::Storable, + pub decimals: aztec::state_vars::Storable, + } + + pub struct StorageLayout { + pub contract_name: str, + pub fields: StorageLayoutFields, + } +} + +mod test { + pub mod access_control { + use super::utils; + use crate::Token; + use aztec::protocol::traits::ToField; + + #[test] + unconstrained fn access_control() { + let (env, token_contract_address, owner, new_admin): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress) = utils::setup(false); + let token: Token::Token = Token::at(token_contract_address); + env.call_public(owner, token.set_admin(new_admin)); + assert(env.view_public(token.get_admin()) == new_admin.to_field()); + assert(!env.view_public(token.is_minter(new_admin))); + env.call_public(new_admin, token.set_minter(new_admin, true)); + assert(env.view_public(token.is_minter(new_admin))); + env.call_public(new_admin, token.set_minter(new_admin, false)); + assert(!env.view_public(token.is_minter(new_admin))); + } + + #[test(should_fail_with = "caller is not admin")] + unconstrained fn set_admin_requires_admin_caller() { + let (env, token_contract_address, _, other): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress) = utils::setup(false); + let token: Token::Token = Token::at(token_contract_address); + env.call_public(other, token.set_admin(other)); + } + + #[test(should_fail_with = "caller is not admin")] + unconstrained fn set_minter_requires_admin_caller() { + let (env, token_contract_address, _, other): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress) = utils::setup(false); + let token: Token::Token = Token::at(token_contract_address); + env.call_public(other, token.set_minter(other, true)); + } + } + + pub mod burn_private { + use super::utils; + use crate::Token; + use aztec::test::helpers::authwit::add_private_authwit_from_call; + use generic_proxy_contract::GenericProxy; + + global AUTHWIT_NONCE: Field = 0x07; + + #[test] + unconstrained fn burn_private_on_behalf_of_self() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let burn_amount: u128 = mint_amount / (10_Field as u128); + env.call_private(owner, Token::at(token_contract_address).burn_private(owner, burn_amount, 0_Field)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount - burn_amount); + } + + #[test] + unconstrained fn burn_private_on_behalf_of_other() { + let (env, token_contract_address, owner, _, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let burn_amount: u128 = mint_amount / (10_Field as u128); + let burn_call: aztec::context::calls::PrivateCall<12, 3, ()> = Token::at(token_contract_address).burn_private(owner, burn_amount, AUTHWIT_NONCE); + add_private_authwit_from_call(env, owner, proxy, burn_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_3(burn_call.target_contract, burn_call.selector, burn_call.args)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount - burn_amount); + } + + #[test(should_fail_with = "Balance too low")] + unconstrained fn burn_private_failure_more_than_balance() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let burn_amount: u128 = mint_amount * (10_Field as u128); + env.call_private(owner, Token::at(token_contract_address).burn_private(owner, burn_amount, 0_Field)); + } + + #[test(should_fail_with = "Assertion failed: Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero")] + unconstrained fn burn_private_failure_on_behalf_of_self_non_zero_nonce() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let burn_amount: u128 = mint_amount; + env.call_private(owner, Token::at(token_contract_address).burn_private(owner, burn_amount, 1_Field)); + } + + #[test(should_fail_with = "Balance too low")] + unconstrained fn burn_private_failure_on_behalf_of_other_more_than_balance() { + let (env, token_contract_address, owner, _, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_public_with_proxy(); + let burn_amount: u128 = mint_amount * (10_Field as u128); + let burn_call: aztec::context::calls::PrivateCall<12, 3, ()> = Token::at(token_contract_address).burn_private(owner, burn_amount, AUTHWIT_NONCE); + add_private_authwit_from_call(env, owner, proxy, burn_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_3(burn_call.target_contract, burn_call.selector, burn_call.args)); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn burn_private_failure_on_behalf_of_other_without_approval() { + let (env, token_contract_address, owner, _, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_public_with_proxy(); + let burn_amount: u128 = mint_amount / (10_Field as u128); + let burn_call: aztec::context::calls::PrivateCall<12, 3, ()> = Token::at(token_contract_address).burn_private(owner, burn_amount, AUTHWIT_NONCE); + env.call_private(owner, GenericProxy::at(proxy).forward_private_3(burn_call.target_contract, burn_call.selector, burn_call.args)); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn burn_private_failure_on_behalf_of_other_wrong_designated_caller() { + let (env, token_contract_address, owner, _, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_public_with_proxy(); + let burn_amount: u128 = mint_amount / (10_Field as u128); + let burn_call: aztec::context::calls::PrivateCall<12, 3, ()> = Token::at(token_contract_address).burn_private(owner, burn_amount, AUTHWIT_NONCE); + add_private_authwit_from_call(env, owner, owner, burn_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_3(burn_call.target_contract, burn_call.selector, burn_call.args)); + } + } + + pub mod burn_public { + use super::utils; + use crate::Token; + use aztec::oracle::random::random; + use aztec::test::helpers::authwit::add_public_authwit_from_call; + + #[test] + unconstrained fn burn_public_success() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let burn_amount: u128 = mint_amount / (10_Field as u128); + env.call_public(owner, Token::at(token_contract_address).burn_public(owner, burn_amount, 0_Field)); + utils::check_public_balance(env, token_contract_address, owner, mint_amount - burn_amount); + } + + #[test] + unconstrained fn burn_public_on_behalf_of_other() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(true); + let burn_amount: u128 = mint_amount / (10_Field as u128); + let burn_call: aztec::context::calls::PublicCall<11, 3, ()> = Token::at(token_contract_address).burn_public(owner, burn_amount, random()); + add_public_authwit_from_call(env, owner, recipient, burn_call); + env.call_public(recipient, burn_call); + utils::check_public_balance(env, token_contract_address, owner, mint_amount - burn_amount); + } + + #[test(should_fail_with = "Assertion failed: attempt to subtract with overflow")] + unconstrained fn burn_public_failure_more_than_balance() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let burn_amount: u128 = mint_amount * (10_Field as u128); + env.call_public(owner, Token::at(token_contract_address).burn_public(owner, burn_amount, 0_Field)); + } + + #[test(should_fail_with = "Assertion failed: Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero")] + unconstrained fn burn_public_failure_on_behalf_of_self_non_zero_nonce() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let burn_amount: u128 = mint_amount / (10_Field as u128); + env.call_public(owner, Token::at(token_contract_address).burn_public(owner, burn_amount, random())); + } + + #[test(should_fail_with = "unauthorized")] + unconstrained fn burn_public_failure_on_behalf_of_other_without_approval() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(true); + let burn_amount: u128 = mint_amount / (10_Field as u128); + let burn_call: aztec::context::calls::PublicCall<11, 3, ()> = Token::at(token_contract_address).burn_public(owner, burn_amount, random()); + env.call_public(recipient, burn_call); + } + + #[test(should_fail_with = "unauthorized")] + unconstrained fn burn_public_failure_on_behalf_of_other_wrong_caller() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(true); + let burn_amount: u128 = mint_amount / (10_Field as u128); + let burn_call: aztec::context::calls::PublicCall<11, 3, ()> = Token::at(token_contract_address).burn_public(owner, burn_amount, random()); + add_public_authwit_from_call(env, owner, owner, burn_call); + env.call_public(recipient, burn_call); + } + } + + pub mod mint_to_public { + use super::utils; + use crate::Token; + + #[test] + unconstrained fn mint_to_public_success() { + let (env, token_contract_address, owner, _): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress) = utils::setup(false); + let mint_amount: u128 = 10000_Field as u128; + env.call_public(owner, Token::at(token_contract_address).mint_to_public(owner, mint_amount)); + utils::check_public_balance(env, token_contract_address, owner, mint_amount); + let total_supply: u128 = env.view_public(Token::at(token_contract_address).total_supply()); + assert(total_supply == mint_amount); + } + + #[test(should_fail_with = "caller is not minter")] + unconstrained fn mint_as_non_minter() { + let (env, token_contract_address, _, recipient): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress) = utils::setup(false); + let mint_amount: u128 = 10000_Field as u128; + env.call_public(recipient, Token::at(token_contract_address).mint_to_public(recipient, mint_amount)); + } + + #[test(should_fail)] + unconstrained fn mint_overflow() { + let (env, token_contract_address, owner, recipient): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress) = utils::setup(false); + let amount_until_overflow: u128 = 1000_Field as u128; + let mint_amount: u128 = (2_Field.pow_32(128_Field) - (amount_until_overflow as Field)) as u128; + env.call_public(owner, Token::at(token_contract_address).mint_to_public(recipient, mint_amount)); + env.call_public(owner, Token::at(token_contract_address).mint_to_public(recipient, amount_until_overflow)); + } + } + + pub mod reading_constants { + use super::utils; + use crate::Token; + + #[test] + unconstrained fn check_decimals_private() { + let (env, token_contract_address, owner, _): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress) = utils::setup(false); + let result: u8 = env.view_private(owner, Token::at(token_contract_address).private_get_decimals()); + assert(result == 18_u8); + } + + #[test] + unconstrained fn check_decimals_public() { + let (env, token_contract_address, _, _): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress) = utils::setup(false); + let result: u8 = env.view_public(Token::at(token_contract_address).public_get_decimals()); + assert(result == 18_u8); + } + } + + pub mod transfer { + use super::utils; + use crate::Token; + + #[test] + unconstrained fn transfer_private() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_amount: u128 = 1000_Field as u128; + env.call_private(owner, Token::at(token_contract_address).transfer(recipient, transfer_amount)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount - transfer_amount); + utils::check_private_balance(env, token_contract_address, recipient, transfer_amount); + } + + #[test] + unconstrained fn transfer_private_to_self() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_amount: u128 = 1000_Field as u128; + let _: () = env.call_private(owner, Token::at(token_contract_address).transfer(owner, transfer_amount)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount); + } + + #[test] + unconstrained fn transfer_private_to_non_deployed_account() { + let (mut env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let not_deployed: aztec::protocol::address::AztecAddress = env.create_light_account(); + let transfer_amount: u128 = 1000_Field as u128; + env.call_private(owner, Token::at(token_contract_address).transfer(not_deployed, transfer_amount)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount - transfer_amount); + utils::check_private_balance(env, token_contract_address, not_deployed, transfer_amount); + } + + #[test(should_fail_with = "Balance too low")] + unconstrained fn transfer_private_failure_more_than_balance() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_amount: u128 = mint_amount + (1_Field as u128); + env.call_private(owner, Token::at(token_contract_address).transfer(recipient, transfer_amount)); + } + } + + pub mod transfer_in_private { + use super::utils; + use crate::Token; + use aztec::test::helpers::authwit::add_private_authwit_from_call; + use generic_proxy_contract::GenericProxy; + + #[test] + unconstrained fn transfer_private_on_behalf_of_other() { + let (env, token_contract_address, owner, recipient, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_amount: u128 = 1000_Field as u128; + let transfer_private_from_call: aztec::context::calls::PrivateCall<19, 4, ()> = Token::at(token_contract_address).transfer_in_private(owner, recipient, transfer_amount, 1_Field); + add_private_authwit_from_call(env, owner, proxy, transfer_private_from_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_private_from_call.target_contract, transfer_private_from_call.selector, transfer_private_from_call.args)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount - transfer_amount); + utils::check_private_balance(env, token_contract_address, recipient, transfer_amount); + } + + #[test(should_fail_with = "Assertion failed: Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero")] + unconstrained fn transfer_private_failure_on_behalf_of_self_non_zero_nonce() { + let (env, token_contract_address, owner, recipient, _): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_amount: u128 = 1000_Field as u128; + let transfer_private_from_call: aztec::context::calls::PrivateCall<19, 4, ()> = Token::at(token_contract_address).transfer_in_private(owner, recipient, transfer_amount, 1_Field); + add_private_authwit_from_call(env, owner, recipient, transfer_private_from_call); + env.call_private(owner, transfer_private_from_call); + } + + #[test(should_fail_with = "Balance too low")] + unconstrained fn transfer_private_failure_on_behalf_of_more_than_balance() { + let (env, token_contract_address, owner, recipient, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_amount: u128 = mint_amount + (1_Field as u128); + let transfer_private_from_call: aztec::context::calls::PrivateCall<19, 4, ()> = Token::at(token_contract_address).transfer_in_private(owner, recipient, transfer_amount, 1_Field); + add_private_authwit_from_call(env, owner, proxy, transfer_private_from_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_private_from_call.target_contract, transfer_private_from_call.selector, transfer_private_from_call.args)); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn transfer_private_failure_on_behalf_of_other_without_approval() { + let (env, token_contract_address, owner, recipient, _, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_amount: u128 = 1000_Field as u128; + let transfer_private_from_call: aztec::context::calls::PrivateCall<19, 4, ()> = Token::at(token_contract_address).transfer_in_private(owner, recipient, transfer_amount, 1_Field); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_private_from_call.target_contract, transfer_private_from_call.selector, transfer_private_from_call.args)); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn transfer_private_failure_on_behalf_of_other_wrong_caller() { + let (env, token_contract_address, owner, recipient, _, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_amount: u128 = 1000_Field as u128; + let transfer_private_from_call: aztec::context::calls::PrivateCall<19, 4, ()> = Token::at(token_contract_address).transfer_in_private(owner, recipient, transfer_amount, 1_Field); + add_private_authwit_from_call(env, owner, owner, transfer_private_from_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_private_from_call.target_contract, transfer_private_from_call.selector, transfer_private_from_call.args)); + } + } + + pub mod transfer_in_private_with_offchain_delivery { + use super::utils; + use crate::Token; + use aztec::test::helpers::authwit::add_private_authwit_from_call; + use generic_proxy_contract::GenericProxy; + + #[test] + unconstrained fn transfer_in_private_with_offchain_delivery_updates_both_balances() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_amount: u128 = 1000_Field as u128; + let transfer_call: aztec::context::calls::PrivateCall<42, 4, ()> = Token::at(token_contract_address).transfer_in_private_with_offchain_delivery(owner, recipient, transfer_amount, 0_Field); + env.call_private(owner, transfer_call); + let messages: BoundedVec = env.offchain_messages(); + let mut batch: BoundedVec = BoundedVec::::new(); + for i in 0_u32..messages.len() { + batch.push(messages.get(i)); + }; + env.execute_utility(Token::at(token_contract_address).offchain_receive(batch)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount - transfer_amount); + utils::check_private_balance(env, token_contract_address, recipient, transfer_amount); + } + + #[test(should_fail_with = "Assertion failed: Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero")] + unconstrained fn transfer_in_private_with_offchain_delivery_failure_on_behalf_of_self_non_zero_nonce() { + let (env, token_contract_address, owner, recipient, _): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_amount: u128 = 1000_Field as u128; + let transfer_call: aztec::context::calls::PrivateCall<42, 4, ()> = Token::at(token_contract_address).transfer_in_private_with_offchain_delivery(owner, recipient, transfer_amount, 1_Field); + add_private_authwit_from_call(env, owner, recipient, transfer_call); + env.call_private(owner, transfer_call); + } + + #[test(should_fail_with = "Balance too low")] + unconstrained fn transfer_in_private_with_offchain_delivery_failure_on_behalf_of_more_than_balance() { + let (env, token_contract_address, owner, recipient, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_amount: u128 = mint_amount + (1_Field as u128); + let transfer_call: aztec::context::calls::PrivateCall<42, 4, ()> = Token::at(token_contract_address).transfer_in_private_with_offchain_delivery(owner, recipient, transfer_amount, 1_Field); + add_private_authwit_from_call(env, owner, proxy, transfer_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_call.target_contract, transfer_call.selector, transfer_call.args)); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn transfer_in_private_with_offchain_delivery_failure_on_behalf_of_other_without_approval() { + let (env, token_contract_address, owner, recipient, _, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_amount: u128 = 1000_Field as u128; + let transfer_call: aztec::context::calls::PrivateCall<42, 4, ()> = Token::at(token_contract_address).transfer_in_private_with_offchain_delivery(owner, recipient, transfer_amount, 1_Field); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_call.target_contract, transfer_call.selector, transfer_call.args)); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn transfer_in_private_with_offchain_delivery_failure_on_behalf_of_other_wrong_caller() { + let (env, token_contract_address, owner, recipient, _, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_amount: u128 = 1000_Field as u128; + let transfer_call: aztec::context::calls::PrivateCall<42, 4, ()> = Token::at(token_contract_address).transfer_in_private_with_offchain_delivery(owner, recipient, transfer_amount, 1_Field); + add_private_authwit_from_call(env, owner, owner, transfer_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_call.target_contract, transfer_call.selector, transfer_call.args)); + } + } + + pub mod transfer_in_public { + use super::utils; + use crate::Token; + use aztec::test::helpers::authwit::add_public_authwit_from_call; + + #[test] + unconstrained fn public_transfer() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let transfer_amount: u128 = mint_amount / (10_Field as u128); + env.call_public(owner, Token::at(token_contract_address).transfer_in_public(owner, recipient, transfer_amount, 0_Field)); + utils::check_public_balance(env, token_contract_address, owner, mint_amount - transfer_amount); + utils::check_public_balance(env, token_contract_address, recipient, transfer_amount); + } + + #[test] + unconstrained fn public_transfer_to_self() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let transfer_amount: u128 = mint_amount / (10_Field as u128); + env.call_public(owner, Token::at(token_contract_address).transfer_in_public(owner, owner, transfer_amount, 0_Field)); + utils::check_public_balance(env, token_contract_address, owner, mint_amount); + } + + #[test] + unconstrained fn public_transfer_on_behalf_of_other() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(true); + let transfer_amount: u128 = mint_amount / (10_Field as u128); + let public_transfer_in_private_call: aztec::context::calls::PublicCall<18, 4, ()> = Token::at(token_contract_address).transfer_in_public(owner, recipient, transfer_amount, 1_Field); + add_public_authwit_from_call(env, owner, recipient, public_transfer_in_private_call); + env.call_public(recipient, public_transfer_in_private_call); + utils::check_public_balance(env, token_contract_address, owner, mint_amount - transfer_amount); + utils::check_public_balance(env, token_contract_address, recipient, transfer_amount); + } + + #[test(should_fail_with = "Assertion failed: attempt to subtract with overflow")] + unconstrained fn public_transfer_failure_more_than_balance() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let transfer_amount: u128 = mint_amount + (1_Field as u128); + let public_transfer_call: aztec::context::calls::PublicCall<18, 4, ()> = Token::at(token_contract_address).transfer_in_public(owner, recipient, transfer_amount, 0_Field); + env.call_public(owner, public_transfer_call); + } + + #[test(should_fail_with = "Assertion failed: Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero")] + unconstrained fn public_transfer_failure_on_behalf_of_self_non_zero_nonce() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let transfer_amount: u128 = mint_amount / (10_Field as u128); + let public_transfer_call: aztec::context::calls::PublicCall<18, 4, ()> = Token::at(token_contract_address).transfer_in_public(owner, recipient, transfer_amount, 1_Field); + add_public_authwit_from_call(env, owner, recipient, public_transfer_call); + env.call_public(owner, public_transfer_call); + } + + #[test(should_fail_with = "unauthorized")] + unconstrained fn public_transfer_failure_on_behalf_of_other_without_approval() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(true); + let transfer_amount: u128 = mint_amount / (10_Field as u128); + let public_transfer_in_private_call: aztec::context::calls::PublicCall<18, 4, ()> = Token::at(token_contract_address).transfer_in_public(owner, recipient, transfer_amount, 1_Field); + env.call_public(recipient, public_transfer_in_private_call); + } + + #[test(should_fail_with = "Assertion failed: attempt to subtract with overflow")] + unconstrained fn public_transfer_failure_on_behalf_of_other_more_than_balance() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(true); + let transfer_amount: u128 = mint_amount + (1_Field as u128); + let public_transfer_in_private_call: aztec::context::calls::PublicCall<18, 4, ()> = Token::at(token_contract_address).transfer_in_public(owner, recipient, transfer_amount, 1_Field); + add_public_authwit_from_call(env, owner, recipient, public_transfer_in_private_call); + env.call_public(recipient, public_transfer_in_private_call); + } + + #[test(should_fail_with = "unauthorized")] + unconstrained fn public_transfer_failure_on_behalf_of_other_wrong_caller() { + let (env, token_contract_address, owner, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(true); + let transfer_amount: u128 = mint_amount / (10_Field as u128); + let public_transfer_in_private_call: aztec::context::calls::PublicCall<18, 4, ()> = Token::at(token_contract_address).transfer_in_public(owner, recipient, transfer_amount, 1_Field); + add_public_authwit_from_call(env, owner, owner, public_transfer_in_private_call); + env.call_public(recipient, public_transfer_in_private_call); + } + } + + pub mod transfer_to_private { + use super::utils; + use crate::Token; + use aztec::oracle::random::random; + use aztec::protocol::traits::Deserialize; + use uint_note::PartialUintNote; + + /// Internal orchestration means that the calls to `prepare_private_balance_increase` + /// and `finalize_transfer_to_private` are done by the TOKEN contract itself. + /// In this test's case this is done by the `Token::transfer_to_private(...)` function called + /// in `utils::setup_mint_and_transfer_to_private`. + #[test] + unconstrained fn transfer_to_private_internal_orchestration() { + let (env, token_contract_address, user, _, amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + utils::check_private_balance(env, token_contract_address, user, amount); + } + + /// External orchestration means that the calls to prepare and finalize are not done by the Token contract. This flow + /// will typically be used by a DEX. + #[test] + unconstrained fn transfer_to_private_external_orchestration() { + let (env, token_contract_address, owner, recipient, amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let partial_uint_note: PartialUintNote = env.call_private(owner, Token::at(token_contract_address).prepare_private_balance_increase(recipient)); + env.call_public(owner, Token::at(token_contract_address).finalize_transfer_to_private(amount, partial_uint_note)); + utils::check_private_balance(env, token_contract_address, recipient, amount); + } + + /// External orchestration means that the calls to prepare and finalize are not done by the Token contract. This flow + /// will typically be used by a DEX. + #[test] + unconstrained fn transfer_to_private_from_private_external_orchestration() { + let (env, token_contract_address, owner, recipient, amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let partial_uint_note: PartialUintNote = env.call_private(owner, Token::at(token_contract_address).prepare_private_balance_increase(recipient)); + env.call_private(owner, Token::at(token_contract_address).finalize_transfer_to_private_from_private(owner, partial_uint_note, amount, 0_Field)); + utils::check_private_balance(env, token_contract_address, recipient, amount); + utils::check_private_balance(env, token_contract_address, owner, 0_u128); + } + + #[test(should_fail_with = "Invalid partial note or completer")] + unconstrained fn transfer_to_private_transfer_not_prepared() { + let (env, token_contract_address, owner, _, amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let commitment: Field = random(); + let partial_uint_note: PartialUintNote = PartialUintNote::deserialize([commitment]); + env.call_public(owner, Token::at(token_contract_address).finalize_transfer_to_private(amount, partial_uint_note)); + } + + #[test(should_fail_with = "Assertion failed: attempt to subtract with overflow")] + unconstrained fn transfer_to_private_failure_not_an_owner() { + let (env, token_contract_address, owner, not_owner, amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let partial_uint_note: PartialUintNote = env.call_private(owner, Token::at(token_contract_address).prepare_private_balance_increase(not_owner)); + env.call_public(not_owner, Token::at(token_contract_address).finalize_transfer_to_private(amount, partial_uint_note)); + } + + #[test(should_fail_with = "Invalid partial note or completer")] + unconstrained fn incorrect_completer_cannot_complete_partial_note() { + let (mut env, token_contract_address, owner, recipient, amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_public(false); + let completer: aztec::protocol::address::AztecAddress = env.create_light_account(); + let partial_uint_note: PartialUintNote = env.call_private(completer, Token::at(token_contract_address).prepare_private_balance_increase(recipient)); + env.call_public(owner, Token::at(token_contract_address).finalize_transfer_to_private(amount, partial_uint_note)); + } + } + + pub mod transfer_to_public { + use super::utils; + use crate::Token; + use aztec::oracle::random::random; + use aztec::test::helpers::authwit::add_private_authwit_from_call; + use generic_proxy_contract::GenericProxy; + + #[test] + unconstrained fn transfer_to_public_on_behalf_of_self() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_to_public_amount: u128 = mint_amount / (10_Field as u128); + env.call_private(owner, Token::at(token_contract_address).transfer_to_public(owner, owner, transfer_to_public_amount, 0_Field)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount - transfer_to_public_amount); + utils::check_public_balance(env, token_contract_address, owner, transfer_to_public_amount); + } + + #[test] + unconstrained fn transfer_to_public_on_behalf_of_other() { + let (env, token_contract_address, owner, recipient, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_to_public_amount: u128 = mint_amount / (10_Field as u128); + let transfer_to_public_call: aztec::context::calls::PrivateCall<18, 4, ()> = Token::at(token_contract_address).transfer_to_public(owner, recipient, transfer_to_public_amount, 0_Field); + add_private_authwit_from_call(env, owner, proxy, transfer_to_public_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_to_public_call.target_contract, transfer_to_public_call.selector, transfer_to_public_call.args)); + utils::check_private_balance(env, token_contract_address, owner, mint_amount - transfer_to_public_amount); + utils::check_public_balance(env, token_contract_address, recipient, transfer_to_public_amount); + } + + #[test(should_fail_with = "Balance too low")] + unconstrained fn transfer_to_public_failure_more_than_balance() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_to_public_amount: u128 = mint_amount + (1_Field as u128); + env.call_private(owner, Token::at(token_contract_address).transfer_to_public(owner, owner, transfer_to_public_amount, 0_Field)); + } + + #[test(should_fail_with = "Assertion failed: Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero")] + unconstrained fn transfer_to_public_failure_on_behalf_of_self_non_zero_nonce() { + let (env, token_contract_address, owner, _, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_to_public_amount: u128 = mint_amount + (1_Field as u128); + env.call_private(owner, Token::at(token_contract_address).transfer_to_public(owner, owner, transfer_to_public_amount, random())); + } + + #[test(should_fail_with = "Balance too low")] + unconstrained fn transfer_to_public_failure_on_behalf_of_other_more_than_balance() { + let (env, token_contract_address, owner, recipient, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_to_public_amount: u128 = mint_amount + (1_Field as u128); + let transfer_to_public_call: aztec::context::calls::PrivateCall<18, 4, ()> = Token::at(token_contract_address).transfer_to_public(owner, recipient, transfer_to_public_amount, 0_Field); + add_private_authwit_from_call(env, owner, proxy, transfer_to_public_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_to_public_call.target_contract, transfer_to_public_call.selector, transfer_to_public_call.args)); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn transfer_to_public_failure_on_behalf_of_other_invalid_designated_caller() { + let (env, token_contract_address, owner, recipient, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_to_public_amount: u128 = mint_amount + (1_Field as u128); + let transfer_to_public_call: aztec::context::calls::PrivateCall<18, 4, ()> = Token::at(token_contract_address).transfer_to_public(owner, recipient, transfer_to_public_amount, 0_Field); + add_private_authwit_from_call(env, owner, owner, transfer_to_public_call); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_to_public_call.target_contract, transfer_to_public_call.selector, transfer_to_public_call.args)); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn transfer_to_public_failure_on_behalf_of_other_no_approval() { + let (env, token_contract_address, owner, recipient, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_to_public_amount: u128 = mint_amount + (1_Field as u128); + let transfer_to_public_call: aztec::context::calls::PrivateCall<18, 4, ()> = Token::at(token_contract_address).transfer_to_public(owner, recipient, transfer_to_public_amount, 0_Field); + env.call_private(owner, GenericProxy::at(proxy).forward_private_4(transfer_to_public_call.target_contract, transfer_to_public_call.selector, transfer_to_public_call.args)); + } + } + + pub mod transfer_to_public_and_prepare_private_balance_increase { + use super::utils; + use crate::Token; + use aztec::oracle::random::random; + use aztec::protocol::traits::Deserialize; + use aztec::test::helpers::authwit::add_private_authwit_from_call; + use generic_proxy_contract::GenericProxy; + use uint_note::PartialUintNote; + + #[test] + unconstrained fn transfer_to_public_and_prepare_private_balance_increase_and_finalize_transfer_to_private() { + let (env, token_contract_address, liquidity_provider, _, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let deposit_amount: u128 = mint_amount / (10_Field as u128); + let transfer_call: aztec::context::calls::PrivateCall<55, 4, PartialUintNote> = Token::at(token_contract_address).transfer_to_public_and_prepare_private_balance_increase(liquidity_provider, proxy, deposit_amount, 1_Field); + add_private_authwit_from_call(env, liquidity_provider, proxy, transfer_call); + let partial_note_field: Field = env.call_private(liquidity_provider, GenericProxy::at(proxy).forward_private_4_and_return(transfer_call.target_contract, transfer_call.selector, transfer_call.args)); + let partial_note: PartialUintNote = ::deserialize([partial_note_field]); + utils::check_private_balance(env, token_contract_address, liquidity_provider, mint_amount - deposit_amount); + utils::check_public_balance(env, token_contract_address, proxy, deposit_amount); + let change_amount: u128 = deposit_amount / (2_Field as u128); + env.call_public(proxy, Token::at(token_contract_address).finalize_transfer_to_private(change_amount, partial_note)); + utils::check_private_balance(env, token_contract_address, liquidity_provider, (mint_amount - deposit_amount) + change_amount); + utils::check_public_balance(env, token_contract_address, proxy, deposit_amount - change_amount); + } + + #[test(should_fail_with = "Balance too low")] + unconstrained fn transfer_to_public_and_prepare_private_balance_increase_failure_more_than_balance() { + let (env, token_contract_address, sender, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_amount: u128 = mint_amount + (1_Field as u128); + let _: PartialUintNote = env.call_private(sender, Token::at(token_contract_address).transfer_to_public_and_prepare_private_balance_increase(sender, recipient, transfer_amount, 0_Field)); + } + + #[test(should_fail_with = "Assertion failed: Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero")] + unconstrained fn transfer_to_public_and_prepare_private_balance_increase_failure_on_behalf_of_self_non_zero_nonce() { + let (env, token_contract_address, sender, recipient, mint_amount): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128) = utils::setup_and_mint_to_private(false); + let transfer_amount: u128 = mint_amount / (10_Field as u128); + let _: PartialUintNote = env.call_private(sender, Token::at(token_contract_address).transfer_to_public_and_prepare_private_balance_increase(sender, recipient, transfer_amount, random())); + } + + #[test(should_fail_with = "Unknown auth witness for message hash")] + unconstrained fn transfer_to_public_and_prepare_private_balance_increase_failure_on_behalf_of_other_no_approval() { + let (env, token_contract_address, sender, recipient, mint_amount, proxy): (aztec::test::helpers::test_environment::TestEnvironment, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, aztec::protocol::address::AztecAddress, u128, aztec::protocol::address::AztecAddress) = utils::setup_and_mint_to_private_with_proxy(); + let transfer_amount: u128 = mint_amount / (10_Field as u128); + let transfer_call: aztec::context::calls::PrivateCall<55, 4, PartialUintNote> = Token::at(token_contract_address).transfer_to_public_and_prepare_private_balance_increase(sender, recipient, transfer_amount, 1_Field); + env.call_private(sender, GenericProxy::at(proxy).forward_private_4(transfer_call.target_contract, transfer_call.selector, transfer_call.args)); + } + } + + pub mod utils { + use crate::Token; + use aztec::protocol::address::AztecAddress; + use aztec::test::helpers::test_environment::TestEnvironment; + + pub unconstrained fn setup(with_account_contracts: bool) -> (TestEnvironment, AztecAddress, AztecAddress, AztecAddress) { + let mut env: TestEnvironment = TestEnvironment::new(); + let (owner, recipient): (AztecAddress, AztecAddress) = if with_account_contracts { + let owner: AztecAddress = env.create_contract_account(); + let recipient: AztecAddress = env.create_contract_account(); + (owner, recipient) + } else { + let owner: AztecAddress = env.create_light_account(); + let recipient: AztecAddress = env.create_light_account(); + (owner, recipient) + }; + let initializer_call: aztec::context::calls::PublicCall<11, 64, ()> = Token::interface().constructor(owner, "TestToken0000000000000000000000", "TT00000000000000000000000000000", 18_u8); + let token_contract_address: AztecAddress = env.deploy("Token").with_public_initializer(owner, initializer_call); + (env, token_contract_address, owner, recipient) + } + + pub unconstrained fn setup_and_mint_to_public(with_account_contracts: bool) -> (TestEnvironment, AztecAddress, AztecAddress, AztecAddress, u128) { + let (env, token_contract_address, owner, recipient): (TestEnvironment, AztecAddress, AztecAddress, AztecAddress) = setup(with_account_contracts); + let mint_amount: u128 = 10000_Field as u128; + env.call_public(owner, Token::at(token_contract_address).mint_to_public(owner, mint_amount)); + (env, token_contract_address, owner, recipient, mint_amount) + } + + pub unconstrained fn setup_and_mint_amount_to_private(with_account_contracts: bool, mint_amount: u128) -> (TestEnvironment, AztecAddress, AztecAddress, AztecAddress, u128) { + let (env, token_contract_address, owner, recipient): (TestEnvironment, AztecAddress, AztecAddress, AztecAddress) = setup(with_account_contracts); + env.call_private(owner, Token::at(token_contract_address).mint_to_private(owner, mint_amount)); + (env, token_contract_address, owner, recipient, mint_amount) + } + + pub unconstrained fn setup_and_mint_to_private(with_account_contracts: bool) -> (TestEnvironment, AztecAddress, AztecAddress, AztecAddress, u128) { + let mint_amount: u128 = 10000_Field as u128; + setup_and_mint_amount_to_private(with_account_contracts, mint_amount) + } + + pub unconstrained fn check_public_balance(env: TestEnvironment, token_contract_address: AztecAddress, address: AztecAddress, address_amount: u128) { + assert(env.view_public(Token::at(token_contract_address).balance_of_public(address)) == address_amount); + } + + pub unconstrained fn check_private_balance(env: TestEnvironment, token_contract_address: AztecAddress, address: AztecAddress, address_amount: u128) { + assert(env.execute_utility(Token::at(token_contract_address).balance_of_private(address)) == address_amount); + } + + pub unconstrained fn setup_and_mint_to_private_with_proxy() -> (TestEnvironment, AztecAddress, AztecAddress, AztecAddress, u128, AztecAddress) { + let (mut env, token_contract_address, owner, recipient, mint_amount): (TestEnvironment, AztecAddress, AztecAddress, AztecAddress, u128) = setup_and_mint_to_private(true); + let proxy: AztecAddress = env.deploy("@generic_proxy_contract/GenericProxy").without_initializer(); + (env, token_contract_address, owner, recipient, mint_amount, proxy) + } + + pub unconstrained fn setup_and_mint_to_public_with_proxy() -> (TestEnvironment, AztecAddress, AztecAddress, AztecAddress, u128, AztecAddress) { + let (mut env, token_contract_address, owner, recipient, mint_amount): (TestEnvironment, AztecAddress, AztecAddress, AztecAddress, u128) = setup_and_mint_to_public(true); + let proxy: AztecAddress = env.deploy("@generic_proxy_contract/GenericProxy").without_initializer(); + (env, token_contract_address, owner, recipient, mint_amount, proxy) + } + } +} + +// Warning: the generated code has syntax errors diff --git a/noir-projects/noir-contracts-comp-failures/README.md b/noir-projects/noir-contracts-comp-failures/README.md deleted file mode 100644 index d158c4376e3e..000000000000 --- a/noir-projects/noir-contracts-comp-failures/README.md +++ /dev/null @@ -1,37 +0,0 @@ -## Noir Contracts Compilation Failures - -Aztec-nr contracts that are expected to fail to compile. Each case asserts that compilation fails *and* that the full set of `error:` diagnostics nargo emits matches a committed snapshot, so an unrelated regression that breaks compilation for a different reason does not silently pass. - -### Layout - -Each contract lives in `contracts//` with: - -- `Nargo.toml` — `type = "contract"`, depends on `aztec = { path = "../../../aztec-nr/aztec" }`. -- `src/main.nr` — the intentionally invalid contract. -- `expected_error` — one line per nargo `error:` headline (stripped of the `error: ` prefix), in emission order. An empty file means the contract is expected to compile successfully; see its `src/main.nr` doc comment for context. - -### Running - -```sh -./bootstrap.sh test # all cases -./bootstrap.sh test reserved_public_dispatch # one case -./bootstrap.sh test 'panic_on_*' # glob subset -``` - -For each contract the runner: - -1. Runs `nargo compile --silence-warnings` and asserts it fails. -2. Extracts every `error: ` line from stderr in order and strips the `error: ` prefix. -3. Requires the extracted list to equal, line for line, the non-blank lines of `expected_error`. Any difference — text, count, or order — fails the test. - -### Updating expected errors - -When a compiler or macro error message changes intentionally, regenerate snapshots locally: - -```sh -ACCEPT_SNAPSHOTS=1 ./bootstrap.sh test -``` - -The runner extracts each `error: ` headline, strips the prefix, and writes one per line — no manual trimming needed. If nargo emits no `error: ` diagnostics (e.g. an internal compiler panic), the full stderr is written and a `⚠` warning is printed; those cases need a manual trim before committing. - -CI refuses to run with `ACCEPT_SNAPSHOTS` set (`CI=1 ACCEPT_SNAPSHOTS=1` exits non-zero), so any drift between committed snapshots and actual stderr must be resolved intentionally by a developer. diff --git a/noir-projects/noir-contracts-comp-failures/bootstrap.sh b/noir-projects/noir-contracts-comp-failures/bootstrap.sh deleted file mode 100755 index 8983b882b43c..000000000000 --- a/noir-projects/noir-contracts-comp-failures/bootstrap.sh +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env bash -source $(git rev-parse --show-toplevel)/ci3/source_bootstrap - -# nargo command path relative to the individual contract directory -export NARGO=${NARGO:-../../../../noir/noir-repo/target/release/nargo} - -# Check that `nargo compile` stderr matches expected_error exactly. -# -# Every nargo compile error begins with a line `error: `. The runner -# extracts that ordered list of headlines (stripped of the `error: ` prefix) and -# requires it to equal, line for line, the non-blank lines in expected_error. -# Any change to the emitted errors — different text, different count, different -# order — fails the test and must be resolved by regenerating the snapshot. -# -# When ACCEPT_SNAPSHOTS=1 the runner skips assertion and writes every extracted -# headline (one per line) into expected_error. CI refuses this flag so any drift -# must be resolved by a developer locally. If nargo emits no `error: ` lines -# (e.g. an internal compiler panic), the full stderr is written instead and a -# warning is printed — such cases need a manual trim before committing. -check_compilation_error() { - local contract_dir=$1 - local expected_error_file="$contract_dir/expected_error" - - local actual_output - local compile_rc=0 - actual_output=$(cd "$contract_dir" && $NARGO compile --silence-warnings 2>&1) || compile_rc=$? - - local actual_headlines - actual_headlines=$(echo "$actual_output" | awk '/^error: /{sub(/^error: /, ""); print}') - - if [ -n "${ACCEPT_SNAPSHOTS:-}" ]; then - if [ "$compile_rc" -eq 0 ]; then - : > "$expected_error_file" - echo "↻ $contract_dir: wrote empty expected_error (compiled successfully)" - elif [ -n "$actual_headlines" ]; then - echo "$actual_headlines" > "$expected_error_file" - local count - count=$(printf '%s\n' "$actual_headlines" | wc -l | tr -d ' ') - echo "↻ $contract_dir: wrote $count headline(s) to expected_error" - else - echo "$actual_output" > "$expected_error_file" - echo "⚠ $contract_dir: no 'error: ' headlines found in stderr; wrote full output — trim manually" - fi - return 0 - fi - - if [ ! -f "$expected_error_file" ]; then - echo "✗ $contract_dir: No expected_error file. Run with ACCEPT_SNAPSHOTS=1 to generate one." - exit 1 - fi - - local -a expected_lines=() actual_lines=() - while IFS= read -r line; do - [ -z "$line" ] && continue - expected_lines+=("$line") - done < "$expected_error_file" - while IFS= read -r line; do - actual_lines+=("$line") - done <<< "$actual_headlines" - # `<<<` always appends a newline; if no headlines were found this leaves a - # single empty element that would miscount 0 as 1. - if [ "${#actual_lines[@]}" -eq 1 ] && [ -z "${actual_lines[0]}" ]; then - actual_lines=() - fi - - if [ "${#expected_lines[@]}" -ne "${#actual_lines[@]}" ]; then - echo "✗ $contract_dir: error count mismatch — expected ${#expected_lines[@]}, got ${#actual_lines[@]}" - echo "Expected lines:" - if [ "${#expected_lines[@]}" -eq 0 ]; then echo " (none)"; else printf ' %s\n' "${expected_lines[@]}"; fi - echo "Actual error headlines:" - if [ "${#actual_lines[@]}" -eq 0 ]; then echo " (none)"; else printf ' %s\n' "${actual_lines[@]}"; fi - echo "Full stderr:" - echo "$actual_output" - exit 1 - fi - - local i - for i in "${!expected_lines[@]}"; do - if [ "${actual_lines[$i]}" != "${expected_lines[$i]}" ]; then - echo "✗ $contract_dir: error $((i + 1)) does not match" - echo " Expected: ${expected_lines[$i]}" - echo " Actual: ${actual_lines[$i]}" - echo "Full stderr:" - echo "$actual_output" - exit 1 - fi - done - - if [ "${#expected_lines[@]}" -eq 0 ]; then - echo "⚠ $contract_dir: compiled successfully (see src/main.nr doc comment)" - else - echo "✓ $contract_dir: Compilation failed as expected with correct error(s)" - fi -} - -# Tests that compilation of contracts in noir-contracts-comp-failures fails with the expected error message. -# -# Optional arg: a shell glob to filter by contract directory name. Examples: -# ./bootstrap.sh test # all cases -# ./bootstrap.sh test reserved_public_dispatch -# ./bootstrap.sh test 'panic_on_*' -test() { - if [ -n "${ACCEPT_SNAPSHOTS:-}" ] && [ "${CI:-0}" = "1" ]; then - echo "ACCEPT_SNAPSHOTS is not permitted in CI. Snapshots must be regenerated locally and committed." >&2 - exit 1 - fi - - local pattern=${1:-} - local matched=0 - - for contract_dir in contracts/*/; do - [ -d "$contract_dir" ] || continue - if [ -n "$pattern" ]; then - local name=${contract_dir%/} - name=${name#contracts/} - # `case` pattern matching supports shell globs; leave $pattern unquoted. - case "$name" in - $pattern) ;; - *) continue ;; - esac - fi - check_compilation_error "$contract_dir" - matched=$((matched + 1)) - done - - if [ -n "$pattern" ] && [ "$matched" -eq 0 ]; then - echo "✗ no contracts matched pattern '$pattern'" >&2 - exit 1 - fi -} - -function test_cmds { - # Fairies want to run these tests on every PR - if [ "${TARGET_BRANCH:-}" = "merge-train/fairies" ]; then - hash=disabled-cache - else - hash=$(hash_str $(../../noir/bootstrap.sh hash) $(cache_content_hash ^noir-projects/noir-contracts-comp-failures)) - fi - echo "$hash ./noir-projects/noir-contracts-comp-failures/bootstrap.sh test" -} - -case "$cmd" in - *) - default_cmd_handler "$@" - ;; -esac diff --git a/noir-projects/noir-contracts-comp-failures/contracts/.gitignore b/noir-projects/noir-contracts-comp-failures/contracts/.gitignore deleted file mode 100644 index b60de5b5f2c9..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/target diff --git a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/expected_error deleted file mode 100644 index 81efd937b978..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_non_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[allow_phase_change] attribute can only be applied to #[external("private")] functions - foo is not diff --git a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/expected_error deleted file mode 100644 index 8938c1a408f3..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/allow_phase_change_on_utility_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[allow_phase_change] attribute cannot be applied to #[external("utility")] functions - foo diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/expected_error deleted file mode 100644 index eb13bb71d948..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorization_selector_collision/expected_error +++ /dev/null @@ -1,5 +0,0 @@ -Trait crate::authwit::authorization_interface::AuthorizationInterface not found -Could not resolve 'authwit' in path -check_trait_impl_where_clause_matches_trait_where_clause: missing trait ID -check_trait_impl_method_matches_declaration: missing trait impl -Selector collision detected between authorizations 'EventCollision8370082250' and 'EventCollision' diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_before_external/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_before_external/expected_error deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/expected_error deleted file mode 100644 index 1bbce0be00f8..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_from_wrong_type/expected_error +++ /dev/null @@ -1 +0,0 @@ -Argument from in function foo must be of type AztecAddress, but is of type Field diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/expected_error deleted file mode 100644 index 8b1cfa5ad9d6..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_from_param/expected_error +++ /dev/null @@ -1 +0,0 @@ -Function foo does not have a from parameter. Please specify which one to use in #[authorize_once("...", "authwit_nonce")] diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/expected_error deleted file mode 100644 index ed3aaf603d01..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_missing_nonce_param/expected_error +++ /dev/null @@ -1 +0,0 @@ -Function foo does not have a authwit_nonce. Please specify which one to use in #[authorize_once("from", "...")] diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/expected_error deleted file mode 100644 index bd57ebb6529a..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_nonce_wrong_type/expected_error +++ /dev/null @@ -1 +0,0 @@ -Argument authwit_nonce in function foo must be of type Field, but is of type u64 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/expected_error deleted file mode 100644 index f3f70104ef54..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_non_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[authorize_once] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither diff --git a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/expected_error deleted file mode 100644 index dbe74ea297fa..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/authorize_once_on_utility_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[authorize_once] attribute cannot be applied to #[external("utility")] functions - foo diff --git a/noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/expected_error deleted file mode 100644 index ef5de9454fe1..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/aztec_macro_too_many_args/expected_error +++ /dev/null @@ -1 +0,0 @@ -#[aztec] expects 0 or 1 arguments, got 2 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/bob_token/Nargo.toml b/noir-projects/noir-contracts-comp-failures/contracts/bob_token/Nargo.toml deleted file mode 100644 index c43230433fb1..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/bob_token/Nargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "bob_token" -type = "contract" -authors = [""] - -[dependencies] -aztec = { path = "../../../aztec-nr/aztec" } -balance_set = { path = "../../../aztec-nr/balance-set" } diff --git a/noir-projects/noir-contracts-comp-failures/contracts/bob_token/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/bob_token/expected_error deleted file mode 100644 index 29117d5b03e1..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/bob_token/expected_error +++ /dev/null @@ -1,38 +0,0 @@ -The #[internal] attribute cannot be applied to external functions - transfer_public is marked as both #[external] and #[internal("public")] -A function marked as #[external("private")] or #[internal("private")] must not have public Noir visibility - transfer_private's visibility is 'pub' -The #[view] attribute can only be applied to #[external("private")] or #[external("public")] functions - _assert_is_owner is neither -#[external("private")] or #[internal("private")] functions must not be unconstrained - mint_private is -Function _assert_is_owner must be marked as either #[external(...)], #[internal(...)], or #[test] -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -missing pub keyword on return type of function private_balance_of -cannot find `self` in this scope -missing pub keyword on return type of function public_balance_of -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope -cannot find `self` in this scope diff --git a/noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/expected_error deleted file mode 100644 index c1331b6dca3f..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/duplicate_storage/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[storage] macro can only be applied to a struct with name 'Storage', got 'Storage2' instead. diff --git a/noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/expected_error deleted file mode 100644 index 5d2027e29796..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/event_selector_collision/expected_error +++ /dev/null @@ -1 +0,0 @@ -Event selector collision detected between events 'EventCollision8370082250' and 'EventCollision' diff --git a/noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/expected_error deleted file mode 100644 index bf93cad5e5d7..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/external_and_internal_together/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[internal] attribute cannot be applied to external functions - foo is marked as both #[external] and #[internal("private")] diff --git a/noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/expected_error deleted file mode 100644 index c1331b6dca3f..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/incorrect_storage_struct_name/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[storage] macro can only be applied to a struct with name 'Storage', got 'Storage2' instead. diff --git a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/expected_error deleted file mode 100644 index 5c684056da32..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_non_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[initializer] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither diff --git a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/expected_error deleted file mode 100644 index 73500d3e2c07..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/initializer_on_utility_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[initializer] attribute cannot be applied to #[external("utility")] functions - foo diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_event/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/invalid_event/expected_error deleted file mode 100644 index 52ea26ac60ee..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/invalid_event/expected_error +++ /dev/null @@ -1 +0,0 @@ -event's serialized length exceeds the maximum allowed for private events diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/expected_error deleted file mode 100644 index e53202f2683b..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/invalid_external_function_type/expected_error +++ /dev/null @@ -1 +0,0 @@ -Function 'invalid_external_function_type' is marked as #[external("invalid")], but 'invalid' is not a valid external function type. External functions must be one of 'private', 'public' or 'utility' diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/expected_error deleted file mode 100644 index 598737fea58a..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/invalid_internal_function_type/expected_error +++ /dev/null @@ -1 +0,0 @@ -Function 'foo' is marked as #[internal("utility")], but 'utility' is not a valid internal function type. Internal functions must be one of 'private', 'public' diff --git a/noir-projects/noir-contracts-comp-failures/contracts/invalid_note/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/invalid_note/expected_error deleted file mode 100644 index 02c046ffd7ab..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/invalid_note/expected_error +++ /dev/null @@ -1 +0,0 @@ -InvalidNote has a packed length of 9 fields, which exceeds the maximum allowed length of 8 fields. See https://docs.aztec.network/errors/4 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/expected_error deleted file mode 100644 index 2688275a93b9..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/marked_private_unconstrained/expected_error +++ /dev/null @@ -1 +0,0 @@ -#[external("private")] or #[internal("private")] functions must not be unconstrained - unconstrained_private_function is diff --git a/noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/expected_error deleted file mode 100644 index 8758aa579ffc..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/marked_public_unconstrained/expected_error +++ /dev/null @@ -1 +0,0 @@ -#[external("public")] or #[internal("public")] functions must not be unconstrained - unconstrained_public_function is diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/expected_error deleted file mode 100644 index 69b930611586..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_non_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[noinitcheck] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/expected_error deleted file mode 100644 index 1e1dfaca9e12..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_on_utility_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[noinitcheck] attribute cannot be applied to #[external("utility")] functions - foo diff --git a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/expected_error deleted file mode 100644 index 17c3dff427ad..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/noinitcheck_without_initializer/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[noinitcheck] attribute is unnecessary for contracts with no #[initializer] functions diff --git a/noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/expected_error deleted file mode 100644 index 0752e0c1a17f..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/non_deserializable/expected_error +++ /dev/null @@ -1,6 +0,0 @@ -Contract function 'bad_private_return' returns a value of type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. -Parameter '_p' of contract function 'bad_private_param' has type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. -Contract function 'bad_public_return' returns a value of type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. -Parameter '_p' of contract function 'bad_public_param' has type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. -Contract function 'bad_utility_return' returns a value of type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. -Parameter '_p' of contract function 'bad_utility_param' has type NotDeserializable, which does not implement the Deserialize trait. Add #[derive(Deserialize)] to NotDeserializable's declaration. diff --git a/noir-projects/noir-contracts-comp-failures/contracts/non_serializable/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/non_serializable/expected_error deleted file mode 100644 index 33a63c051f3a..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/non_serializable/expected_error +++ /dev/null @@ -1,6 +0,0 @@ -Contract function 'bad_private_return' returns a value of type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. -Parameter '_p' of contract function 'bad_private_param' has type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. -Contract function 'bad_public_return' returns a value of type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. -Parameter '_p' of contract function 'bad_public_param' has type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. -Contract function 'bad_utility_return' returns a value of type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. -Parameter '_p' of contract function 'bad_utility_param' has type NotSerializable, which does not implement the Serialize trait. Add #[derive(Serialize)] to NotSerializable's declaration. diff --git a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/expected_error deleted file mode 100644 index e2cf366b083d..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_non_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[only_self] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither diff --git a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/expected_error deleted file mode 100644 index 67b493e28c6a..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/only_self_on_utility_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[only_self] attribute cannot be applied to #[external("utility")] functions - foo diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/expected_error deleted file mode 100644 index 03dcdf55e48b..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_external_fn_call/expected_error +++ /dev/null @@ -1 +0,0 @@ -Direct invocation of private functions is not supported. You attempted to call arbitrary_external_function. See https://docs.aztec.network/errors/6 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/expected_error deleted file mode 100644 index 70eb1d78dfed..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_private_internal_fn_call/expected_error +++ /dev/null @@ -1 +0,0 @@ -Direct invocation of private internal functions is not supported. You attempted to call arbitrary_private_function. See https://docs.aztec.network/errors/6 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/expected_error deleted file mode 100644 index b698579729a9..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_external_fn_call/expected_error +++ /dev/null @@ -1 +0,0 @@ -Direct invocation of public functions is not supported. You attempted to call arbitrary_external_function. See https://docs.aztec.network/errors/6 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/expected_error deleted file mode 100644 index b50d8f6b8a7e..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_public_internal_fn_call/expected_error +++ /dev/null @@ -1 +0,0 @@ -Direct invocation of public internal functions is not supported. You attempted to call arbitrary_public_function. See https://docs.aztec.network/errors/6 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/expected_error deleted file mode 100644 index d83a13317cd4..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_direct_utility_external_fn_call/expected_error +++ /dev/null @@ -1 +0,0 @@ -Direct invocation of utility functions is not supported. You attempted to call arbitrary_external_function. See https://docs.aztec.network/errors/6 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/expected_error deleted file mode 100644 index 691f42b15075..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_call/expected_error +++ /dev/null @@ -1,2 +0,0 @@ -Could not resolve 'ZERO' in path -Your private call needs to be passed into the `self.call(...)` method to be executed (e.g. `self.call(MyContract::at(address).my_private_function(...args))` diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/expected_error deleted file mode 100644 index 1ef6eef9437f..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_private_static_call/expected_error +++ /dev/null @@ -1,2 +0,0 @@ -Could not resolve 'ZERO' in path -Your private static call needs to be passed into the `self.view(...)` method to be executed (e.g. `self.view(MyContract::at(address).my_private_static_function(...args))` diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/expected_error deleted file mode 100644 index aba4880076cb..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_call/expected_error +++ /dev/null @@ -1,2 +0,0 @@ -Could not resolve 'ZERO' in path -Your public call needs to be passed into the `self.call(...)`, `self.enqueue(...)` or `self.enqueue_incognito(...)` method to be executed (e.g. `self.call(MyContract::at(address).my_public_function(...args))` diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/expected_error deleted file mode 100644 index 663ed39ae75b..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_incorrectly_performed_public_static_call/expected_error +++ /dev/null @@ -1,2 +0,0 @@ -Could not resolve 'ZERO' in path -Your public static call needs to be passed into the `self.view(...)`, `self.enqueue_view(...)` or `self.enqueue_view_incognito(...)` method to be executed (e.g. `self.view(MyContract::at(address).my_public_static_function(...args))` diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/expected_error deleted file mode 100644 index a557e8eba5d2..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_non_state_var_in_storage/expected_error +++ /dev/null @@ -1,3 +0,0 @@ -Type NonStateVar does not implement StateVariable and hence cannot be placed in Storage struct. -Could not resolve 'init' in path -Type annotation needed diff --git a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/expected_error deleted file mode 100644 index 912e28180292..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/panic_on_owned_state_var_in_storage/expected_error +++ /dev/null @@ -1,3 +0,0 @@ -Type PrivateImmutable implements OwnedStateVariable and hence cannot be placed in Storage struct without being wrapped in Owned. Wrap the type in Owned<..., Context>. -Could not resolve 'init' in path -Type annotation needed diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/expected_error deleted file mode 100644 index 669dc8c04480..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/pub_private_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -A function marked as #[external("private")] or #[internal("private")] must not have public Noir visibility - foo's visibility is 'pub' diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/expected_error deleted file mode 100644 index 044cc7b24636..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/pub_public_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -A function marked as #[external("public")] or #[internal("public")] must not have public Noir visibility - foo's visibility is 'pub' diff --git a/noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/expected_error deleted file mode 100644 index e619f508ff8e..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/pub_utility_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -A function marked as #[external("utility")] must not have public Noir visibility - foo's visibility is 'pub' diff --git a/noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/expected_error deleted file mode 100644 index abb57930739e..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/public_allow_phase_change/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[allow_phase_change] attribute cannot be applied to #[external("public")] functions - foo diff --git a/noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/expected_error deleted file mode 100644 index 3ac5de4c49d9..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/public_function_selector_collision/expected_error +++ /dev/null @@ -1 +0,0 @@ -Public function selector collision detected between functions 'fn_selector_collision_1442740381' and 'fn_selector_collision' diff --git a/noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/expected_error deleted file mode 100644 index e7bef0a515de..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/reserved_emit_public_init_nullifier/expected_error +++ /dev/null @@ -1 +0,0 @@ -Function name '__emit_public_init_nullifier' is reserved for internal use diff --git a/noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/expected_error deleted file mode 100644 index 6652431061c4..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/reserved_public_dispatch/expected_error +++ /dev/null @@ -1 +0,0 @@ -Function name 'public_dispatch' is reserved for internal use diff --git a/noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/expected_error deleted file mode 100644 index 5923b9ac25d3..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/unmacroified_function_in_contract/expected_error +++ /dev/null @@ -1 +0,0 @@ -Function foo must be marked as either #[external(...)], #[internal(...)], or #[test] diff --git a/noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/expected_error deleted file mode 100644 index 3aa9a27613c7..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/user_defined_offchain_receive/expected_error +++ /dev/null @@ -1 +0,0 @@ -User-defined 'offchain_receive' is not allowed. The function is auto-injected by the #[aztec] macro. See https://docs.aztec.network/errors/7 diff --git a/noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/expected_error deleted file mode 100644 index aeeba4db64c8..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/utility_not_unconstrained/expected_error +++ /dev/null @@ -1 +0,0 @@ -#[external("utility")] must be unconstrained - constrained_utility_function isn't diff --git a/noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/expected_error deleted file mode 100644 index 237014f4076a..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/view_on_non_external_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[view] attribute can only be applied to #[external("private")] or #[external("public")] functions - foo is neither diff --git a/noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/expected_error b/noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/expected_error deleted file mode 100644 index b51bee13a6a6..000000000000 --- a/noir-projects/noir-contracts-comp-failures/contracts/view_on_utility_fn/expected_error +++ /dev/null @@ -1 +0,0 @@ -The #[view] attribute cannot be applied to #[external("utility")] functions - foo diff --git a/pied! b/pied! new file mode 100644 index 000000000000..848aa01d6543 --- /dev/null +++ b/pied! @@ -0,0 +1,43 @@ +diff --git a/cspell.json b/cspell.json +index 9766afc1ea..f792d7920a 100644 +--- a/cspell.json ++++ b/cspell.json +@@ -71,6 +71,7 @@ + "cimg", + "ciphertext", + "ciphertexts", ++ "clippy", + "clonedeep", + "clonedeepwith", + "cmd", +@@ -171,6 +172,7 @@ + "includable", + "incrementation", + "indexeddb", ++ "INSTA", + "interruptible", + "IPFS", + "isequal", +@@ -367,8 +369,8 @@ + "unfinalized", + "uniquified", + "uniquify", +- "unlinkability", + "unkonstrained", ++ "unlinkability", + "unnullify", + "unpadded", + "unprefixed", +diff --git a/noir-projects/bootstrap.sh b/noir-projects/bootstrap.sh +index 9bd80aeea5..cadced1662 100755 +--- a/noir-projects/bootstrap.sh ++++ b/noir-projects/bootstrap.sh +@@ -26,7 +26,7 @@ function build { + } +  + function test_cmds { +- parallel -k ./{}/bootstrap.sh test_cmds ::: noir-protocol-circuits noir-contracts aztec-nr noir-contracts-comp-failures ++ parallel -k ./{}/bootstrap.sh test_cmds ::: noir-protocol-circuits noir-contracts aztec-nr noir-contract-snapshots + } +  + function test { From 2465ec26ee66f90b193f8feb7e3a2fbb1ad80129 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 7 May 2026 15:12:54 -0400 Subject: [PATCH 2/6] rename folder --- noir-projects/bootstrap.sh | 2 +- .../.gitignore | 0 .../Cargo.toml | 0 .../README.md | 0 .../bootstrap.sh | 8 ++-- .../build.rs | 0 .../src/lib.rs | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../authorize_once_from_wrong_type/Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../authorize_once_on_utility_fn/Nargo.toml | 0 .../authorize_once_on_utility_fn/src/main.nr | 0 .../aztec_macro_too_many_args/Nargo.toml | 0 .../aztec_macro_too_many_args/src/main.nr | 0 .../compile_failure/bob_token/Nargo.toml | 0 .../compile_failure/bob_token/src/main.nr | 0 .../duplicate_storage/Nargo.toml | 0 .../duplicate_storage/src/main.nr | 0 .../event_selector_collision/Nargo.toml | 0 .../event_selector_collision/src/main.nr | 0 .../external_and_internal_together/Nargo.toml | 0 .../src/main.nr | 0 .../incorrect_storage_struct_name/Nargo.toml | 0 .../incorrect_storage_struct_name/src/main.nr | 0 .../initializer_on_non_external_fn/Nargo.toml | 0 .../src/main.nr | 0 .../initializer_on_utility_fn/Nargo.toml | 0 .../initializer_on_utility_fn/src/main.nr | 0 .../compile_failure/invalid_event/Nargo.toml | 0 .../invalid_event/src/invalid_event.nr | 0 .../compile_failure/invalid_event/src/main.nr | 0 .../invalid_external_function_type/Nargo.toml | 0 .../src/main.nr | 0 .../invalid_internal_function_type/Nargo.toml | 0 .../src/main.nr | 0 .../compile_failure/invalid_note/Nargo.toml | 0 .../invalid_note/src/invalid_note.nr | 0 .../compile_failure/invalid_note/src/main.nr | 0 .../marked_private_unconstrained/Nargo.toml | 0 .../marked_private_unconstrained/src/main.nr | 0 .../marked_public_unconstrained/Nargo.toml | 0 .../marked_public_unconstrained/src/main.nr | 0 ...constrained-MarkedPublicUnconstrained.json | 0 .../noinitcheck_on_non_external_fn/Nargo.toml | 0 .../src/main.nr | 0 .../noinitcheck_on_utility_fn/Nargo.toml | 0 .../noinitcheck_on_utility_fn/src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../non_deserializable/Nargo.toml | 0 .../non_deserializable/src/main.nr | 0 .../non_serializable/Nargo.toml | 0 .../non_serializable/src/main.nr | 0 .../only_self_on_non_external_fn/Nargo.toml | 0 .../only_self_on_non_external_fn/src/main.nr | 0 .../only_self_on_utility_fn/Nargo.toml | 0 .../only_self_on_utility_fn/src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../pub_private_external_fn/Nargo.toml | 0 .../pub_private_external_fn/src/main.nr | 0 .../pub_public_external_fn/Nargo.toml | 0 .../pub_public_external_fn/src/main.nr | 0 .../pub_utility_external_fn/Nargo.toml | 0 .../pub_utility_external_fn/src/main.nr | 0 .../public_allow_phase_change/Nargo.toml | 0 .../public_allow_phase_change/src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../reserved_public_dispatch/Nargo.toml | 0 .../reserved_public_dispatch/src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../user_defined_offchain_receive/Nargo.toml | 0 .../user_defined_offchain_receive/src/main.nr | 0 .../utility_not_unconstrained/Nargo.toml | 0 .../utility_not_unconstrained/src/main.nr | 0 .../view_on_non_external_fn/Nargo.toml | 0 .../view_on_non_external_fn/src/main.nr | 0 .../view_on_utility_fn/Nargo.toml | 0 .../view_on_utility_fn/src/main.nr | 0 .../authorize_once_before_external/Nargo.toml | 0 .../src/main.nr | 0 ..._external-AuthorizeOnceBeforeExternal.json | 0 ...ernal-AuthorizeOnceBeforeExternal.json.bak | 0 .../tests/snapshots.rs | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../bob_token/snapshots__stderr.snap | 0 .../duplicate_storage/snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../invalid_event/snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../invalid_note/snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../non_deserializable/snapshots__stderr.snap | 0 .../non_serializable/snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../view_on_utility_fn/snapshots__stderr.snap | 0 .../snapshots__stderr.snap | 0 .../amm_contract/snapshots__expanded.snap | 0 .../snapshots__expanded.snap | 0 .../snapshots__expanded.snap | 0 .../snapshots__expanded.snap | 0 .../token_contract/snapshots__expanded.snap | 0 pied! | 43 ------------------- 181 files changed, 5 insertions(+), 48 deletions(-) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/.gitignore (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/Cargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/README.md (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/bootstrap.sh (85%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/build.rs (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/src/lib.rs (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/allow_phase_change_on_non_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/allow_phase_change_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/allow_phase_change_on_utility_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/allow_phase_change_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorization_selector_collision/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorization_selector_collision/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_from_wrong_type/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_from_wrong_type/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_missing_from_param/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_missing_from_param/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_missing_nonce_param/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_missing_nonce_param/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_nonce_wrong_type/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_nonce_wrong_type/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_on_non_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_on_utility_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/authorize_once_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/aztec_macro_too_many_args/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/aztec_macro_too_many_args/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/bob_token/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/bob_token/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/duplicate_storage/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/duplicate_storage/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/event_selector_collision/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/event_selector_collision/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/external_and_internal_together/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/external_and_internal_together/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/incorrect_storage_struct_name/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/incorrect_storage_struct_name/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/initializer_on_non_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/initializer_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/initializer_on_utility_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/initializer_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_event/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_event/src/invalid_event.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_event/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_external_function_type/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_external_function_type/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_internal_function_type/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_internal_function_type/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_note/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_note/src/invalid_note.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/invalid_note/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/marked_private_unconstrained/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/marked_private_unconstrained/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/marked_public_unconstrained/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/marked_public_unconstrained/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/noinitcheck_on_non_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/noinitcheck_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/noinitcheck_on_utility_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/noinitcheck_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/noinitcheck_without_initializer/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/noinitcheck_without_initializer/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/non_deserializable/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/non_deserializable/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/non_serializable/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/non_serializable/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/only_self_on_non_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/only_self_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/only_self_on_utility_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/only_self_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_private_external_fn_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_private_external_fn_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_public_external_fn_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_public_external_fn_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_non_state_var_in_storage/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_non_state_var_in_storage/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_owned_state_var_in_storage/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/panic_on_owned_state_var_in_storage/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/pub_private_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/pub_private_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/pub_public_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/pub_public_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/pub_utility_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/pub_utility_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/public_allow_phase_change/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/public_allow_phase_change/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/public_function_selector_collision/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/public_function_selector_collision/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/reserved_emit_public_init_nullifier/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/reserved_emit_public_init_nullifier/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/reserved_public_dispatch/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/reserved_public_dispatch/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/unmacroified_function_in_contract/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/unmacroified_function_in_contract/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/user_defined_offchain_receive/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/user_defined_offchain_receive/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/utility_not_unconstrained/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/utility_not_unconstrained/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/view_on_non_external_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/view_on_non_external_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/view_on_utility_fn/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_failure/view_on_utility_fn/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_success/authorize_once_before_external/Nargo.toml (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_success/authorize_once_before_external/src/main.nr (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots.rs (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/expand/amm_contract/snapshots__expanded.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap (100%) rename noir-projects/{noir-contract-snapshots => contract-snapshots}/tests/snapshots/expand/token_contract/snapshots__expanded.snap (100%) delete mode 100644 pied! diff --git a/noir-projects/bootstrap.sh b/noir-projects/bootstrap.sh index cadced1662e0..006f75495900 100755 --- a/noir-projects/bootstrap.sh +++ b/noir-projects/bootstrap.sh @@ -26,7 +26,7 @@ function build { } function test_cmds { - parallel -k ./{}/bootstrap.sh test_cmds ::: noir-protocol-circuits noir-contracts aztec-nr noir-contract-snapshots + parallel -k ./{}/bootstrap.sh test_cmds ::: noir-protocol-circuits noir-contracts aztec-nr contract-snapshots } function test { diff --git a/noir-projects/noir-contract-snapshots/.gitignore b/noir-projects/contract-snapshots/.gitignore similarity index 100% rename from noir-projects/noir-contract-snapshots/.gitignore rename to noir-projects/contract-snapshots/.gitignore diff --git a/noir-projects/noir-contract-snapshots/Cargo.toml b/noir-projects/contract-snapshots/Cargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/Cargo.toml rename to noir-projects/contract-snapshots/Cargo.toml diff --git a/noir-projects/noir-contract-snapshots/README.md b/noir-projects/contract-snapshots/README.md similarity index 100% rename from noir-projects/noir-contract-snapshots/README.md rename to noir-projects/contract-snapshots/README.md diff --git a/noir-projects/noir-contract-snapshots/bootstrap.sh b/noir-projects/contract-snapshots/bootstrap.sh similarity index 85% rename from noir-projects/noir-contract-snapshots/bootstrap.sh rename to noir-projects/contract-snapshots/bootstrap.sh index 721f5eb41295..f4ae19760903 100755 --- a/noir-projects/noir-contract-snapshots/bootstrap.sh +++ b/noir-projects/contract-snapshots/bootstrap.sh @@ -6,7 +6,7 @@ export NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} # Build the snapshot test binaries (compiles build.rs codegen too) and run Rust lints. function build { - echo_header "noir-contract-snapshots build" + echo_header "contract-snapshots build" denoise "cargo build --tests" denoise "cargo fmt --check" denoise "cargo clippy --all-targets" @@ -15,7 +15,7 @@ function build { # Run the snapshot tests. CI rejects INSTA_UPDATE so any drift between # committed snapshots and reality must be resolved intentionally by a developer. function test { - echo_header "noir-contract-snapshots test" + echo_header "contract-snapshots test" if [ "${CI:-0}" = "1" ] && [ -n "${INSTA_UPDATE:-}" ] && [ "${INSTA_UPDATE}" != "no" ]; then echo "INSTA_UPDATE is not permitted in CI. Run 'cargo insta accept' locally and commit." >&2 exit 1 @@ -30,12 +30,12 @@ function test_cmds { hash=$(hash_str \ $(../../noir/bootstrap.sh hash) \ $(cache_content_hash \ - ^noir-projects/noir-contract-snapshots \ + ^noir-projects/contract-snapshots \ ^noir-projects/noir-contracts/contracts/app \ ^noir-projects/noir-contracts/contracts/test \ ^noir-projects/aztec-nr)) fi - echo "$hash ./noir-projects/noir-contract-snapshots/bootstrap.sh test" + echo "$hash ./noir-projects/contract-snapshots/bootstrap.sh test" } case "$cmd" in diff --git a/noir-projects/noir-contract-snapshots/build.rs b/noir-projects/contract-snapshots/build.rs similarity index 100% rename from noir-projects/noir-contract-snapshots/build.rs rename to noir-projects/contract-snapshots/build.rs diff --git a/noir-projects/noir-contract-snapshots/src/lib.rs b/noir-projects/contract-snapshots/src/lib.rs similarity index 100% rename from noir-projects/noir-contract-snapshots/src/lib.rs rename to noir-projects/contract-snapshots/src/lib.rs diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/allow_phase_change_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/allow_phase_change_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/authorization_selector_collision/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorization_selector_collision/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/authorization_selector_collision/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorization_selector_collision/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorization_selector_collision/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_from_wrong_type/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_missing_from_param/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_missing_nonce_param/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_nonce_wrong_type/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/authorize_once_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/aztec_macro_too_many_args/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/bob_token/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/bob_token/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/bob_token/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/bob_token/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/bob_token/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/duplicate_storage/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/duplicate_storage/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/duplicate_storage/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/duplicate_storage/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/duplicate_storage/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/event_selector_collision/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/event_selector_collision/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/event_selector_collision/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/event_selector_collision/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/event_selector_collision/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/external_and_internal_together/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/external_and_internal_together/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/external_and_internal_together/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/external_and_internal_together/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/external_and_internal_together/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/incorrect_storage_struct_name/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/initializer_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/initializer_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_event/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_event/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/src/invalid_event.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_event/src/invalid_event.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/src/invalid_event.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_event/src/invalid_event.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_event/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_event/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_event/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_external_function_type/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_external_function_type/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_external_function_type/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_external_function_type/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_external_function_type/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_internal_function_type/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_note/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_note/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/src/invalid_note.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_note/src/invalid_note.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/src/invalid_note.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_note/src/invalid_note.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/invalid_note/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/invalid_note/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/invalid_note/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/marked_private_unconstrained/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json b/noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json rename to noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/noinitcheck_without_initializer/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/non_deserializable/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/non_deserializable/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/non_deserializable/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_deserializable/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/non_deserializable/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/non_serializable/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/non_serializable/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/non_serializable/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/non_serializable/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/non_serializable/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/only_self_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/only_self_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_private_external_fn_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_private_internal_fn_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_public_external_fn_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_public_internal_fn_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_direct_utility_external_fn_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_private_static_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_incorrectly_performed_public_static_call/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_non_state_var_in_storage/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/panic_on_owned_state_var_in_storage/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/pub_private_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/pub_private_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/pub_private_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_private_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/pub_private_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/pub_public_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/pub_public_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/pub_public_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_public_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/pub_public_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/pub_utility_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/public_allow_phase_change/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/public_allow_phase_change/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/public_allow_phase_change/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_allow_phase_change/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/public_allow_phase_change/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/public_function_selector_collision/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/public_function_selector_collision/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/public_function_selector_collision/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/public_function_selector_collision/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/public_function_selector_collision/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/reserved_emit_public_init_nullifier/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/reserved_public_dispatch/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/unmacroified_function_in_contract/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/user_defined_offchain_receive/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/utility_not_unconstrained/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/view_on_non_external_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_failure/view_on_utility_fn/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_failure/view_on_utility_fn/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_failure/view_on_utility_fn/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_failure/view_on_utility_fn/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_failure/view_on_utility_fn/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/Nargo.toml b/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/Nargo.toml similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/Nargo.toml rename to noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/Nargo.toml diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/src/main.nr b/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/src/main.nr similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/src/main.nr rename to noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/src/main.nr diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json b/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json rename to noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json diff --git a/noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak b/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak similarity index 100% rename from noir-projects/noir-contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak rename to noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots.rs b/noir-projects/contract-snapshots/tests/snapshots.rs similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots.rs rename to noir-projects/contract-snapshots/tests/snapshots.rs diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_non_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/allow_phase_change_on_utility_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorization_selector_collision/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_from_wrong_type/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_from_param/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_missing_nonce_param/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_nonce_wrong_type/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_non_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/authorize_once_on_utility_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/aztec_macro_too_many_args/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/bob_token/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/duplicate_storage/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/event_selector_collision/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/external_and_internal_together/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/incorrect_storage_struct_name/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/initializer_on_non_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/initializer_on_utility_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/invalid_event/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/invalid_external_function_type/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/invalid_internal_function_type/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/invalid_note/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/marked_private_unconstrained/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/marked_public_unconstrained/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_non_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/noinitcheck_on_utility_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/noinitcheck_without_initializer/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/non_deserializable/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/non_serializable/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/only_self_on_non_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/only_self_on_utility_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_external_fn_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_private_internal_fn_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_external_fn_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_public_internal_fn_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_direct_utility_external_fn_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_private_static_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_incorrectly_performed_public_static_call/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_non_state_var_in_storage/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/panic_on_owned_state_var_in_storage/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/pub_private_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/pub_public_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/pub_utility_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/public_allow_phase_change/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/public_function_selector_collision/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/reserved_emit_public_init_nullifier/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/reserved_public_dispatch/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/unmacroified_function_in_contract/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/user_defined_offchain_receive/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/utility_not_unconstrained/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/view_on_non_external_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_failure/view_on_utility_fn/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap b/noir-projects/contract-snapshots/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap rename to noir-projects/contract-snapshots/tests/snapshots/compile_success/authorize_once_before_external/snapshots__stderr.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/amm_contract/snapshots__expanded.snap b/noir-projects/contract-snapshots/tests/snapshots/expand/amm_contract/snapshots__expanded.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/expand/amm_contract/snapshots__expanded.snap rename to noir-projects/contract-snapshots/tests/snapshots/expand/amm_contract/snapshots__expanded.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap b/noir-projects/contract-snapshots/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap rename to noir-projects/contract-snapshots/tests/snapshots/expand/avm_gadgets_test_contract/snapshots__expanded.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap b/noir-projects/contract-snapshots/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap rename to noir-projects/contract-snapshots/tests/snapshots/expand/avm_test_contract/snapshots__expanded.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap b/noir-projects/contract-snapshots/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap rename to noir-projects/contract-snapshots/tests/snapshots/expand/storage_proof_test_contract/snapshots__expanded.snap diff --git a/noir-projects/noir-contract-snapshots/tests/snapshots/expand/token_contract/snapshots__expanded.snap b/noir-projects/contract-snapshots/tests/snapshots/expand/token_contract/snapshots__expanded.snap similarity index 100% rename from noir-projects/noir-contract-snapshots/tests/snapshots/expand/token_contract/snapshots__expanded.snap rename to noir-projects/contract-snapshots/tests/snapshots/expand/token_contract/snapshots__expanded.snap diff --git a/pied! b/pied! deleted file mode 100644 index 848aa01d6543..000000000000 --- a/pied! +++ /dev/null @@ -1,43 +0,0 @@ -diff --git a/cspell.json b/cspell.json -index 9766afc1ea..f792d7920a 100644 ---- a/cspell.json -+++ b/cspell.json -@@ -71,6 +71,7 @@ - "cimg", - "ciphertext", - "ciphertexts", -+ "clippy", - "clonedeep", - "clonedeepwith", - "cmd", -@@ -171,6 +172,7 @@ - "includable", - "incrementation", - "indexeddb", -+ "INSTA", - "interruptible", - "IPFS", - "isequal", -@@ -367,8 +369,8 @@ - "unfinalized", - "uniquified", - "uniquify", -- "unlinkability", - "unkonstrained", -+ "unlinkability", - "unnullify", - "unpadded", - "unprefixed", -diff --git a/noir-projects/bootstrap.sh b/noir-projects/bootstrap.sh -index 9bd80aeea5..cadced1662 100755 ---- a/noir-projects/bootstrap.sh -+++ b/noir-projects/bootstrap.sh -@@ -26,7 +26,7 @@ function build { - } -  - function test_cmds { -- parallel -k ./{}/bootstrap.sh test_cmds ::: noir-protocol-circuits noir-contracts aztec-nr noir-contracts-comp-failures -+ parallel -k ./{}/bootstrap.sh test_cmds ::: noir-protocol-circuits noir-contracts aztec-nr noir-contract-snapshots - } -  - function test { From d35b80d1f50a8eb755813676dee55e0fa46910bf Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 7 May 2026 15:14:27 -0400 Subject: [PATCH 3/6] rename --- noir-projects/contract-snapshots/Cargo.toml | 2 +- noir-projects/contract-snapshots/build.rs | 2 +- noir-projects/contract-snapshots/tests/snapshots.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/noir-projects/contract-snapshots/Cargo.toml b/noir-projects/contract-snapshots/Cargo.toml index edc56c445319..1fc3e8e0f3b4 100644 --- a/noir-projects/contract-snapshots/Cargo.toml +++ b/noir-projects/contract-snapshots/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "noir-contract-snapshots" +name = "contract-snapshots" version = "0.1.0" edition = "2024" publish = false diff --git a/noir-projects/contract-snapshots/build.rs b/noir-projects/contract-snapshots/build.rs index 32f4f73bf0be..22949c8a6e68 100644 --- a/noir-projects/contract-snapshots/build.rs +++ b/noir-projects/contract-snapshots/build.rs @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf}; /// macro-induced diffs and benchmark deltas show up on the same review. /// /// To add a case: append an entry here and run -/// `cargo insta test --accept -p noir-contract-snapshots`. +/// `cargo insta test --accept -p contract-snapshots`. const EXPAND_CASES: &[(&str, &str)] = &[ ( "token_contract", diff --git a/noir-projects/contract-snapshots/tests/snapshots.rs b/noir-projects/contract-snapshots/tests/snapshots.rs index a0702d6009f2..f89ef8a41e71 100644 --- a/noir-projects/contract-snapshots/tests/snapshots.rs +++ b/noir-projects/contract-snapshots/tests/snapshots.rs @@ -5,7 +5,7 @@ fn manifest_dir() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) } -/// `noir-projects/noir-contract-snapshots/` → repo root. +/// `noir-projects/contract-snapshots/` -> repo root. fn repo_root() -> PathBuf { manifest_dir() .parent() From 7591681477b8379d567c44817fd2e347d2586728 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 7 May 2026 15:41:00 -0400 Subject: [PATCH 4/6] gitignore and remove target artifacts --- noir-projects/contract-snapshots/.gitignore | 2 +- .../marked_public_unconstrained-MarkedPublicUnconstrained.json | 1 - ...horize_once_before_external-AuthorizeOnceBeforeExternal.json | 1 - ...ze_once_before_external-AuthorizeOnceBeforeExternal.json.bak | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json delete mode 100644 noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json delete mode 100644 noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak diff --git a/noir-projects/contract-snapshots/.gitignore b/noir-projects/contract-snapshots/.gitignore index ca98cd96efdc..e7fa33123dd6 100644 --- a/noir-projects/contract-snapshots/.gitignore +++ b/noir-projects/contract-snapshots/.gitignore @@ -1,2 +1,2 @@ -/target/ +/**/target/ Cargo.lock diff --git a/noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json b/noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json deleted file mode 100644 index 59ae2162c3bf..000000000000 --- a/noir-projects/contract-snapshots/test_programs/compile_failure/marked_public_unconstrained/target/marked_public_unconstrained-MarkedPublicUnconstrained.json +++ /dev/null @@ -1 +0,0 @@ -{"noir_version":"1.0.0-beta.20+ad02a20cd80b3e8a6189722b11a625998e578435","name":"MarkedPublicUnconstrained","functions":[{"name":"offchain_receive","hash":"12116004815156287947","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]},"visibility":"private"}],"return_type":null,"error_types":{"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"}}},"bytecode":"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","debug_symbols":"tZnRbhs5DEX/xc95ECmJEvMrQVG4qVsYMJzATRZYBPn3JTO6st1CgtdOX6KTxHNMcUhJ9rytvm++vf78ut3/ePq1un94W307bHe77c+vu6fH9cv2aW9/fVsF/yFcV/fxzkZd3YuNMbSR2shtjG1MbcxtlDaWNtY2Nl9qvtR8qfmyva7YKPZ39ZHbaH4ihwywdyAPUQqgArRBCQACMCACEiADYC4wF5gLzBXmCnOFucJcYa4wV5grzBXmCrPCrDArzAqzwqzNXIJflR0IwAB/jTgIoADs3Tk4aAMKAAIwIALs3dkvpwwQQAG4uThoAw4AN6uDmaMHzxGQABkggAKoAG3gtbkAAWCOMEeYvUCjp8UrdIECcLNH6EX6AV6lC/jlHnOyFydysBcnFyZtkAPAwkjJgQERkAAZIIACcLPHk7WBBAAB3OyBSQQkgJurgwAKoAK0gTfIAgRws8/UG2SBBMgAM2dPgjfIAhVg5swG3iALEIABEZAAGeBmz6E3yAIVoA28QbInyhske7F5gywQAW72bHiDLCCAAqgAXaB6Ey3g5urAgAhIAF/pgoMACsAXO3LQBt5Wwg4EYEAE+BIqDm72t/C2WqAAKkAbeFstQAA3q0MEmLl4GN5WCwjAzMXf3dtqAW3gbbUAARgQAW6ODhkggAJwc3LQBt5WCxDAr8oOBVABfpXPy/trAQJ4PD5B768FEiADBFAAFWDm6vfL+2sBAjDAzfL+frfCJvn15bDZ+B55smvaXvq8Pmz2L6v7/etud7f6Z717/XjRr+f1/mN8WR/sv6bc7L/baMIf293G6f3ueHUYX0rBNt12ubFoV1A4l9BYknxx/lCkVLqgnF/P4+tjxgxiqccAiv6PWWjts7DlaziLNJbkXLU5sgQ5KnI8U+SxgoWRTLbDR1fIxTHYMaHHoDyMYaKww1RsCjsnhaGijhW2pzdDORWUcvE0So8h2647jIEm9zQy4XZEjnmQy7lBe13FUEeGSWEmYhgSRb3iftp2gkTYuj1OxMShft76UCgfJ5Ho4hi0TyKrhqtqKgQoJNBYQWXSoyqoKtKSuiOfdzlN6pIK9bXKTglDhc6SiSC0ni41crlBU19pKA8VPFkvmRMczHl4T5lnKx4fl+1M4zDipDBqd2Tbtk7C4HPHvDK0VwaHsWO2aqbcF83jTU3hysLQcWGU2T2J1O9JiiMFT6KQnHsusqaroiApiMLW8ZEiTla9lPtmXMZ1EWfbOQn3VU9P7+n5Xhpn9Zn7DcnxxBAvj4J7ZSU+afY/ophUJ3HFPkSRaBzHxBFL7PtQDXUch/xdBwmlnlOhEoe9Fic1qlmRET2t0T8c00jicQ2UROOuT7PdWY6HvjS8M1ND6kk9W71+M8z29xCx9KSQyngeEwdHzIMzXxUF177+VRnXaJkdG0Nfya1MxvOQT8iF3JwLuTkXcnsucrg9FzPHZbmYGm7OhQVf+zyErur2i3OR/67jwnzmm/M53ZO0zyNO1vGsn7Anzeqz9E+qKYxPsbODRqw4JrDdkqvOKon6KTafHEF/U0i89awis905KLrdkjneEyXPPifK8ZNm5SsdfSqmq2NHubXCp/m8qC5mx3nOWDCEZfx5tUyK0x5wIBX2ZCMOPjRPDZVxCrbHHXqVofR51HLFB3d7RNXP8jGMP/FOz1rST7AqJNed104dcVzf5RN2xFJuX8HLzfU9NYxX8C/26/pxezh77PjuqsN2/W23ab/+eN0/nvz35d9n/AePLZ8PT4+b76+HjZuOzy7tx0O1b5Wr8pe7lX1/+2Bn8DvhYr/51+8P1QpGA31591j+Aw=="},{"name":"sync_state","hash":"5670089859456161743","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"return_type":null,"error_types":{"361444214588792908":{"error_kind":"string","string":"attempt to multiply with overflow"},"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"1064022259863234536":{"error_kind":"fmtstring","length":101,"item_types":[{"kind":"integer","sign":"unsigned","width":32}]},"1998584279744703196":{"error_kind":"string","string":"attempt to subtract with overflow"},"5421095327929394772":{"error_kind":"string","string":"attempt to bit-shift with overflow"},"5449178635769758673":{"error_kind":"fmtstring","length":61,"item_types":[{"kind":"field"},{"kind":"field"}]},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"9791669845391776238":{"error_kind":"string","string":"0 has a square root; you cannot claim it is not square"},"9885968605480832328":{"error_kind":"string","string":"Attempted to read past the length of a CapsuleArray"},"10791800398362570014":{"error_kind":"string","string":"extend_from_bounded_vec out of bounds"},"10835969307644359280":{"error_kind":"fmtstring","length":40,"item_types":[]},"11021520179822076911":{"error_kind":"string","string":"Attempted to delete past the length of a CapsuleArray"},"12820178569648940736":{"error_kind":"fmtstring","length":48,"item_types":[{"kind":"field"},{"kind":"field"}]},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"},"17110599087403377004":{"error_kind":"fmtstring","length":98,"item_types":[]},"17655676068928457687":{"error_kind":"string","string":"Reader did not read all data"}}},"bytecode":"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","debug_symbols":"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"}],"outputs":{"structs":{"functions":[{"kind":"struct","path":"MarkedPublicUnconstrained::offchain_receive_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"MarkedPublicUnconstrained::offchain_receive_parameters","fields":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]},{"kind":"struct","path":"MarkedPublicUnconstrained::sync_state_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"MarkedPublicUnconstrained::sync_state_parameters","fields":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}]},"globals":{}},"file_map":{"6":{"source":"use crate::{cmp::Eq, convert::From, runtime::is_unconstrained, static_assert};\n\n/// A `BoundedVec` is a growable storage similar to a built-in vector except that it\n/// is bounded with a maximum possible length. `BoundedVec` is also not\n/// subject to the same restrictions vectors are (notably, nested vectors are disallowed).\n///\n/// Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by\n/// pushing an additional element is also more efficient - the length only needs to be increased\n/// by one.\n///\n/// For these reasons `BoundedVec` should generally be preferred over vectors when there\n/// is a reasonable maximum bound that can be placed on the vector.\n///\n/// Example:\n///\n/// ```noir\n/// let mut vector: BoundedVec = BoundedVec::new();\n/// for i in 0..5 {\n/// vector.push(i);\n/// }\n/// assert(vector.len() == 5);\n/// assert(vector.max_len() == 10);\n/// ```\npub struct BoundedVec {\n storage: [T; MaxLen],\n len: u32,\n}\n\nimpl BoundedVec {\n /// Creates a new, empty vector of length zero.\n ///\n /// Since this container is backed by an array internally, it still needs an initial value\n /// to give each element. To resolve this, each element is zeroed internally. This value\n /// is guaranteed to be inaccessible unless `get_unchecked` is used.\n ///\n /// Example:\n ///\n /// ```noir\n /// let empty_vector: BoundedVec = BoundedVec::new();\n /// assert(empty_vector.len() == 0);\n /// ```\n ///\n /// Note that whenever calling `new` the maximum length of the vector should always be specified\n /// via a type signature:\n ///\n /// ```noir\n /// fn good() -> BoundedVec {\n /// // Ok! MaxLen is specified with a type annotation\n /// let v1: BoundedVec = BoundedVec::new();\n /// let v2 = BoundedVec::new();\n ///\n /// // Ok! MaxLen is known from the type of `good`'s return value\n /// v2\n /// }\n ///\n /// fn bad() {\n /// // Error: Type annotation needed\n /// // The compiler can't infer `MaxLen` from the following code:\n /// let mut v3 = BoundedVec::new();\n /// v3.push(5);\n /// }\n /// ```\n ///\n /// This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions\n /// but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a\n /// constraint failure at runtime when the vec is pushed to.\n pub fn new() -> Self {\n let zeroed = crate::mem::zeroed();\n BoundedVec { storage: [zeroed; MaxLen], len: 0 }\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this\n /// will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// let last = v.get(v.len() - 1);\n /// assert(first != last);\n /// }\n /// ```\n pub fn get(&self, index: u32) -> T {\n assert(index < self.len, \"Attempted to read past end of BoundedVec\");\n self.get_unchecked(index)\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero, without\n /// performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element,\n /// it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn sum_of_first_three(v: BoundedVec) -> u32 {\n /// // Always ensure the length is larger than the largest\n /// // index passed to get_unchecked\n /// assert(v.len() > 2);\n /// let first = v.get_unchecked(0);\n /// let second = v.get_unchecked(1);\n /// let third = v.get_unchecked(2);\n /// first + second + third\n /// }\n /// ```\n pub fn get_unchecked(&self, index: u32) -> T {\n self.storage[index]\n }\n\n /// Writes an element to the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// assert(first != 42);\n /// v.set(0, 42);\n /// let new_first = v.get(0);\n /// assert(new_first == 42);\n /// }\n /// ```\n pub fn set(&mut self, index: u32, value: T) {\n assert(index < self.len, \"Attempted to write past end of BoundedVec\");\n self.set_unchecked(index, value)\n }\n\n /// Writes an element to the vector at the given index, starting from zero, without performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element, it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn set_unchecked_example() {\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([1, 2]);\n ///\n /// // Here we're safely writing within the valid range of `vec`\n /// // `vec` now has the value [42, 2]\n /// vec.set_unchecked(0, 42);\n ///\n /// // We can then safely read this value back out of `vec`.\n /// // Notice that we use the checked version of `get` which would prevent reading unsafe values.\n /// assert_eq(vec.get(0), 42);\n ///\n /// // We've now written past the end of `vec`.\n /// // As this index is still within the maximum potential length of `v`,\n /// // it won't cause a constraint failure.\n /// vec.set_unchecked(2, 42);\n /// println(vec);\n ///\n /// // This will write past the end of the maximum potential length of `vec`,\n /// // it will then trigger a constraint failure.\n /// vec.set_unchecked(5, 42);\n /// println(vec);\n /// }\n /// ```\n pub fn set_unchecked(&mut self, index: u32, value: T) {\n self.storage[index] = value;\n }\n\n /// Pushes an element to the end of the vector. This increases the length\n /// of the vector by one.\n ///\n /// Panics if the new length of the vector will be greater than the max length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// v.push(1);\n /// v.push(2);\n ///\n /// // Panics with failed assertion \"push out of bounds\"\n /// v.push(3);\n /// ```\n pub fn push(&mut self, elem: T) {\n assert(self.len < MaxLen, \"push out of bounds\");\n\n self.storage[self.len] = elem;\n self.len += 1;\n }\n\n /// Returns the current length of this vector\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// assert(v.len() == 0);\n ///\n /// v.push(100);\n /// assert(v.len() == 1);\n ///\n /// v.push(200);\n /// v.push(300);\n /// v.push(400);\n /// assert(v.len() == 4);\n ///\n /// let _ = v.pop();\n /// let _ = v.pop();\n /// assert(v.len() == 2);\n /// ```\n pub fn len(&self) -> u32 {\n self.len\n }\n\n /// Returns the maximum length of this vector. This is always\n /// equal to the `MaxLen` parameter this vector was initialized with.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.max_len() == 5);\n /// v.push(10);\n /// assert(v.max_len() == 5);\n /// ```\n pub fn max_len(_self: &BoundedVec) -> u32 {\n MaxLen\n }\n\n /// Returns the internal array within this vector.\n ///\n /// Since arrays in Noir are immutable, mutating the returned storage array will not mutate\n /// the storage held internally by this vector.\n ///\n /// Note that uninitialized elements may be zeroed out!\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.storage() == [0, 0, 0, 0, 0]);\n ///\n /// v.push(57);\n /// assert(v.storage() == [57, 0, 0, 0, 0]);\n /// ```\n pub fn storage(self) -> [T; MaxLen] {\n self.storage\n }\n\n /// Pushes each element from the given array to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([2, 4]);\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_array(&mut self, array: [T; Len]) {\n let new_len = self.len + array.len();\n assert(new_len <= MaxLen, \"extend_from_array out of bounds\");\n for i in 0..array.len() {\n self.storage[self.len + i] = array[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the given vector to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_vector([2, 4].as_vector());\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_vector(&mut self, vector: [T]) {\n let new_len = self.len + vector.len();\n assert(new_len <= MaxLen, \"extend_from_vector out of bounds\");\n for i in 0..vector.len() {\n self.storage[self.len + i] = vector[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the other vector to this vector. The length of\n /// the other vector is left unchanged.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// ```noir\n /// let mut v1: BoundedVec = BoundedVec::new();\n /// let mut v2: BoundedVec = BoundedVec::new();\n ///\n /// v2.extend_from_array([1, 2, 3]);\n /// v1.extend_from_bounded_vec(v2);\n ///\n /// assert(v1.storage() == [1, 2, 3, 0, 0]);\n /// assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]);\n /// ```\n pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) {\n let append_len = vec.len();\n let new_len = self.len + append_len;\n assert(new_len <= MaxLen, \"extend_from_bounded_vec out of bounds\");\n\n if is_unconstrained() {\n for i in 0..append_len {\n self.storage[self.len + i] = vec.get_unchecked(i);\n }\n } else {\n // The source vector can be longer than the destination, or vice versa;\n // regardless we will only ever be able to read or write whichever is\n // the shorter max length of the two. We asserted that the actual content fits,\n // but the capacity of the source vector could be higher.\n let max = crate::cmp::min(Len, MaxLen);\n\n // Save the last item in case we have to do a fixup on an already full array.\n let last = if MaxLen > 0 {\n self.storage[MaxLen - 1]\n } else {\n crate::mem::zeroed()\n };\n\n for src in 0..max {\n // Since we are iterating to the static capacity of the arrays,\n // the destination could be out of bounds. If that's the case,\n // overwrite the last item, which we'll fixup in the end.\n // NB using cmp::min resulted in more opcodes here.\n let mut dst = self.len + src;\n if dst >= MaxLen { dst = MaxLen - 1; };\n // Assigning the source or zeroed to avoid having to merge arrays in SSA.\n self.storage[dst] = if src < append_len {\n vec.get_unchecked(src)\n } else {\n last\n }\n }\n\n // Fixup the last item if we have to.\n if MaxLen > 0 {\n self.storage[MaxLen - 1] = if (self.len + append_len == MaxLen) & (append_len > 0) {\n vec.get_unchecked(append_len - 1)\n } else {\n last\n }\n }\n }\n self.len = new_len;\n }\n\n /// Creates a new vector, populating it with values derived from an array input.\n /// The maximum length of the vector is determined based on the type signature.\n ///\n /// Example:\n ///\n /// ```noir\n /// let bounded_vec: BoundedVec = BoundedVec::from_array([1, 2, 3])\n /// ```\n pub fn from_array(array: [T; Len]) -> Self {\n static_assert(Len <= MaxLen, \"from array out of bounds\");\n let mut vec: BoundedVec = BoundedVec::new();\n vec.extend_from_array(array);\n vec\n }\n\n /// Pops the element at the end of the vector. This will decrease the length\n /// of the vector by one.\n ///\n /// Panics if the vector is empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.push(1);\n /// v.push(2);\n ///\n /// let two = v.pop();\n /// let one = v.pop();\n ///\n /// assert(two == 2);\n /// assert(one == 1);\n ///\n /// // error: cannot pop from an empty vector\n /// let _ = v.pop();\n /// ```\n pub fn pop(&mut self) -> T {\n assert(self.len > 0, \"cannot pop from an empty vector\");\n self.len -= 1;\n\n let elem = self.storage[self.len];\n self.storage[self.len] = crate::mem::zeroed();\n elem\n }\n\n /// Returns true if the given predicate returns true for any element\n /// in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.extend_from_array([2, 4, 6]);\n ///\n /// let all_even = !v.any(|elem: u32| elem % 2 != 0);\n /// assert(all_even);\n /// ```\n pub fn any(self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n if is_unconstrained() {\n for i in 0..self.len {\n ret |= predicate(self.storage[i]);\n }\n } else {\n let mut exceeded_len = false;\n for i in 0..MaxLen {\n exceeded_len |= i == self.len;\n if !exceeded_len {\n ret |= predicate(self.storage[i]);\n }\n }\n }\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.map(|value| value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element\n /// in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.mapi(|i, value| i + value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(i, self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Calls a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_each(|value| result.push(value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Calls a closure on each element in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_eachi(|i, value| result.push(i + value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(i, self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function will zero out any elements at or past index `len` of `array`.\n /// This incurs an extra runtime cost of O(MaxLen). If you are sure your array is\n /// zeroed after that index, you can use [`from_parts_unchecked`][Self::from_parts_unchecked] to remove the extra loop.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n /// ```\n pub fn from_parts(mut array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n let zeroed = crate::mem::zeroed();\n\n if is_unconstrained() {\n for i in len..MaxLen {\n array[i] = zeroed;\n }\n } else {\n for i in 0..MaxLen {\n if i >= len {\n array[i] = zeroed;\n }\n }\n }\n\n BoundedVec { storage: array, len }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function is unsafe because it expects all elements past the `len` index\n /// of `array` to be zeroed, but does not check for this internally. Use `from_parts`\n /// for a safe version of this function which does zero out any indices past the\n /// given length. Invalidating this assumption can notably cause `BoundedVec::eq`\n /// to give incorrect results since it will check even elements past `len`.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n ///\n /// // invalid use!\n /// let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n /// let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n ///\n /// // both vecs have length 3 so we'd expect them to be equal, but this\n /// // fails because elements past the length are still checked in eq\n /// assert_eq(vec1, vec2); // fails\n /// ```\n pub fn from_parts_unchecked(array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n BoundedVec { storage: array, len }\n }\n}\n\nimpl Eq for BoundedVec\nwhere\n T: Eq,\n{\n fn eq(self, other: BoundedVec) -> bool {\n // TODO: https://github.com/noir-lang/noir/issues/4837\n //\n // We make the assumption that the user has used the proper interface for working with `BoundedVec`s\n // rather than directly manipulating the internal fields as this can result in an inconsistent internal state.\n if self.len == other.len {\n self.storage == other.storage\n } else {\n false\n }\n }\n}\n\nimpl From<[T; Len]> for BoundedVec {\n fn from(array: [T; Len]) -> BoundedVec {\n BoundedVec::from_array(array)\n }\n}\n\nmod bounded_vec_tests {\n\n mod get {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_elements_past_end_of_vec() {\n let vec: BoundedVec = BoundedVec::new();\n\n let _ = vec.get(0);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_beyond_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let _ = vec.get(3);\n }\n\n #[test]\n fn get_works_within_bounds() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(2), 3);\n assert_eq(vec.get(4), 5);\n }\n\n #[test]\n fn get_unchecked_works() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(0), 1);\n assert_eq(vec.get_unchecked(2), 3);\n }\n\n #[test]\n fn get_unchecked_works_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(4), 0);\n }\n }\n\n mod set {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn set_updates_values_properly() {\n let mut vec = BoundedVec::from_array([0, 0, 0, 0, 0]);\n\n vec.set(0, 42);\n assert_eq(vec.storage, [42, 0, 0, 0, 0]);\n\n vec.set(1, 43);\n assert_eq(vec.storage, [42, 43, 0, 0, 0]);\n\n vec.set(2, 44);\n assert_eq(vec.storage, [42, 43, 44, 0, 0]);\n\n vec.set(1, 10);\n assert_eq(vec.storage, [42, 10, 44, 0, 0]);\n\n vec.set(0, 0);\n assert_eq(vec.storage, [0, 10, 44, 0, 0]);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_writing_elements_past_end_of_vec() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.set(0, 42);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_setting_beyond_length() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.set(3, 4);\n }\n\n #[test]\n fn set_unchecked_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(0, 10);\n assert_eq(vec.get(0), 10);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn set_unchecked_operations_past_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(3, 40);\n assert_eq(vec.get(3), 40);\n }\n\n #[test]\n fn set_preserves_other_elements() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n vec.set(2, 30);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 30);\n assert_eq(vec.get(3), 4);\n assert_eq(vec.get(4), 5);\n }\n }\n\n mod any {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn returns_false_if_predicate_not_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, false, false]);\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn returns_true_if_predicate_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, true, true]);\n let result = vec.any(|value| value);\n\n assert(result);\n }\n\n #[test]\n fn returns_false_on_empty_boundedvec() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn any_with_complex_predicates() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n assert(vec.any(|x| x > 3));\n assert(!vec.any(|x| x > 10));\n assert(vec.any(|x| x % 2 == 0)); // has a even number\n assert(vec.any(|x| x == 3)); // has a specific value\n }\n\n #[test]\n fn any_with_partial_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n assert(vec.any(|x| x == 1));\n assert(vec.any(|x| x == 2));\n assert(!vec.any(|x| x == 3));\n }\n }\n\n mod map {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-map-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| value * 2);\n // docs:end:bounded-vec-map-example\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.map(|value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn map_with_conditional_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.map(|x| if x % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([1, 4, 3, 8]);\n assert_eq(result, expected);\n }\n\n #[test]\n fn map_preserves_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|x| x * 2);\n\n assert_eq(result.len(), vec.len());\n assert_eq(result.max_len(), vec.max_len());\n }\n\n #[test]\n fn map_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.map(|x| x * 2);\n assert_eq(result, vec);\n assert_eq(result.len(), 0);\n assert_eq(result.max_len(), 5);\n }\n }\n\n mod mapi {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-mapi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| i + value * 2);\n // docs:end:bounded-vec-mapi-example\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.mapi(|_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn mapi_with_index_branching_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.mapi(|i, x| if i % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([2, 2, 6, 4]);\n assert_eq(result, expected);\n }\n }\n\n mod for_each {\n use crate::collections::bounded_vec::BoundedVec;\n\n // map in terms of for_each\n fn for_each_map(\n input: BoundedVec,\n f: fn[Env](T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_each(|x| output_ref.push(f(x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-each-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_each(|value| { *acc_ref += value; });\n // docs:end:bounded-vec-for-each-example\n assert_eq(acc, 6);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| value * 2);\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_each_map(vec, |value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_each_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_each(|_| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_each_with_side_effects() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let mut seen = BoundedVec::::new();\n let seen_ref = &mut seen;\n vec.for_each(|x| seen_ref.push(x));\n assert_eq(seen, vec);\n }\n }\n\n mod for_eachi {\n use crate::collections::bounded_vec::BoundedVec;\n\n // mapi in terms of for_eachi\n fn for_eachi_mapi(\n input: BoundedVec,\n f: fn[Env](u32, T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_eachi(|i, x| output_ref.push(f(i, x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-eachi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_eachi(|i, value| { *acc_ref += i * value; });\n // docs:end:bounded-vec-for-eachi-example\n\n // 0 * 1 + 1 * 2 + 2 * 3\n assert_eq(acc, 8);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| i + value * 2);\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_eachi_mapi(vec, |_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_eachi_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_eachi(|_, _| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_eachi_with_index_tracking() {\n let vec: BoundedVec = BoundedVec::from_array([10, 20, 30]);\n let mut indices = BoundedVec::::new();\n let indices_ref = &mut indices;\n vec.for_eachi(|i, _| indices_ref.push(i));\n\n let expected = BoundedVec::from_array([0, 1, 2]);\n assert_eq(indices, expected);\n }\n\n }\n\n mod from_array {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty() {\n let empty_array: [Field; 0] = [];\n let bounded_vec = BoundedVec::from_array([]);\n\n assert_eq(bounded_vec.max_len(), 0);\n assert_eq(bounded_vec.len(), 0);\n assert_eq(bounded_vec.storage(), empty_array);\n }\n\n #[test]\n fn equal_len() {\n let array = [1, 2, 3];\n let bounded_vec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 3);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.storage(), array);\n }\n\n #[test]\n fn max_len_greater_then_array_len() {\n let array = [1, 2, 3];\n let bounded_vec: BoundedVec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n assert_eq(bounded_vec.get(2), 3);\n }\n\n #[test(should_fail_with = \"from array out of bounds\")]\n fn max_len_lower_then_array_len() {\n let _: BoundedVec = BoundedVec::from_array([0; 3]);\n }\n\n #[test]\n fn from_array_preserves_order() {\n let array = [5, 3, 1, 4, 2];\n let vec: BoundedVec = BoundedVec::from_array(array);\n for i in 0..array.len() {\n assert_eq(vec.get(i), array[i]);\n }\n }\n\n #[test]\n fn from_array_with_different_types() {\n let bool_array = [true, false, true];\n let bool_vec: BoundedVec = BoundedVec::from_array(bool_array);\n assert_eq(bool_vec.len(), 3);\n assert_eq(bool_vec.get(0), true);\n assert_eq(bool_vec.get(1), false);\n }\n }\n\n mod trait_from {\n use crate::collections::bounded_vec::BoundedVec;\n use crate::convert::From;\n\n #[test]\n fn simple() {\n let array = [1, 2];\n let bounded_vec: BoundedVec = BoundedVec::from(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 2);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n }\n }\n\n mod trait_eq {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty_equality() {\n let bounded_vec1: BoundedVec = BoundedVec::new();\n let bounded_vec2: BoundedVec = BoundedVec::new();\n\n assert_eq(bounded_vec1, bounded_vec2);\n }\n\n #[test]\n fn inequality() {\n let mut bounded_vec1: BoundedVec = BoundedVec::new();\n let mut bounded_vec2: BoundedVec = BoundedVec::new();\n bounded_vec1.push(1);\n bounded_vec2.push(2);\n\n assert(bounded_vec1 != bounded_vec2);\n }\n }\n\n mod from_parts {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn from_parts() {\n // docs:start:from-parts\n let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // Any elements past the given length are zeroed out, so these\n // two BoundedVecs will be completely equal\n let vec1: BoundedVec = BoundedVec::from_parts([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts([1, 2, 3, 2], 3);\n assert_eq(vec1, vec2);\n // docs:end:from-parts\n }\n\n #[test]\n fn from_parts_unchecked() {\n // docs:start:from-parts-unchecked\n let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // invalid use!\n let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n\n // both vecs have length 3 so we'd expect them to be equal, but this\n // fails because elements past the length are still checked in eq\n assert(vec1 != vec2);\n // docs:end:from-parts-unchecked\n }\n }\n\n mod push_pop {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn push_and_pop_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n assert_eq(vec.len(), 0);\n\n vec.push(1);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 1);\n\n vec.push(2);\n assert_eq(vec.len(), 2);\n assert_eq(vec.get(1), 2);\n\n let popped = vec.pop();\n assert_eq(popped, 2);\n assert_eq(vec.len(), 1);\n\n let popped2 = vec.pop();\n assert_eq(popped2, 1);\n assert_eq(vec.len(), 0);\n }\n\n #[test(should_fail_with = \"push out of bounds\")]\n fn push_to_full_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n vec.push(3); // should panic\n }\n\n #[test(should_fail_with = \"cannot pop from an empty vector\")]\n fn pop_from_empty_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n let _ = vec.pop(); // should panic\n }\n\n #[test]\n fn push_pop_cycle() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // push to full\n vec.push(1);\n vec.push(2);\n vec.push(3);\n assert_eq(vec.len(), 3);\n\n // pop all\n assert_eq(vec.pop(), 3);\n assert_eq(vec.pop(), 2);\n assert_eq(vec.pop(), 1);\n assert_eq(vec.len(), 0);\n\n // push again\n vec.push(4);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 4);\n }\n }\n\n mod extend {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn extend_from_array() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3]);\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3].as_vector());\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec() {\n // The source deliberately has a higher capacity,\n // to make sure we are not trying to assign out-of-bounds.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_limit() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_full_and_empty() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_zero_len() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_last_zeroed() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get_unchecked(3), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_empty_self() {\n // self.len == 0 with Len > MaxLen: the loop doesn't reach\n // the last storage slot, so the fixup must write it.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_equal_capacity() {\n // Len == MaxLen, fills to capacity.\n let mut vec1: BoundedVec = BoundedVec::new();\n vec1.push(1);\n let vec2: BoundedVec = BoundedVec::from_array([2, 3, 4]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 4);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n assert_eq(vec1.get(3), 4);\n }\n\n #[test(should_fail_with = \"extend_from_array out of bounds\")]\n fn extend_array_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3, 4]); // should panic\n }\n\n #[test(should_fail_with = \"extend_from_vector out of bounds\")]\n fn extend_vector_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3, 4].as_vector()); // S]should panic\n }\n\n #[test(should_fail_with = \"extend_from_bounded_vec out of bounds\")]\n fn extend_bounded_vec_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n let other: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n vec.extend_from_bounded_vec(other); // should panic\n }\n\n #[test]\n fn extend_with_empty_collections() {\n let mut vec: BoundedVec = BoundedVec::new();\n let original_len = vec.len();\n\n vec.extend_from_array([]);\n assert_eq(vec.len(), original_len);\n\n vec.extend_from_vector([].as_vector());\n assert_eq(vec.len(), original_len);\n\n let empty: BoundedVec = BoundedVec::new();\n vec.extend_from_bounded_vec(empty);\n assert_eq(vec.len(), original_len);\n }\n }\n\n mod storage {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn storage_consistency() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // test initial storage state\n assert_eq(vec.storage(), [0, 0, 0, 0, 0]);\n\n vec.push(1);\n vec.push(2);\n\n // test storage after modifications\n assert_eq(vec.storage(), [1, 2, 0, 0, 0]);\n\n // storage doesn't change length\n assert_eq(vec.len(), 2);\n assert_eq(vec.max_len(), 5);\n }\n\n #[test]\n fn storage_after_pop() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n let _ = vec.pop();\n // after pop, the last element should be zeroed\n assert_eq(vec.storage(), [1, 2, 0]);\n assert_eq(vec.len(), 2);\n }\n\n #[test]\n fn vector_immutable() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let storage = vec.storage();\n\n assert_eq(storage, [1, 2, 3]);\n\n // Verify that the original vector is unchanged\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n }\n}\n","path":"std/collections/bounded_vec.nr","function_locations":[{"start":2599,"name":"BoundedVec::new"},{"start":3202,"name":"BoundedVec::get"},{"start":4110,"name":"BoundedVec::get_unchecked"},{"start":4693,"name":"BoundedVec::set"},{"start":6221,"name":"BoundedVec::set_unchecked"},{"start":6759,"name":"BoundedVec::push"},{"start":7367,"name":"BoundedVec::len"},{"start":7808,"name":"BoundedVec::max_len"},{"start":8406,"name":"BoundedVec::storage"},{"start":8962,"name":"BoundedVec::extend_from_array"},{"start":9733,"name":"BoundedVec::extend_from_vector"},{"start":10678,"name":"BoundedVec::extend_from_bounded_vec"},{"start":13073,"name":"BoundedVec::from_array"},{"start":13816,"name":"BoundedVec::pop"},{"start":14439,"name":"BoundedVec::any"},{"start":15355,"name":"BoundedVec::map"},{"start":16355,"name":"BoundedVec::mapi"},{"start":17313,"name":"BoundedVec::for_each"},{"start":18118,"name":"BoundedVec::for_eachi"},{"start":19117,"name":"BoundedVec::from_parts"},{"start":20766,"name":"BoundedVec::from_parts_unchecked"},{"start":20978,"name":">::eq"},{"start":21549,"name":" for BoundedVec>::from"},{"start":21832,"name":"bounded_vec_tests::get::panics_when_reading_elements_past_end_of_vec"},{"start":22067,"name":"bounded_vec_tests::get::panics_when_reading_beyond_length"},{"start":22242,"name":"bounded_vec_tests::get::get_works_within_bounds"},{"start":22501,"name":"bounded_vec_tests::get::get_unchecked_works"},{"start":22745,"name":"bounded_vec_tests::get::get_unchecked_works_past_len"},{"start":23018,"name":"bounded_vec_tests::set::set_updates_values_properly"},{"start":23656,"name":"bounded_vec_tests::set::panics_when_writing_elements_past_end_of_vec"},{"start":23891,"name":"bounded_vec_tests::set::panics_when_setting_beyond_length"},{"start":24066,"name":"bounded_vec_tests::set::set_unchecked_operations"},{"start":24398,"name":"bounded_vec_tests::set::set_unchecked_operations_past_len"},{"start":24662,"name":"bounded_vec_tests::set::set_preserves_other_elements"},{"start":25130,"name":"bounded_vec_tests::any::returns_false_if_predicate_not_satisfied"},{"start":25384,"name":"bounded_vec_tests::any::returns_true_if_predicate_satisfied"},{"start":25633,"name":"bounded_vec_tests::any::returns_false_on_empty_boundedvec"},{"start":25844,"name":"bounded_vec_tests::any::any_with_complex_predicates"},{"start":26207,"name":"bounded_vec_tests::any::any_with_partial_vector"},{"start":26594,"name":"bounded_vec_tests::map::applies_function_correctly"},{"start":27016,"name":"bounded_vec_tests::map::applies_function_that_changes_return_type"},{"start":27364,"name":"bounded_vec_tests::map::does_not_apply_function_past_len"},{"start":27737,"name":"bounded_vec_tests::map::map_with_conditional_logic"},{"start":28061,"name":"bounded_vec_tests::map::map_preserves_length"},{"start":28353,"name":"bounded_vec_tests::map::map_on_empty_vector"},{"start":28727,"name":"bounded_vec_tests::mapi::applies_function_correctly"},{"start":29160,"name":"bounded_vec_tests::mapi::applies_function_that_changes_return_type"},{"start":29517,"name":"bounded_vec_tests::mapi::does_not_apply_function_past_len"},{"start":29899,"name":"bounded_vec_tests::mapi::mapi_with_index_branching_logic"},{"start":30458,"name":"bounded_vec_tests::for_each::for_each_map"},{"start":30688,"name":"bounded_vec_tests::for_each::smoke_test"},{"start":31096,"name":"bounded_vec_tests::for_each::applies_function_correctly"},{"start":31430,"name":"bounded_vec_tests::for_each::applies_function_that_changes_return_type"},{"start":31788,"name":"bounded_vec_tests::for_each::does_not_apply_function_past_len"},{"start":32169,"name":"bounded_vec_tests::for_each::for_each_on_empty_vector"},{"start":32455,"name":"bounded_vec_tests::for_each::for_each_with_side_effects"},{"start":33012,"name":"bounded_vec_tests::for_eachi::for_eachi_mapi"},{"start":33249,"name":"bounded_vec_tests::for_eachi::smoke_test"},{"start":33705,"name":"bounded_vec_tests::for_eachi::applies_function_correctly"},{"start":34049,"name":"bounded_vec_tests::for_eachi::applies_function_that_changes_return_type"},{"start":34417,"name":"bounded_vec_tests::for_eachi::does_not_apply_function_past_len"},{"start":34804,"name":"bounded_vec_tests::for_eachi::for_eachi_on_empty_vector"},{"start":35097,"name":"bounded_vec_tests::for_eachi::for_eachi_with_index_tracking"},{"start":35574,"name":"bounded_vec_tests::from_array::empty"},{"start":35884,"name":"bounded_vec_tests::from_array::equal_len"},{"start":36201,"name":"bounded_vec_tests::from_array::max_len_greater_then_array_len"},{"start":36672,"name":"bounded_vec_tests::from_array::max_len_lower_then_array_len"},{"start":36815,"name":"bounded_vec_tests::from_array::from_array_preserves_order"},{"start":37104,"name":"bounded_vec_tests::from_array::from_array_with_different_types"},{"start":37541,"name":"bounded_vec_tests::trait_from::simple"},{"start":37979,"name":"bounded_vec_tests::trait_eq::empty_equality"},{"start":38228,"name":"bounded_vec_tests::trait_eq::inequality"},{"start":38637,"name":"bounded_vec_tests::from_parts::from_parts"},{"start":39227,"name":"bounded_vec_tests::from_parts::from_parts_unchecked"},{"start":40009,"name":"bounded_vec_tests::push_pop::push_and_pop_operations"},{"start":40635,"name":"bounded_vec_tests::push_pop::push_to_full_vector"},{"start":40909,"name":"bounded_vec_tests::push_pop::pop_from_empty_vector"},{"start":41078,"name":"bounded_vec_tests::push_pop::push_pop_cycle"},{"start":41724,"name":"bounded_vec_tests::extend::extend_from_array"},{"start":42070,"name":"bounded_vec_tests::extend::extend_from_vector"},{"start":42434,"name":"bounded_vec_tests::extend::extend_from_bounded_vec"},{"start":43055,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_limit"},{"start":43569,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_full_and_empty"},{"start":44073,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_zero_len"},{"start":44367,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_last_zeroed"},{"start":44792,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_empty_self"},{"start":45359,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_equal_capacity"},{"start":45946,"name":"bounded_vec_tests::extend::extend_array_beyond_max_len"},{"start":46224,"name":"bounded_vec_tests::extend::extend_vector_beyond_max_len"},{"start":46527,"name":"bounded_vec_tests::extend::extend_bounded_vec_beyond_max_len"},{"start":46813,"name":"bounded_vec_tests::extend::extend_with_empty_collections"},{"start":47413,"name":"bounded_vec_tests::storage::storage_consistency"},{"start":47915,"name":"bounded_vec_tests::storage::storage_after_pop"},{"start":48233,"name":"bounded_vec_tests::storage::vector_immutable"}]},"16":{"source":"use crate::field::field_less_than;\nuse crate::runtime::is_unconstrained;\n\n// The low and high decomposition of the field modulus\npub(crate) global PLO: Field = 53438638232309528389504892708671455233;\npub(crate) global PHI: Field = 64323764613183177041862057485226039389;\n\npub(crate) global TWO_POW_128: Field = 0x100000000000000000000000000000000;\n\n// Decomposes a single field into two 16 byte fields.\nfn compute_decomposition(x: Field) -> (Field, Field) {\n // Here's we're taking advantage of truncating 128 bit limbs from the input field\n // and then subtracting them from the input such the field division is equivalent to integer division.\n let low = (x as u128) as Field;\n let high = (x - low) / TWO_POW_128;\n\n (low, high)\n}\n\npub(crate) unconstrained fn decompose_hint(x: Field) -> (Field, Field) {\n compute_decomposition(x)\n}\n\nunconstrained fn lte_hint(x: Field, y: Field) -> bool {\n if x == y {\n true\n } else {\n field_less_than(x, y)\n }\n}\n\n// Assert that (alo > blo && ahi >= bhi) || (alo <= blo && ahi > bhi)\nfn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) {\n let (alo, ahi) = a;\n let (blo, bhi) = b;\n // Safety: borrow is enforced to be boolean due to its type.\n // if borrow is 0, it asserts that (alo > blo && ahi >= bhi)\n // if borrow is 1, it asserts that (alo <= blo && ahi > bhi)\n unsafe {\n let borrow = lte_hint(alo, blo);\n\n let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128;\n let rhi = ahi - bhi - (borrow as Field);\n\n rlo.assert_max_bit_size::<128>();\n rhi.assert_max_bit_size::<128>();\n }\n}\n\n/// Decompose a single field into two 16 byte fields.\npub fn decompose(x: Field) -> (Field, Field) {\n if is_unconstrained() {\n compute_decomposition(x)\n } else {\n // Safety: decomposition is properly checked below\n unsafe {\n // Take hints of the decomposition\n let (xlo, xhi) = decompose_hint(x);\n\n // Range check the limbs\n xlo.assert_max_bit_size::<128>();\n xhi.assert_max_bit_size::<128>();\n\n // Check that the decomposition is correct\n assert_eq(x, xlo + TWO_POW_128 * xhi);\n\n // Assert that the decomposition of P is greater than the decomposition of x\n assert_gt_limbs((PLO, PHI), (xlo, xhi));\n (xlo, xhi)\n }\n }\n}\n\npub fn assert_gt(a: Field, b: Field) {\n if is_unconstrained() {\n assert(\n // Safety: already unconstrained\n unsafe { field_less_than(b, a) },\n );\n } else {\n // Decompose a and b\n let a_limbs = decompose(a);\n let b_limbs = decompose(b);\n\n // Assert that a_limbs is greater than b_limbs\n assert_gt_limbs(a_limbs, b_limbs)\n }\n}\n\npub fn assert_lt(a: Field, b: Field) {\n assert_gt(b, a);\n}\n\npub fn gt(a: Field, b: Field) -> bool {\n if is_unconstrained() {\n // Safety: unsafe in unconstrained\n unsafe {\n field_less_than(b, a)\n }\n } else if a == b {\n false\n } else {\n // Safety: Take a hint of the comparison and verify it\n unsafe {\n if field_less_than(a, b) {\n assert_gt(b, a);\n false\n } else {\n assert_gt(a, b);\n true\n }\n }\n }\n}\n\npub fn lt(a: Field, b: Field) -> bool {\n gt(b, a)\n}\n\nmod tests {\n // TODO: Allow imports from \"super\"\n use crate::field::bn254::{assert_gt, decompose, gt, lt, lte_hint, PHI, PLO, TWO_POW_128};\n\n #[test]\n fn check_decompose() {\n assert_eq(decompose(TWO_POW_128), (0, 1));\n assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1));\n assert_eq(decompose(0x1234567890), (0x1234567890, 0));\n }\n\n #[test]\n unconstrained fn check_lte_hint() {\n assert(lte_hint(0, 1));\n assert(lte_hint(0, 0x100));\n assert(lte_hint(0x100, TWO_POW_128 - 1));\n assert(!lte_hint(0 - 1, 0));\n\n assert(lte_hint(0, 0));\n assert(lte_hint(0x100, 0x100));\n assert(lte_hint(0 - 1, 0 - 1));\n }\n\n #[test]\n fn check_gt() {\n assert(gt(1, 0));\n assert(gt(0x100, 0));\n assert(gt((0 - 1), (0 - 2)));\n assert(gt(TWO_POW_128, 0));\n assert(!gt(0, 0));\n assert(!gt(0, 0x100));\n assert(gt(0 - 1, 0 - 2));\n assert(!gt(0 - 2, 0 - 1));\n assert_gt(0 - 1, 0);\n }\n\n #[test]\n fn check_plo_phi() {\n assert_eq(PLO + PHI * TWO_POW_128, 0);\n let p_bytes = crate::field::modulus_le_bytes();\n let mut p_low: Field = 0;\n let mut p_high: Field = 0;\n\n let mut offset = 1;\n for i in 0..16 {\n p_low += (p_bytes[i] as Field) * offset;\n p_high += (p_bytes[i + 16] as Field) * offset;\n offset *= 256;\n }\n assert_eq(p_low, PLO);\n assert_eq(p_high, PHI);\n }\n\n #[test]\n fn check_decompose_edge_cases() {\n assert_eq(decompose(0), (0, 0));\n assert_eq(decompose(TWO_POW_128 - 1), (TWO_POW_128 - 1, 0));\n assert_eq(decompose(TWO_POW_128 + 1), (1, 1));\n assert_eq(decompose(TWO_POW_128 * 2), (0, 2));\n assert_eq(decompose(TWO_POW_128 * 2 + 0x1234567890), (0x1234567890, 2));\n }\n\n #[test]\n fn check_decompose_large_values() {\n let large_field = 0xffffffffffffffff;\n let (lo, hi) = decompose(large_field);\n assert_eq(large_field, lo + TWO_POW_128 * hi);\n\n let large_value = large_field - TWO_POW_128;\n let (lo2, hi2) = decompose(large_value);\n assert_eq(large_value, lo2 + TWO_POW_128 * hi2);\n }\n\n #[test]\n fn check_lt_comprehensive() {\n assert(lt(0, 1));\n assert(!lt(1, 0));\n assert(!lt(0, 0));\n assert(!lt(42, 42));\n\n assert(lt(TWO_POW_128 - 1, TWO_POW_128));\n assert(!lt(TWO_POW_128, TWO_POW_128 - 1));\n }\n}\n","path":"std/field/bn254.nr","function_locations":[{"start":456,"name":"compute_decomposition"},{"start":818,"name":"decompose_hint"},{"start":906,"name":"lte_hint"},{"start":1116,"name":"assert_gt_limbs"},{"start":1725,"name":"decompose"},{"start":2431,"name":"assert_gt"},{"start":2837,"name":"assert_lt"},{"start":2901,"name":"gt"},{"start":3405,"name":"lt"},{"start":3607,"name":"tests::check_decompose"},{"start":3857,"name":"tests::check_lte_hint"},{"start":4164,"name":"tests::check_gt"},{"start":4494,"name":"tests::check_plo_phi"},{"start":4989,"name":"tests::check_decompose_edge_cases"},{"start":5349,"name":"tests::check_decompose_large_values"},{"start":5710,"name":"tests::check_lt_comprehensive"}]},"17":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [bool; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [bool; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [bool; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = false if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = true.\n pub fn sgn0(self) -> bool {\n (self as u8) % 2 == 1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [bool; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [bool; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [bool] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [bool] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_be_bits();\n assert_eq(bits, [false, false, false, false, false, false, true, false]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_le_bits();\n assert_eq(bits, [false, true, false, false, false, false, false, false]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_field.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_val.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [bool; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [false; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [bool; 8] = 1.to_le_bits();\n let expected: [bool; 8] = [true, false, false, false, false, false, false, false];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [bool; 8] = 4.to_le_bits();\n let expected: [bool; 8] = [false, false, true, false, false, false, false, false];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), false);\n assert_eq(2.sgn0(), false);\n assert_eq(4.sgn0(), false);\n assert_eq(100.sgn0(), false);\n\n assert_eq(1.sgn0(), true);\n assert_eq(3.sgn0(), true);\n assert_eq(5.sgn0(), true);\n assert_eq(101.sgn0(), true);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [bool; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits(bits: [bool; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits(bits: [bool; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1]);\n p_minus_1_bits[254 - 1] = false;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(!p_plus_4_bits[254 - 3]);\n p_plus_4_bits[254 - 3] = true;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_be_bits();\n assert(p_plus_4_converted_bits[254 - 3]);\n p_plus_4_converted_bits[254 - 3] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_be_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0]);\n p_minus_1_bits[0] = false;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(!p_plus_4_bits[2]);\n p_plus_4_bits[2] = true;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_le_bits();\n assert(p_plus_4_converted_bits[2]);\n p_plus_4_converted_bits[2] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_le_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n}\n","path":"std/field/mod.nr","function_locations":[{"start":380,"name":"Field::assert_max_bit_size"},{"start":1196,"name":"Field::to_le_bits"},{"start":2387,"name":"Field::to_be_bits"},{"start":3562,"name":"Field::to_le_bytes"},{"start":5033,"name":"Field::to_be_bytes"},{"start":5904,"name":"Field::to_le_radix"},{"start":6362,"name":"Field::to_be_radix"},{"start":7053,"name":"Field::pow_32"},{"start":7455,"name":"Field::sgn0"},{"start":7538,"name":"Field::lt"},{"start":7918,"name":"Field::from_le_bytes"},{"start":8476,"name":"Field::from_be_bytes"},{"start":8757,"name":"__assert_max_bit_size"},{"start":8885,"name":"__to_le_radix"},{"start":9013,"name":"__to_be_radix"},{"start":9734,"name":"__to_le_bits"},{"start":10452,"name":"__to_be_bits"},{"start":10527,"name":"modulus_num_bits"},{"start":10603,"name":"modulus_be_bits"},{"start":10679,"name":"modulus_le_bits"},{"start":10755,"name":"modulus_be_bytes"},{"start":10831,"name":"modulus_le_bytes"},{"start":10992,"name":"__field_less_than"},{"start":11068,"name":"field_less_than"},{"start":11210,"name":"bytes32_to_field"},{"start":11617,"name":"lt_fallback"},{"start":12579,"name":"tests::test_to_be_bits"},{"start":12852,"name":"tests::test_to_le_bits"},{"start":13127,"name":"tests::test_to_be_bytes"},{"start":13433,"name":"tests::test_to_le_bytes"},{"start":13739,"name":"tests::test_to_be_radix"},{"start":14321,"name":"tests::test_to_le_radix"},{"start":14921,"name":"tests::test_to_le_radix_1"},{"start":15374,"name":"tests::test_to_le_radix_brillig_1"},{"start":15728,"name":"tests::test_to_le_radix_3"},{"start":16039,"name":"tests::test_to_le_radix_brillig_3"},{"start":16467,"name":"tests::test_to_le_radix_512"},{"start":16876,"name":"tests::not_enough_limbs_brillig"},{"start":17072,"name":"tests::not_enough_limbs"},{"start":17214,"name":"tests::test_field_less_than"},{"start":17469,"name":"tests::test_large_field_values_unconstrained"},{"start":17922,"name":"tests::test_large_field_values"},{"start":18369,"name":"tests::test_decomposition_edge_cases"},{"start":18959,"name":"tests::test_pow_32"},{"start":19288,"name":"tests::test_sgn0"},{"start":19710,"name":"tests::test_bit_decomposition_overflow"},{"start":19992,"name":"tests::test_byte_decomposition_overflow"},{"start":20209,"name":"tests::test_to_from_be_bytes_bn254_edge_cases"},{"start":22160,"name":"tests::test_to_from_le_bytes_bn254_edge_cases"},{"start":24245,"name":"tests::from_le_bits"},{"start":24792,"name":"tests::from_be_bits"},{"start":25038,"name":"tests::test_to_from_be_bits_bn254_edge_cases"},{"start":26971,"name":"tests::test_to_from_le_bits_bn254_edge_cases"}]},"18":{"source":"// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\nuse crate::static_assert;\n\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated(\"This function has been moved to std::hash::keccakf1600\")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you're working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n \"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\n }\n let generators = derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n crate::assert_constant(separator);\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators(\"pedersen_hash_length\".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n crate::assert_constant(starting_index);\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\npub fn poseidon2_permutation(input: [Field; N]) -> [Field; N] {\n static_assert(\n N == POSEIDON2_CONFIG_STATE_SIZE,\n f\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\",\n );\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal(input: [Field; N]) -> [Field; N] {}\n\n#[foreign(poseidon2_config_state_size)]\ncomptime fn poseidon2_config_state_size() -> u32 {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n /// Returns the hash value without consuming the hasher.\n /// Override this for more efficient implementations that avoid copying.\n /// TODO: deprecate finish() and replace it\n fn finish_ref(&self) -> Field {\n (*self).finish()\n }\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault;\n\nimpl BuildHasher for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl Default for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for [T]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n },\n );\n}\n","path":"std/hash/mod.nr","function_locations":[{"start":572,"name":"sha256_compression"},{"start":707,"name":"keccakf1600"},{"start":882,"name":"keccak::keccakf1600"},{"start":1044,"name":"blake2s"},{"start":1142,"name":"blake3"},{"start":1629,"name":"__blake3"},{"start":1747,"name":"pedersen_commitment"},{"start":1976,"name":"pedersen_commitment_with_separator"},{"start":2380,"name":"pedersen_hash"},{"start":2537,"name":"pedersen_hash_with_separator"},{"start":3531,"name":"derive_generators"},{"start":3890,"name":"__derive_generators"},{"start":3968,"name":"poseidon2_permutation"},{"start":4324,"name":"poseidon2_permutation_internal"},{"start":4417,"name":"poseidon2_config_state_size"},{"start":4728,"name":"derive_hash"},{"start":5953,"name":">::build_hasher"},{"start":6085,"name":">::default"},{"start":6217,"name":"::hash"},{"start":6347,"name":"::hash"},{"start":6487,"name":"::hash"},{"start":6627,"name":"::hash"},{"start":6767,"name":"::hash"},{"start":6908,"name":"::hash"},{"start":7047,"name":"::hash"},{"start":7193,"name":"::hash"},{"start":7340,"name":"::hash"},{"start":7487,"name":"::hash"},{"start":7635,"name":"::hash"},{"start":7782,"name":"::hash"},{"start":7914,"name":"::hash"},{"start":8103,"name":"::hash"},{"start":8343,"name":"::hash"},{"start":8559,"name":"::hash"},{"start":8822,"name":"::hash"},{"start":9132,"name":"::hash"},{"start":9528,"name":"assert_pedersen"}]},"41":{"source":"use crate::cmp::{Eq, Ord, Ordering};\nuse crate::default::Default;\nuse crate::hash::{Hash, Hasher};\n\n/// Represents a value of type T or its absence.\n/// Use `Option::some(value)` to construct a value or `Option::none()` to record the absence of one.\npub struct Option {\n _is_some: bool,\n _value: T,\n}\n\nimpl Option {\n /// Constructs a None value\n pub fn none() -> Self {\n Self { _is_some: false, _value: crate::mem::zeroed() }\n }\n\n /// Constructs a Some wrapper around the given value\n pub fn some(_value: T) -> Self {\n Self { _is_some: true, _value }\n }\n\n /// True if this Option is None\n pub fn is_none(&self) -> bool {\n !self._is_some\n }\n\n /// True if this Option is Some\n pub fn is_some(&self) -> bool {\n self._is_some\n }\n\n /// Asserts `self.is_some()` and returns the wrapped value.\n pub fn unwrap(self) -> T {\n assert(self._is_some);\n self._value\n }\n\n /// Returns the inner value without asserting `self.is_some()`\n /// Note that if `self` is `None`, there is no guarantee what value will be returned,\n /// only that it will be of type `T`.\n pub fn unwrap_unchecked(self) -> T {\n self._value\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.\n pub fn unwrap_or(self, default: T) -> T {\n if self._is_some {\n self._value\n } else {\n default\n }\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return\n /// a default value.\n pub fn unwrap_or_else(self, default: fn[Env]() -> T) -> T {\n if self._is_some {\n self._value\n } else {\n default()\n }\n }\n\n /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value\n pub fn expect(self, message: fmtstr) -> T {\n assert(self.is_some(), message);\n self._value\n }\n\n /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.\n pub fn map(self, f: fn[Env](T) -> U) -> Option {\n if self._is_some {\n Option::some(f(self._value))\n } else {\n Option::none()\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.\n pub fn map_or(self, default: U, f: fn[Env](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.\n pub fn map_or_else(self, default: fn[Env1]() -> U, f: fn[Env2](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default()\n }\n }\n\n /// Returns None if self is None. Otherwise, this returns `other`.\n pub fn and(self, other: Self) -> Self {\n if self.is_none() {\n Option::none()\n } else {\n other\n }\n }\n\n /// If self is None, this returns None. Otherwise, this calls the given function\n /// with the Some value contained within self, and returns the result of that call.\n ///\n /// In some languages this function is called `flat_map` or `bind`.\n pub fn and_then(self, f: fn[Env](T) -> Option) -> Option {\n if self._is_some {\n f(self._value)\n } else {\n Option::none()\n }\n }\n\n /// If self is Some, return self. Otherwise, return `other`.\n pub fn or(self, other: Self) -> Self {\n if self._is_some {\n self\n } else {\n other\n }\n }\n\n /// If self is Some, return self. Otherwise, return `default()`.\n pub fn or_else(self, default: fn[Env]() -> Self) -> Self {\n if self._is_some {\n self\n } else {\n default()\n }\n }\n\n // If only one of the two Options is Some, return that option.\n // Otherwise, if both options are Some or both are None, None is returned.\n pub fn xor(self, other: Self) -> Self {\n if self._is_some {\n if other._is_some {\n Option::none()\n } else {\n self\n }\n } else if other._is_some {\n other\n } else {\n Option::none()\n }\n }\n\n /// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.\n /// Otherwise, this returns `None`\n pub fn filter(self, predicate: fn[Env](T) -> bool) -> Self {\n if self._is_some {\n if predicate(self._value) {\n self\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n }\n\n /// Flattens an Option> into a Option.\n /// This returns None if the outer Option is None. Otherwise, this returns the inner Option.\n pub fn flatten(option: Option>) -> Option {\n if option._is_some {\n option._value\n } else {\n Option::none()\n }\n }\n}\n\nimpl Default for Option {\n fn default() -> Self {\n Option::none()\n }\n}\n\nimpl Eq for Option\nwhere\n T: Eq,\n{\n fn eq(self, other: Self) -> bool {\n if self._is_some == other._is_some {\n if self._is_some {\n self._value == other._value\n } else {\n true\n }\n } else {\n false\n }\n }\n}\n\nimpl Hash for Option\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self._is_some.hash(state);\n if self._is_some {\n self._value.hash(state);\n }\n }\n}\n\n// For this impl we're declaring Option::none < Option::some\nimpl Ord for Option\nwhere\n T: Ord,\n{\n fn cmp(self, other: Self) -> Ordering {\n if self._is_some {\n if other._is_some {\n self._value.cmp(other._value)\n } else {\n Ordering::greater()\n }\n } else if other._is_some {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n","path":"std/option.nr","function_locations":[{"start":389,"name":"Option::none"},{"start":553,"name":"Option::some"},{"start":672,"name":"Option::is_none"},{"start":774,"name":"Option::is_some"},{"start":898,"name":"Option::unwrap"},{"start":1196,"name":"Option::unwrap_unchecked"},{"start":1368,"name":"Option::unwrap_or"},{"start":1668,"name":"Option::unwrap_or_else"},{"start":1969,"name":"Option::expect"},{"start":2190,"name":"Option::map"},{"start":2490,"name":"Option::map_or"},{"start":2784,"name":"Option::map_or_else"},{"start":3009,"name":"Option::and"},{"start":3446,"name":"Option::and_then"},{"start":3669,"name":"Option::or"},{"start":3902,"name":"Option::or_else"},{"start":4192,"name":"Option::xor"},{"start":4636,"name":"Option::filter"},{"start":5065,"name":"Option::flatten"},{"start":5242,"name":">::default"},{"start":5357,"name":">::eq"},{"start":5706,"name":">::hash"},{"start":5975,"name":">::cmp"}]},"42":{"source":"/// Halt the program at runtime with the given error message.\n///\n/// The provided error message must be either a `str` or a `fmtstr`.\npub fn panic(message: T) -> U\nwhere\n T: StringLike,\n{\n assert(false, message);\n crate::mem::zeroed()\n}\n\ntrait StringLike {}\n\nimpl StringLike for str {}\nimpl StringLike for fmtstr {}\n","path":"std/panic.nr","function_locations":[{"start":196,"name":"panic"}]},"59":{"source":"use crate::oracle::capsules;\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// A dynamically sized array backed by PXE's non-volatile database (called capsules). Values are persisted until\n/// deleted, so they can be e.g. stored during simulation of a transaction and later retrieved during witness\n/// generation. All values are scoped per contract address, so external contracts cannot access them.\npub struct CapsuleArray {\n contract_address: AztecAddress,\n /// The base slot is where the array length is stored in capsules. Array elements are stored in consecutive slots\n /// after the base slot. For example, with base slot 5: the length is at slot 5, the first element (index 0) is at\n /// slot 6, the second element (index 1) is at slot 7, and so on.\n base_slot: Field,\n /// Scope for capsule isolation. Capsule operations are scoped to the given address, allowing multiple independent\n /// namespaces within the same contract.\n scope: AztecAddress,\n}\n\nimpl CapsuleArray {\n /// Returns a CapsuleArray scoped to a specific address.\n ///\n /// Array elements are stored in contiguous slots\n /// following the base slot, so there should be sufficient space between array base slots to accommodate elements.\n /// A reasonable strategy is to make the base slot a hash of a unique value.\n pub unconstrained fn at(contract_address: AztecAddress, base_slot: Field, scope: AztecAddress) -> Self {\n Self { contract_address, base_slot, scope }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n // An uninitialized array defaults to a length of 0.\n capsules::load(self.contract_address, self.base_slot, self.scope).unwrap_or(0) as u32\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let current_length = self.len();\n\n // The slot corresponding to the index `current_length` is the first slot immediately after the end of the\n // array, which is where we want to place the new value.\n capsules::store(\n self.contract_address,\n self.slot_at(current_length),\n value,\n self.scope,\n );\n\n // Then we simply update the length.\n let new_length = current_length + 1;\n capsules::store(\n self.contract_address,\n self.base_slot,\n new_length,\n self.scope,\n );\n }\n\n /// Retrieves the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n assert(index < self.len(), \"Attempted to read past the length of a CapsuleArray\");\n\n capsules::load(self.contract_address, self.slot_at(index), self.scope).unwrap()\n }\n\n /// Deletes the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n let current_length = self.len();\n assert(index < current_length, \"Attempted to delete past the length of a CapsuleArray\");\n\n // In order to be able to remove elements at arbitrary indices, we need to shift the entire contents of the\n // array past the removed element one slot backward so that we don't end up with a gap and preserve the\n // contiguous slots. We can skip this when deleting the last element however.\n if index != current_length - 1 {\n // The source and destination regions overlap, but `copy` supports this.\n capsules::copy(\n self.contract_address,\n self.slot_at(index + 1),\n self.slot_at(index),\n current_length - index - 1,\n self.scope,\n );\n }\n\n // We can now delete the last element (which has either been copied to the slot immediately before it, or was\n // the element we meant to delete in the first place) and update the length.\n capsules::delete(\n self.contract_address,\n self.slot_at(current_length - 1),\n self.scope,\n );\n capsules::store(\n self.contract_address,\n self.base_slot,\n current_length - 1,\n self.scope,\n );\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. The order in which values\n /// are processed is arbitrary.\n ///\n /// ## Array Mutation\n ///\n /// It is safe to delete the current element (and only the current element) from inside the callback via `remove`:\n /// ```noir\n /// array.for_each(|index, value| {\n /// if some_condition(value) {\n /// array.remove(index); // safe only for this index\n /// }\n /// }\n /// ```\n ///\n /// If all elements in the array need to iterated over and then removed, then using `for_each` results in optimal\n /// efficiency.\n ///\n /// It is **not** safe to push new elements into the array from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n // Iterating over all elements is simple, but we want to do it in such a way that a) deleting the current\n // element is safe to do, and b) deleting *all* elements is optimally efficient. This is because CapsuleArrays\n // are typically used to hold pending tasks, so iterating them while clearing completed tasks (sometimes\n // unconditionally, resulting in a full clear) is a very common access pattern.\n //\n // The way we achieve this is by iterating backwards: each element can always be deleted since it won't change\n // any preceding (lower) indices, and if every element is deleted then every element will (in turn) be the last\n // element. This results in an optimal full clear since `remove` will be able to skip the `capsules::copy` call\n // to shift any elements past the deleted one (because there will be none).\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n\n unconstrained fn slot_at(self, index: u32) -> Field {\n // Elements are stored immediately after the base slot, so we add 1 to it to compute the slot for the first\n // element.\n self.base_slot + 1 + index as Field\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::CapsuleArray;\n\n global SLOT: Field = 1230;\n\n #[test]\n unconstrained fn empty_array() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array: CapsuleArray = CapsuleArray::at(contract_address, SLOT, scope);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn empty_array_read() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n let _: Field = array.get(0);\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn read_past_len() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(5);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 8);\n assert_eq(array.get(2), 9);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We store all values that we were called with and check that all (value, index) tuples are present. Note\n // that we do not care about the order in which each tuple was passed to the closure.\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all_no_copy() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We test that the aztec_utl_copyCapsule was never called, which is the expensive operation we want to\n // avoid.\n let mock = std::test::OracleMock::mock(\"aztec_utl_copyCapsule\");\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(mock.times_called(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_scopes_are_isolated() {\n let mut env = TestEnvironment::new();\n let scope_a = env.create_light_account();\n let scope_b = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array_a = CapsuleArray::at(contract_address, SLOT, scope_a);\n let array_b = CapsuleArray::at(contract_address, SLOT, scope_b);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/capsules/mod.nr","function_locations":[{"start":1478,"name":"CapsuleArray::at"},{"start":1641,"name":"CapsuleArray::len"},{"start":1935,"name":"CapsuleArray::push"},{"start":2748,"name":"CapsuleArray::get"},{"start":3083,"name":"CapsuleArray::remove"},{"start":5345,"name":"CapsuleArray::for_each"},{"start":6413,"name":"CapsuleArray::slot_at"},{"start":6789,"name":"test::empty_array"},{"start":7263,"name":"test::empty_array_read"},{"start":7638,"name":"test::array_push"},{"start":8156,"name":"test::read_past_len"},{"start":8559,"name":"test::array_remove_last"},{"start":8997,"name":"test::array_remove_some"},{"start":9729,"name":"test::array_remove_all"},{"start":10296,"name":"test::for_each_called_with_all_elements"},{"start":11389,"name":"test::for_each_remove_some"},{"start":12081,"name":"test::for_each_remove_all"},{"start":12619,"name":"test::for_each_remove_all_no_copy"},{"start":13383,"name":"test::different_scopes_are_isolated"}]},"70":{"source":"use crate::oracle::{execution::get_utility_context, storage::storage_read};\nuse crate::protocol::{abis::block_header::BlockHeader, address::AztecAddress, traits::Packable};\n\n// If you'll modify this struct don't forget to update utility_context.ts as well.\npub struct UtilityContext {\n block_header: BlockHeader,\n contract_address: AztecAddress,\n}\n\nimpl UtilityContext {\n pub unconstrained fn new() -> Self {\n get_utility_context()\n }\n\n pub unconstrained fn at(contract_address: AztecAddress) -> Self {\n // We get a context with default contract address, and then we construct the final context with the provided\n // contract address.\n let default_context = get_utility_context();\n\n Self { block_header: default_context.block_header, contract_address }\n }\n\n pub fn block_header(self) -> BlockHeader {\n self.block_header\n }\n\n pub fn block_number(self) -> u32 {\n self.block_header.block_number()\n }\n\n pub fn timestamp(self) -> u64 {\n self.block_header.timestamp()\n }\n\n pub fn this_address(self) -> AztecAddress {\n self.contract_address\n }\n\n pub fn version(self) -> Field {\n self.block_header.version()\n }\n\n pub fn chain_id(self) -> Field {\n self.block_header.chain_id()\n }\n\n pub unconstrained fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n storage_read(self.block_header, self.this_address(), storage_slot)\n }\n\n pub unconstrained fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/utility_context.nr","function_locations":[{"start":416,"name":"UtilityContext::new"},{"start":523,"name":"UtilityContext::at"},{"start":855,"name":"UtilityContext::block_header"},{"start":927,"name":"UtilityContext::block_number"},{"start":1011,"name":"UtilityContext::timestamp"},{"start":1104,"name":"UtilityContext::this_address"},{"start":1177,"name":"UtilityContext::version"},{"start":1257,"name":"UtilityContext::chain_id"},{"start":1404,"name":"UtilityContext::raw_storage_read"},{"start":1596,"name":"UtilityContext::storage_read"}]},"75":{"source":"use crate::oracle::ephemeral;\nuse crate::protocol::traits::{Deserialize, Serialize};\n\n/// A dynamically sized array that exists only during a single contract call frame.\n///\n/// Ephemeral arrays are backed by in-memory storage on the PXE side rather than a persistent database. Each contract\n/// call frame gets its own isolated slot space of ephemeral arrays. Child simulations cannot see the parent's\n/// ephemeral arrays, and vice versa.\n///\n/// Each logical array operation (push, pop, get, etc.) is a single oracle call, making ephemeral arrays significantly\n/// cheaper than capsule arrays.\n///\n/// ## Use Cases\n///\n/// Ephemeral arrays are designed for passing data between PXE (TypeScript) and contracts (Noir) during simulation,\n/// for example, note validation requests or event validation responses. This data type is appropriate for data that\n/// is not supposed to be persisted.\n///\n/// For data that needs to persist across simulations, contract calls, etc, use\n/// [`CapsuleArray`](crate::capsules::CapsuleArray) instead.\npub struct EphemeralArray {\n pub slot: Field,\n}\n\nimpl EphemeralArray {\n /// Returns a handle to an ephemeral array at the given slot, which may already contain data (e.g. populated\n /// by an oracle).\n pub unconstrained fn at(slot: Field) -> Self {\n Self { slot }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n ephemeral::len_oracle(self.slot)\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n let _ = ephemeral::push_oracle(self.slot, serialized);\n }\n\n /// Removes and returns the last element. Panics if the array is empty.\n pub unconstrained fn pop(self) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::pop_oracle(self.slot);\n Deserialize::deserialize(serialized)\n }\n\n /// Retrieves the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::get_oracle(self.slot, index);\n Deserialize::deserialize(serialized)\n }\n\n /// Overwrites the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn set(self, index: u32, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n ephemeral::set_oracle(self.slot, index, serialized);\n }\n\n /// Removes the element at `index`, shifting subsequent elements backward. Panics if out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n ephemeral::remove_oracle(self.slot, index);\n }\n\n /// Removes all elements from the array and returns self for chaining (e.g. `EphemeralArray::at(slot).clear()`\n /// to get a guaranteed-empty array at a given slot).\n pub unconstrained fn clear(self) -> Self {\n ephemeral::clear_oracle(self.slot);\n self\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. Iteration proceeds\n /// backwards so that it is safe to remove the current element (and only the current element) inside the\n /// callback.\n ///\n /// It is **not** safe to push new elements from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use crate::test::mocks::MockStruct;\n use super::EphemeralArray;\n\n global SLOT: Field = 1230;\n global OTHER_SLOT: Field = 5670;\n\n #[test]\n unconstrained fn empty_array() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn empty_array_read() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.get(0);\n });\n }\n\n #[test(should_fail_with = \"is empty\")]\n unconstrained fn empty_array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.pop();\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn read_past_len() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.push(10);\n\n let popped: Field = array.pop();\n assert_eq(popped, 10);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test]\n unconstrained fn array_set() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.set(0, 99);\n assert_eq(array.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.remove(0);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_slots_are_isolated() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array_a = EphemeralArray::at(SLOT);\n let array_b = EphemeralArray::at(OTHER_SLOT);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn works_with_multi_field_type() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n\n let a = MockStruct::new(5, 6);\n let b = MockStruct::new(7, 8);\n array.push(a);\n array.push(b);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), a);\n assert_eq(array.get(1), b);\n\n let popped: MockStruct = array.pop();\n assert_eq(popped, b);\n assert_eq(array.len(), 1);\n });\n }\n\n #[test]\n unconstrained fn clear_returns_self() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(array.len(), 0);\n\n array.push(42);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 42);\n });\n }\n\n #[test]\n unconstrained fn clear_wipes_previous_data() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n array.push(1);\n array.push(2);\n array.push(3);\n assert_eq(array.len(), 3);\n\n // Clear the same slot, previous data should be gone.\n let fresh: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(fresh.len(), 0);\n fresh.push(4);\n assert_eq(fresh.get(0), 4);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/ephemeral/mod.nr","function_locations":[{"start":1305,"name":"EphemeralArray::at"},{"start":1438,"name":"EphemeralArray::len"},{"start":1618,"name":"EphemeralArray::push"},{"start":1888,"name":"EphemeralArray::pop"},{"start":2176,"name":"EphemeralArray::get"},{"start":2475,"name":"EphemeralArray::set"},{"start":2743,"name":"EphemeralArray::remove"},{"start":3022,"name":"EphemeralArray::clear"},{"start":3593,"name":"EphemeralArray::for_each"},{"start":3983,"name":"test::empty_array"},{"start":4280,"name":"test::empty_array_read"},{"start":4550,"name":"test::empty_array_pop"},{"start":4783,"name":"test::array_push"},{"start":5122,"name":"test::read_past_len"},{"start":5376,"name":"test::array_pop"},{"start":5783,"name":"test::array_set"},{"start":6081,"name":"test::array_remove_last"},{"start":6376,"name":"test::array_remove_some"},{"start":6847,"name":"test::array_remove_all"},{"start":7273,"name":"test::for_each_called_with_all_elements"},{"start":8009,"name":"test::for_each_remove_some"},{"start":8561,"name":"test::for_each_remove_all"},{"start":8960,"name":"test::different_slots_are_isolated"},{"start":9534,"name":"test::works_with_multi_field_type"},{"start":10148,"name":"test::clear_returns_self"},{"start":10535,"name":"test::clear_wipes_previous_data"}]},"77":{"source":"use crate::{event::EventSelector, messages::logs::event::MAX_EVENT_SERIALIZED_LEN};\nuse crate::protocol::{\n constants::DOM_SEP__EVENT_COMMITMENT,\n hash::{poseidon2_hash_with_separator, poseidon2_hash_with_separator_bounded_vec},\n traits::{Serialize, ToField},\n};\n\npub trait EventInterface {\n fn get_event_type_id() -> EventSelector;\n}\n\n/// A private event's commitment is a value stored on-chain which is used to verify that the event was indeed emitted.\n///\n/// It requires a `randomness` value that must be produced alongside the event in order to perform said validation.\n/// This random value prevents attacks in which someone guesses plausible events (e.g. 'Alice transfers to Bob an\n/// amount of 10'), since they will not be able to test for existence of their guessed events without brute-forcing the\n/// entire `Field` space by guessing `randomness` values.\npub fn compute_private_event_commitment(event: Event, randomness: Field) -> Field\nwhere\n Event: EventInterface + Serialize,\n{\n poseidon2_hash_with_separator(\n [randomness, Event::get_event_type_id().to_field()].concat(event.serialize()),\n DOM_SEP__EVENT_COMMITMENT,\n )\n}\n\n/// Unconstrained variant of [`compute_private_event_commitment`] which takes the event in serialized form.\n///\n/// This function is unconstrained as the mechanism it uses to compute the commitment would be very inefficient in a\n/// constrained environment (due to the hashing of a dynamically sized array). This is not an issue as it is typically\n/// invoked when processing event messages, which is an unconstrained operation.\npub unconstrained fn compute_private_serialized_event_commitment(\n serialized_event: BoundedVec,\n randomness: Field,\n event_type_id: Field,\n) -> Field {\n let mut commitment_preimage =\n BoundedVec::<_, 2 + MAX_EVENT_SERIALIZED_LEN>::from_array([randomness, event_type_id]);\n commitment_preimage.extend_from_bounded_vec(serialized_event);\n\n poseidon2_hash_with_separator_bounded_vec(commitment_preimage, DOM_SEP__EVENT_COMMITMENT)\n}\n\nmod test {\n use crate::event::event_interface::{\n compute_private_event_commitment, compute_private_serialized_event_commitment, EventInterface,\n };\n use crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN;\n use crate::protocol::traits::{Serialize, ToField};\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn max_size_serialized_event_commitment() {\n let serialized_event = BoundedVec::from_array([0; MAX_EVENT_SERIALIZED_LEN]);\n let _ = compute_private_serialized_event_commitment(serialized_event, 0, 0);\n }\n\n #[test]\n unconstrained fn event_commitment_equivalence() {\n let event = MockEvent::new(VALUE).build_event();\n\n assert_eq(\n compute_private_event_commitment(event, RANDOMNESS),\n compute_private_serialized_event_commitment(\n BoundedVec::from_array(event.serialize()),\n RANDOMNESS,\n MockEvent::get_event_type_id().to_field(),\n ),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_interface.nr","function_locations":[{"start":1013,"name":"compute_private_event_commitment"},{"start":1803,"name":"compute_private_serialized_event_commitment"},{"start":2570,"name":"test::max_size_serialized_event_commitment"},{"start":2814,"name":"test::event_commitment_equivalence"}]},"79":{"source":"use crate::protocol::{hash::poseidon2_hash_bytes, traits::{Deserialize, Empty, FromField, Serialize, ToField}};\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct EventSelector {\n // Low 32 bits of the poseidon2 hash of the event signature.\n inner: u32,\n}\n\nimpl FromField for EventSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for EventSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for EventSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl EventSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n EventSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_selector.nr","function_locations":[{"start":337,"name":"::from_field"},{"start":449,"name":"::to_field"},{"start":542,"name":"::empty"},{"start":647,"name":"EventSelector::from_u32"},{"start":751,"name":"EventSelector::from_signature"},{"start":985,"name":"EventSelector::zero"}]},"92":{"source":"use crate::protocol::{\n address::aztec_address::AztecAddress,\n constants::{DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, DOM_SEP__ECDH_FIELD_MASK, DOM_SEP__ECDH_SUBKEY},\n hash::poseidon2_hash_with_separator,\n point::Point,\n scalar::Scalar,\n traits::{FromField, ToField},\n};\nuse std::{embedded_curve_ops::multi_scalar_mul, ops::Neg};\n\n/// Computes a standard ECDH shared secret: secret * public_key = shared_secret.\n///\n/// The input secret is known only to one party. The output shared secret can be derived given knowledge of\n/// `public_key`'s key-pair and the public ephemeral secret, using this same function (with reversed inputs).\n///\n/// E.g.: Epk = esk * G // ephemeral key-pair\n/// Pk = sk * G // recipient key-pair\n/// Shared secret S = esk * Pk = sk * Epk\n///\n/// See also: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman\npub fn derive_ecdh_shared_secret(secret: Scalar, public_key: Point) -> Point {\n // TODO(F-553): Drop the `.to_embedded()` / `.into()` round-trip once the custom `Point` wrapper is removed and we\n // use `EmbeddedCurvePoint` directly.\n multi_scalar_mul([public_key.to_embedded()], [secret]).into()\n}\n\n/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.\n///\n/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`\npub(crate) fn compute_app_siloed_shared_secret(shared_secret: Point, contract_address: AztecAddress) -> Field {\n poseidon2_hash_with_separator(\n [shared_secret.x, shared_secret.y, contract_address.to_field()],\n DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET,\n )\n}\n\n/// Derives an indexed subkey from an app-siloed shared secret, used for AES key/IV derivation.\n///\n/// `s_i = h(DOM_SEP__ECDH_SUBKEY + i, s_app)`\npub(crate) fn derive_shared_secret_subkey(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_SUBKEY + index)\n}\n\n/// Derives an indexed field mask from an app-siloed shared secret, used for masking ciphertext fields.\n///\n/// `m_i = h(DOM_SEP__ECDH_FIELD_MASK + i, s_app)`\npub(crate) fn derive_shared_secret_field_mask(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_FIELD_MASK + index)\n}\n\n#[test]\nunconstrained fn test_consistency_with_typescript() {\n let secret = Scalar {\n lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,\n hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,\n };\n let point = Point {\n x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,\n y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,\n is_infinite: false,\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret, point);\n\n // This is just pasted from a test run. The original typescript code from which this could be generated seems to\n // have been deleted by someone, and soon the typescript code for encryption and decryption won't be needed, so\n // this will have to do.\n let hard_coded_shared_secret = Point {\n x: 0x15d55a5b3b2caa6a6207f313f05c5113deba5da9927d6421bcaa164822b911bc,\n y: 0x0974c3d0825031ae933243d653ebb1a0b08b90ee7f228f94c5c74739ea3c871e,\n is_infinite: false,\n };\n assert_eq(shared_secret, hard_coded_shared_secret);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_from_address_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let mut pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let mut pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let address_b = AztecAddress::from_field(pk_b.x);\n\n // We were lazy in deriving the secret keys, and didn't check the resulting y-coordinates of the pk_a or pk_b to be\n // less than half the field modulus. If needed, we negate the pk's so that they yield valid address points. (We\n // could also have negated the secrets, but there's no negate method for EmbeddedCurvesScalar).\n pk_a = if (AztecAddress::from_field(pk_a.x).to_address_point().unwrap().inner == pk_a) {\n pk_a\n } else {\n pk_a.neg()\n };\n pk_b = if (address_b.to_address_point().unwrap().inner == pk_b) {\n pk_b\n } else {\n pk_b.neg()\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, address_b.to_address_point().unwrap().inner);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_app_siloed_shared_secret_differs_per_contract() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(Scalar { lo: 0x3456, hi: 0x4567 }).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n\n let contract_a = AztecAddress::from_field(0xAAAA);\n let contract_b = AztecAddress::from_field(0xBBBB);\n\n let s_app_a = compute_app_siloed_shared_secret(shared_secret, contract_a);\n let s_app_b = compute_app_siloed_shared_secret(shared_secret, contract_b);\n\n assert(s_app_a != s_app_b, \"app-siloed secrets must differ for different contracts\");\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/keys/ecdh_shared_secret.nr","function_locations":[{"start":954,"name":"derive_ecdh_shared_secret"},{"start":1485,"name":"compute_app_siloed_shared_secret"},{"start":1876,"name":"derive_shared_secret_subkey"},{"start":2194,"name":"derive_shared_secret_field_mask"},{"start":2336,"name":"test_consistency_with_typescript"},{"start":3450,"name":"test_shared_secret_computation_in_both_directions"},{"start":4017,"name":"test_shared_secret_computation_from_address_in_both_directions"},{"start":5278,"name":"test_app_siloed_shared_secret_differs_per_contract"}]},"97":{"source":"// Not all log levels are currently used, but we provide the full set so that new call sites can use any level. Because\n// of that we tag all with `#[allow(dead_code)]` to prevent warnings.\n//\n// All wrappers resolve function paths at comptime via `resolve_fn` so that the emitted `Quoted` code works both inside\n// aztec-nr (where `crate::` = aztec) and inside macro-generated contract code (where `crate::` = the contract).\n\nuse std::meta::ctstring::AsCtString;\n\ncomptime fn log_prefix(msg: str) -> CtString {\n \"[aztec-nr] \".as_ctstring().append_str(msg)\n}\n\n// --- No-args variants (direct call) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log });\n quote { $f($msg) }\n}\n\n// --- Format variants (return lambda for runtime args) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n// See module-level comment for why this is needed.\ncomptime fn resolve_fn(path: Quoted) -> TypedExpr {\n path.as_expr().unwrap().resolve(Option::none())\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/logging.nr","function_locations":[{"start":525,"name":"log_prefix"},{"start":717,"name":"aztecnr_fatal_log"},{"start":943,"name":"aztecnr_error_log"},{"start":1168,"name":"aztecnr_warn_log"},{"start":1392,"name":"aztecnr_info_log"},{"start":1619,"name":"aztecnr_verbose_log"},{"start":1847,"name":"aztecnr_debug_log"},{"start":2073,"name":"aztecnr_trace_log"},{"start":2367,"name":"aztecnr_fatal_log_format"},{"start":2622,"name":"aztecnr_error_log_format"},{"start":2876,"name":"aztecnr_warn_log_format"},{"start":3129,"name":"aztecnr_info_log_format"},{"start":3385,"name":"aztecnr_verbose_log_format"},{"start":3642,"name":"aztecnr_debug_log_format"},{"start":3897,"name":"aztecnr_trace_log_format"},{"start":4151,"name":"resolve_fn"}]},"99":{"source":"use crate::logging;\nuse crate::macros::{notes::NOTES, utils::get_trait_impl_method};\n\n/// Generates two contract library methods called `_compute_note_hash` and `_compute_note_nullifier`, plus a\n/// (deprecated) wrapper called `_compute_note_hash_and_nullifier`, which are used for note discovery (i.e. these are\n/// of the `aztec::messages::discovery::ComputeNoteHash` and `aztec::messages::discovery::ComputeNoteNullifier` types).\npub(crate) comptime fn generate_contract_library_methods_compute_note_hash_and_nullifier() -> Quoted {\n let compute_note_hash = generate_contract_library_method_compute_note_hash();\n let compute_note_nullifier = generate_contract_library_method_compute_note_nullifier();\n\n quote {\n $compute_note_hash\n $compute_note_nullifier\n\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n #[allow(dead_code)]\n unconstrained fn _compute_note_hash_and_nullifier(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n note_nonce: Field,\n ) -> Option {\n _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash| {\n\n let siloed_note_hash = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash);\n let unique_note_hash = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash);\n \n let inner_nullifier = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness);\n\n aztec::messages::discovery::NoteHashAndNullifier {\n note_hash,\n inner_nullifier,\n }\n })\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_hash() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the note hash (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_note_hash = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_note_hash },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n Option::some($compute_note_hash(note, owner, storage_slot, randomness))\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed).\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_nullifier() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the inner nullifier (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_nullifier_unconstrained = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_nullifier_unconstrained },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n // The message discovery process finds settled notes, that is, notes that were created in\n // prior transactions and are therefore already part of the note hash tree. The note hash\n // for nullification is hence the unique note hash.\n $compute_nullifier_unconstrained(note, owner, unique_note_hash)\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data.\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec/compute_note_hash_and_nullifier.nr","function_locations":[{"start":534,"name":"generate_contract_library_methods_compute_note_hash_and_nullifier"},{"start":2449,"name":"generate_contract_library_method_compute_note_hash"},{"start":7674,"name":"generate_contract_library_method_compute_note_nullifier"}]},"100":{"source":"mod compute_note_hash_and_nullifier;\n\nuse crate::{\n macros::{\n calls_generation::{\n external_functions::{generate_external_function_calls, generate_external_function_self_calls_structs},\n internal_functions::generate_call_internal_struct,\n },\n dispatch::generate_public_dispatch,\n emit_public_init_nullifier::generate_emit_public_init_nullifier,\n internals_functions_generation::{create_fn_abi_exports, process_functions},\n storage::STORAGE_LAYOUT_NAME,\n utils::{is_fn_contract_library_method, is_fn_external, is_fn_internal, is_fn_test, module_has_storage},\n },\n messages::discovery::CustomMessageHandler,\n};\n\nuse compute_note_hash_and_nullifier::generate_contract_library_methods_compute_note_hash_and_nullifier;\n\n/// Configuration for the [`aztec`] macro.\n///\n/// This type lets users override different parts of the default aztec-nr contract behavior, such\n/// as message handling. These are advanced features that require careful understanding of\n/// the behavior of these systems.\n///\n/// ## Examples\n///\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyContract { ... }\n/// ```\npub struct AztecConfig {\n custom_message_handler: Option>,\n}\n\nimpl AztecConfig {\n /// Creates a new `AztecConfig` with default values.\n ///\n /// Calling `new` is equivalent to invoking the [`aztec`] macro with no parameters. The different methods\n /// (e.g. [`AztecConfig::custom_message_handler`]) can then be used to change the default behavior.\n pub comptime fn new() -> Self {\n Self { custom_message_handler: Option::none() }\n }\n\n /// Sets a handler for custom messages.\n ///\n /// This enables contracts to process non-standard messages (i.e. any with a message type that is not in\n /// [`crate::messages::msg_type`]).\n ///\n /// `handler` must be a function that conforms to the\n /// [`crate::messages::discovery::CustomMessageHandler`] type signature.\n pub comptime fn custom_message_handler(_self: Self, handler: CustomMessageHandler<()>) -> Self {\n Self { custom_message_handler: Option::some(handler) }\n }\n}\n\n/// Enables aztec-nr features on a `contract`.\n///\n/// All aztec-nr contracts should have this macro invoked on them, as it is the one that processes all contract\n/// functions, notes, storage, generates interfaces for external calls, and creates the message processing\n/// boilerplate.\n///\n/// ## Examples\n///\n/// Most contracts can simply invoke the macro with no parameters, resulting in default aztec-nr behavior:\n/// ```noir\n/// #[aztec]\n/// contract MyContract { ... }\n/// ```\n///\n/// Advanced contracts can use [`AztecConfig`] to customize parts of its behavior, such as message\n/// processing.\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyAdvancedContract { ... }\n/// ```\n#[varargs]\npub comptime fn aztec(m: Module, args: [AztecConfig]) -> Quoted {\n let num_args = args.len();\n let config = if num_args == 0 {\n AztecConfig::new()\n } else if num_args == 1 {\n args[0]\n } else {\n panic(f\"#[aztec] expects 0 or 1 arguments, got {num_args}\")\n };\n\n // Functions that don't have #[external(...)], #[contract_library_method], or #[test] are not allowed in contracts.\n check_each_fn_macroified(m);\n\n // We generate new functions prefixed with `__aztec_nr_internals__` and we replace the original functions' bodies\n // with `static_assert(false, ...)` to prevent them from being called directly from within the contract.\n let functions = process_functions(m);\n\n // We generate structs and their implementations necessary for convenient functions calls.\n let interface = generate_contract_interface(m);\n let self_call_structs = generate_external_function_self_calls_structs(m);\n let call_internal_struct = generate_call_internal_struct(m);\n\n // We generate ABI exports for all the external functions in the contract.\n let fn_abi_exports = create_fn_abi_exports(m);\n\n // We generate `_compute_note_hash`, `_compute_note_nullifier` (and the deprecated\n // `_compute_note_hash_and_nullifier` wrapper) and `sync_state` functions only if they are not already implemented.\n // If they are implemented we just insert empty quotes.\n let contract_library_method_compute_note_hash_and_nullifier = if !m.functions().any(|f| {\n // Note that we don't test for `_compute_note_hash` or `_compute_note_nullifier` in order to make this simpler\n // - users must either implement all three or none.\n // Down the line we'll remove this check and use `AztecConfig`.\n f.name() == quote { _compute_note_hash_and_nullifier }\n }) {\n generate_contract_library_methods_compute_note_hash_and_nullifier()\n } else {\n quote {}\n };\n let process_custom_message_option = if config.custom_message_handler.is_some() {\n let handler = config.custom_message_handler.unwrap();\n quote { Option::some($handler) }\n } else {\n quote { Option::>::none() }\n };\n\n let offchain_inbox_sync_option = quote {\n Option::some(aztec::messages::processing::offchain::sync_inbox)\n };\n\n let sync_state_fn_and_abi_export = if !m.functions().any(|f| f.name() == quote { sync_state }) {\n generate_sync_state(process_custom_message_option, offchain_inbox_sync_option)\n } else {\n quote {}\n };\n\n if m.functions().any(|f| f.name() == quote { offchain_receive }) {\n panic(\n \"User-defined 'offchain_receive' is not allowed. The function is auto-injected by the #[aztec] macro. See https://docs.aztec.network/errors/7\",\n );\n }\n let offchain_receive_fn_and_abi_export = generate_offchain_receive();\n\n let (has_public_init_nullifier_fn, emit_public_init_nullifier_fn_body) = generate_emit_public_init_nullifier(m);\n let public_dispatch = generate_public_dispatch(m, has_public_init_nullifier_fn);\n\n quote {\n $interface\n $self_call_structs\n $call_internal_struct\n $functions\n $fn_abi_exports\n $contract_library_method_compute_note_hash_and_nullifier\n $public_dispatch\n $sync_state_fn_and_abi_export\n $emit_public_init_nullifier_fn_body\n $offchain_receive_fn_and_abi_export\n }\n}\n\ncomptime fn generate_contract_interface(m: Module) -> Quoted {\n let calls = generate_external_function_calls(m);\n\n let module_name = m.name();\n\n let has_storage_layout = module_has_storage(m) & STORAGE_LAYOUT_NAME.get(m).is_some();\n let storage_layout_getter = if has_storage_layout {\n let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap();\n quote {\n pub fn storage_layout() -> StorageLayoutFields {\n $storage_layout_name.fields\n }\n }\n } else {\n quote {}\n };\n\n let library_storage_layout_getter = if has_storage_layout {\n quote {\n #[contract_library_method]\n $storage_layout_getter\n }\n } else {\n quote {}\n };\n\n quote {\n pub struct $module_name {\n pub target_contract: aztec::protocol::address::AztecAddress\n }\n\n impl $module_name {\n $calls\n\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> Self {\n Self { target_contract: addr }\n }\n\n pub fn interface() -> Self {\n Self { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $storage_layout_getter\n }\n\n #[contract_library_method]\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> $module_name {\n $module_name { target_contract: addr }\n }\n\n #[contract_library_method]\n pub fn interface() -> $module_name {\n $module_name { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $library_storage_layout_getter\n\n }\n}\n\n/// Generates the `sync_state` utility function that performs message discovery.\ncomptime fn generate_sync_state(process_custom_message_option: Quoted, offchain_inbox_sync_option: Quoted) -> Quoted {\n quote {\n pub struct sync_state_parameters {\n pub scope: aztec::protocol::address::AztecAddress,\n }\n\n #[abi(functions)]\n pub struct sync_state_abi {\n parameters: sync_state_parameters,\n }\n\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn sync_state(scope: aztec::protocol::address::AztecAddress) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::discovery::do_sync_state(\n address,\n _compute_note_hash,\n _compute_note_nullifier,\n $process_custom_message_option,\n $offchain_inbox_sync_option,\n scope,\n );\n }\n }\n}\n\n/// Generates an `offchain_receive` utility function that lets callers add messages to the offchain message inbox.\n///\n/// For more details, see `aztec::messages::processing::offchain::receive`.\ncomptime fn generate_offchain_receive() -> Quoted {\n quote {\n pub struct offchain_receive_parameters {\n pub messages: BoundedVec<\n aztec::messages::processing::offchain::OffchainMessage,\n aztec::messages::processing::offchain::MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL,\n >,\n }\n\n #[abi(functions)]\n pub struct offchain_receive_abi {\n parameters: offchain_receive_parameters,\n }\n\n /// Receives offchain messages into this contract's offchain inbox for subsequent processing.\n ///\n /// Each message is routed to the inbox scoped to its `recipient` field.\n ///\n /// For more details, see `aztec::messages::processing::offchain::receive`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn offchain_receive(\n messages: BoundedVec<\n aztec::messages::processing::offchain::OffchainMessage,\n aztec::messages::processing::offchain::MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL,\n >,\n ) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::processing::offchain::receive(address, messages);\n }\n }\n}\n\n/// Checks that all functions in the module have a context macro applied.\n///\n/// Non-macroified functions are not allowed in contracts. They must all be one of\n/// [`crate::macros::functions::external`], [`crate::macros::functions::internal`] or `test`.\ncomptime fn check_each_fn_macroified(m: Module) {\n for f in m.functions() {\n let name = f.name();\n if !is_fn_external(f) & !is_fn_contract_library_method(f) & !is_fn_internal(f) & !is_fn_test(f) {\n // We don't suggest that #[contract_library_method] is allowed because we don't want to introduce another\n // concept\n panic(\n f\"Function {name} must be marked as either #[external(...)], #[internal(...)], or #[test]\",\n );\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec.nr","function_locations":[{"start":1648,"name":"AztecConfig::new"},{"start":2156,"name":"AztecConfig::custom_message_handler"},{"start":3050,"name":"aztec"},{"start":6527,"name":"generate_contract_interface"},{"start":8389,"name":"generate_sync_state"},{"start":9443,"name":"generate_offchain_receive"},{"start":11087,"name":"check_each_fn_macroified"}]},"126":{"source":"use crate::logging::{aztecnr_debug_log, aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\npub(crate) mod nonce_discovery;\npub(crate) mod partial_notes;\npub(crate) mod private_events;\npub mod private_notes;\npub mod process_message;\n\nuse crate::{\n messages::{\n discovery::process_message::process_message_ciphertext,\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{\n MessageContext, offchain::OffchainInboxSync, OffchainMessageWithContext,\n pending_tagged_log::PendingTaggedLog, validate_and_store_enqueued_notes_and_events,\n },\n },\n oracle::message_processing,\n utils::array,\n};\n\npub struct NoteHashAndNullifier {\n /// The result of [`crate::note::note_interface::NoteHash::compute_note_hash`].\n pub note_hash: Field,\n /// The result of [`crate::note::note_interface::NoteHash::compute_nullifier_unconstrained`].\n ///\n /// This value is unconstrained, as all of message discovery is unconstrained. It is `None` if the nullifier\n /// cannot be computed (e.g. because the nullifier hiding key is not available).\n pub inner_nullifier: Option,\n}\n\n/// A contract's way of computing note hashes.\n///\n/// Each contract in the network is free to compute their note's hash as they see fit - the hash function itself is not\n/// enshrined or standardized. Some aztec-nr functions however do need to know the details of this computation (e.g.\n/// when finding new notes), which is what this type represents.\n///\n/// This function takes a note's packed content, storage slot, note type ID, address of the emitting contract and\n/// randomness, and attempts to compute its inner note hash (not siloed by address nor uniqued by nonce).\n///\n/// ## Transient Notes\n///\n/// This function is meant to always be used on **settled** notes, i.e. those that have been inserted into the trees\n/// and for which the nonce is known. It is never invoked in the context of a transient note, as those are not involved\n/// in message processing.\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract by inspecting all note types in use and the storage layout. This injected function is a\n/// `#[contract_library_method]` called `_compute_note_hash`, and it looks something like this:\n///\n/// ```noir\n/// |packed_note, owner, storage_slot, note_type_id, _contract_address, randomness| {\n/// if note_type_id == MyNoteType::get_id() {\n/// if packed_note.len() != MY_NOTE_TYPE_SERIALIZATION_LENGTH {\n/// Option::none()\n/// } else {\n/// let note = MyNoteType::unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n/// Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n/// }\n/// } else if note_type_id == MyOtherNoteType::get_id() {\n/// ... // Similar to above but calling MyOtherNoteType::unpack\n/// } else {\n/// Option::none() // Unknown note type ID\n/// };\n/// }\n/// ```\npub type ComputeNoteHash = unconstrained fn(/* packed_note */BoundedVec, /*\n owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress, /*\nrandomness */ Field) -> Option;\n\n/// A contract's way of computing note nullifiers.\n///\n/// Like [`ComputeNoteHash`], each contract is free to derive nullifiers as they see fit. This function takes the\n/// unique note hash (used as the note hash for nullification for settled notes), plus the note's packed content and\n/// metadata, and attempts to compute the inner nullifier (not siloed by address).\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract called `_compute_note_nullifier`. It dispatches on `note_type_id` similarly to\n/// [`ComputeNoteHash`], then calls the note's\n/// [`compute_nullifier_unconstrained`](crate::note::note_interface::NoteHash::compute_nullifier_unconstrained) method.\npub type ComputeNoteNullifier = unconstrained fn(/* unique_note_hash */Field, /* packed_note */ BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/* randomness */ Field) -> Option;\n\n/// Deprecated: use [`ComputeNoteHash`] and [`ComputeNoteNullifier`] instead.\npub type ComputeNoteHashAndNullifier = unconstrained fn[Env](/* packed_note */BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/*randomness */ Field, /* note nonce */ Field) -> Option;\n\n/// A handler for custom messages.\n///\n/// Contracts that emit custom messages (i.e. any with a message type that is not in [`crate::messages::msg_type`])\n/// need to use [`crate::macros::AztecConfig::custom_message_handler`] with a function of this type in order to\n/// process them. They will otherwise be **silently ignored**.\npub type CustomMessageHandler = unconstrained fn[Env](\n/* contract_address */AztecAddress,\n/* msg_type_id */ u64,\n/* msg_metadata */ u64,\n/* msg_content */ BoundedVec,\n/* message_context */ MessageContext,\n/* scope */ AztecAddress);\n\n/// Synchronizes the contract's private state with the network.\n///\n/// As blocks are mined, it is possible for a contract's private state to change (e.g. with new notes being created),\n/// but because these changes are private they will be invisible to most actors. This is the function that processes\n/// new transactions in order to discover new notes, events, and other kinds of private state changes.\n///\n/// The private state will be synchronized up to the block that will be used for private transactions (i.e. the anchor\n/// block. This will typically be close to the tip of the chain.\npub unconstrained fn do_sync_state(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n offchain_inbox_sync: Option>,\n scope: AztecAddress,\n) {\n aztecnr_debug_log!(\"Performing state synchronization\");\n\n // First we process all private logs, which can contain different kinds of messages e.g. private notes, partial\n // notes, private events, etc.\n let logs = message_processing::get_pending_tagged_logs(scope);\n logs.for_each(|_i, pending_tagged_log: PendingTaggedLog| {\n if pending_tagged_log.log.len() == 0 {\n aztecnr_warn_log_format!(\"Skipping empty log from tx {0}\")([pending_tagged_log.context.tx_hash]);\n } else {\n aztecnr_debug_log_format!(\"Processing log with tag {0}\")([pending_tagged_log.log.get(0)]);\n\n // We remove the tag from the pending tagged log and process the message ciphertext contained in it.\n let message_ciphertext = array::subbvec(pending_tagged_log.log, 1);\n\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_ciphertext,\n pending_tagged_log.context,\n scope,\n );\n }\n });\n\n if offchain_inbox_sync.is_some() {\n let msgs = offchain_inbox_sync.unwrap()(contract_address, scope);\n msgs.for_each(|_i, msg: OffchainMessageWithContext| {\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n msg.message_ciphertext,\n msg.message_context,\n scope,\n );\n });\n }\n\n // Then we process all pending partial notes, regardless of whether they were found in the current or previous\n // executions.\n partial_notes::fetch_and_process_partial_note_completion_logs(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n scope,\n );\n\n // Finally we validate all notes and events that were found as part of the previous processes, resulting in them\n // being added to PXE's database and retrievable via oracles (get_notes) and our TS API (PXE::getPrivateEvents).\n validate_and_store_enqueued_notes_and_events(scope);\n}\n\nmod test {\n use crate::ephemeral::EphemeralArray;\n use crate::messages::{\n discovery::{CustomMessageHandler, do_sync_state},\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{offchain::OffchainInboxSync, pending_tagged_log::PendingTaggedLog},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n\n #[test]\n unconstrained fn do_sync_state_does_not_panic_on_empty_logs() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n\n let contract_address = AztecAddress { inner: 0xdeadbeef };\n\n env.utility_context_at(contract_address, |_| {\n // Mock the oracle call to return a known base slot, then populate an ephemeral\n // array at that slot so do_sync_state processes a non-empty log list.\n let base_slot = 42;\n let mock = std::test::OracleMock::mock(\"aztec_utl_getPendingTaggedLogs_v2\");\n let _ = mock.returns(base_slot);\n\n let logs: EphemeralArray = EphemeralArray::at(base_slot);\n logs.push(PendingTaggedLog { log: BoundedVec::new(), context: std::mem::zeroed() });\n assert_eq(logs.len(), 1);\n\n let no_handler: Option> = Option::none();\n let no_inbox_sync: Option> = Option::none();\n do_sync_state(\n contract_address,\n dummy_compute_note_hash,\n dummy_compute_note_nullifier,\n no_handler,\n no_inbox_sync,\n scope,\n );\n });\n }\n\n unconstrained fn dummy_compute_note_hash(\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n\n unconstrained fn dummy_compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr","function_locations":[{"start":6465,"name":"do_sync_state"},{"start":9175,"name":"test::do_sync_state_does_not_panic_on_empty_logs"},{"start":10673,"name":"test::dummy_compute_note_hash"},{"start":11034,"name":"test::dummy_compute_note_nullifier"}]},"127":{"source":"use crate::messages::{discovery::{ComputeNoteHash, ComputeNoteNullifier}, logs::note::MAX_NOTE_PACKED_LEN};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{\n address::AztecAddress,\n constants::MAX_NOTE_HASHES_PER_TX,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::ToField,\n};\n\n/// A struct with the discovered information of a complete note, required for delivery to PXE. Note that this is *not*\n/// the complete note information, since it does not include content, storage slot, etc.\npub(crate) struct DiscoveredNoteInfo {\n pub(crate) note_nonce: Field,\n pub(crate) note_hash: Field,\n pub(crate) inner_nullifier: Field,\n}\n\n/// Searches for note nonces that will result in a note that was emitted in a transaction. While rare, it is possible\n/// for multiple notes to have the exact same packed content and storage slot but different nonces, resulting in\n/// different unique note hashes. Because of this this function returns a *vector* of discovered notes, though in most\n/// cases it will contain a single element.\n///\n/// Due to how nonces are computed, this function requires knowledge of the transaction in which the note was created,\n/// more specifically the list of all unique note hashes in it plus the value of its first nullifier.\npub(crate) unconstrained fn attempt_note_nonce_discovery(\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) -> BoundedVec {\n let discovered_notes = &mut BoundedVec::new();\n\n aztecnr_debug_log_format!(\n \"Attempting nonce discovery on {0} potential notes on contract {1} for storage slot {2}\",\n )(\n [unique_note_hashes_in_tx.len() as Field, contract_address.to_field(), storage_slot],\n );\n\n let maybe_note_hash = compute_note_hash(\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_note_hash.is_none() {\n aztecnr_warn_log_format!(\n \"Unable to compute note hash for note of id {0} with packed length {1}, skipping nonce discovery\",\n )(\n [note_type_id, packed_note.len() as Field],\n );\n } else {\n let note_hash = maybe_note_hash.unwrap();\n let siloed_note_hash = compute_siloed_note_hash(contract_address, note_hash);\n\n // We need to find nonces (typically just one) that result in the siloed note hash that being uniqued into one\n // of the transaction's effects.\n // The nonce is meant to be derived from the index of the note hash in the transaction effects array. However,\n // due to an issue in the kernels the nonce might actually use any of the possible note hash indices - not\n // necessarily the one that corresponds to the note hash. Hence, we need to try them all.\n for i in 0..MAX_NOTE_HASHES_PER_TX {\n let nonce_for_i = compute_note_hash_nonce(first_nullifier_in_tx, i);\n let unique_note_hash_for_i = compute_unique_note_hash(nonce_for_i, siloed_note_hash);\n\n let matching_notes = bvec_filter(\n unique_note_hashes_in_tx,\n |unique_note_hash_in_tx| unique_note_hash_in_tx == unique_note_hash_for_i,\n );\n if matching_notes.len() > 1 {\n let identical_note_hashes = matching_notes.len();\n // Note that we don't actually check that the note hashes array contains unique values, only that the\n // note we found is unique. We don't expect for this to ever happen (it'd indicate a malicious node or\n // PXE, which are both assumed to be cooperative) so testing for it just in case is unnecessary, but we\n // _do_ need to handle it if we find a duplicate.\n panic(\n f\"Received {identical_note_hashes} identical note hashes for a transaction - these should all be unique\",\n )\n } else if matching_notes.len() == 1 {\n let maybe_inner_nullifier_for_i = compute_note_nullifier(\n unique_note_hash_for_i,\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_inner_nullifier_for_i.is_none() {\n // TODO: down the line we want to be able to store notes for which we don't know their nullifier,\n // e.g. notes that belong to someone that is not us (and for which we therefore don't know their\n // associated app-siloed nullifer hiding secret key).\n // https://linear.app/aztec-labs/issue/F-265/store-external-notes\n aztecnr_warn_log_format!(\n \"Unable to compute nullifier of unique note {0} with note type id {1} and owner {2}, skipping PXE insertion\",\n )(\n [unique_note_hash_for_i, note_type_id, owner.to_field()],\n );\n } else {\n // Note that while we did check that the note hash is the preimage of a unique note hash, we\n // perform no validations on the nullifier - we fundamentally cannot, since only the application\n // knows how to compute nullifiers. We simply trust it to have provided the correct one: if it\n // hasn't, then PXE may fail to realize that a given note has been nullified already, and calls to\n // the application could result in invalid transactions (with duplicate nullifiers). This is not a\n // concern because an application already has more direct means of making a call to it fail the\n // transaction.\n discovered_notes.push(\n DiscoveredNoteInfo {\n note_nonce: nonce_for_i,\n note_hash,\n inner_nullifier: maybe_inner_nullifier_for_i.unwrap(),\n },\n );\n }\n // We don't exit the loop - it is possible (though rare) for the exact same note content to be present\n // multiple times in the same transaction with different nonces. This typically doesn't happen due to\n // notes containing random values in order to hide their contents.\n }\n }\n }\n\n *discovered_notes\n}\n\n// There is no BoundedVec::filter in the stdlib, so we use this until that is implemented.\nunconstrained fn bvec_filter(\n bvec: BoundedVec,\n filter: fn[Env](T) -> bool,\n) -> BoundedVec {\n let filtered = &mut BoundedVec::new();\n\n bvec.for_each(|value| {\n if filter(value) {\n filtered.push(value);\n }\n });\n\n *filtered\n}\n\nmod test {\n use crate::{\n messages::logs::note::MAX_NOTE_PACKED_LEN,\n note::{\n note_interface::{NoteHash, NoteType},\n note_metadata::SettledNoteMetadata,\n utils::compute_note_hash_for_nullification,\n },\n oracle::random::random,\n test::mocks::mock_note::MockNote,\n utils::array,\n };\n\n use crate::protocol::{\n address::AztecAddress,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::{FromField, Packable},\n };\n\n use super::attempt_note_nonce_discovery;\n\n // This implementation could be simpler, but this serves as a nice example of the expected flow in a real\n // implementation, and as a sanity check that the interface is sufficient.\n\n unconstrained fn compute_note_hash(\n packed_note: BoundedVec,\n owner: AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n } else {\n Option::none()\n }\n }\n\n unconstrained fn compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n note.compute_nullifier_unconstrained(owner, unique_note_hash)\n } else {\n Option::none()\n }\n }\n\n global VALUE: Field = 7;\n global FIRST_NULLIFIER_IN_TX: Field = 47;\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress::from_field(13);\n global OWNER: AztecAddress = AztecAddress::from_field(14);\n global STORAGE_SLOT: Field = 99;\n global RANDOMNESS: Field = 99;\n\n #[test]\n unconstrained fn no_note_hashes() {\n let unique_note_hashes_in_tx = BoundedVec::new();\n let packed_note = BoundedVec::new();\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n packed_note,\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_hash_computation_is_ignored() {\n let unique_note_hashes_in_tx = BoundedVec::from_array([random()]);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n |_, _, _, _, _, _| Option::none(),\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::new(),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_nullifier_computation_is_ignored() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n |_, _, _, _, _, _, _| Option::none(),\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n struct NoteAndData {\n note: MockNote,\n note_nonce: Field,\n note_hash: Field,\n unique_note_hash: Field,\n inner_nullifier: Field,\n }\n\n unconstrained fn construct_note(value: Field, note_index_in_tx: u32) -> NoteAndData {\n let note_nonce = compute_note_hash_nonce(FIRST_NULLIFIER_IN_TX, note_index_in_tx);\n\n let hinted_note = MockNote::new(value)\n .contract_address(CONTRACT_ADDRESS)\n .owner(OWNER)\n .randomness(RANDOMNESS)\n .storage_slot(STORAGE_SLOT)\n .note_metadata(SettledNoteMetadata::new(note_nonce).into())\n .build_hinted_note();\n let note = hinted_note.note;\n\n let note_hash = note.compute_note_hash(OWNER, STORAGE_SLOT, RANDOMNESS);\n let unique_note_hash = compute_unique_note_hash(\n note_nonce,\n compute_siloed_note_hash(CONTRACT_ADDRESS, note_hash),\n );\n let inner_nullifier = note\n .compute_nullifier_unconstrained(OWNER, compute_note_hash_for_nullification(hinted_note))\n .expect(f\"Could not compute nullifier for note owned by {OWNER}\");\n\n NoteAndData { note, note_nonce, note_hash, unique_note_hash, inner_nullifier }\n }\n\n #[test]\n unconstrained fn single_note() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn multiple_notes_same_preimage() {\n let first_note_index_in_tx = 3;\n let first_note_and_data = construct_note(VALUE, first_note_index_in_tx);\n\n let second_note_index_in_tx = 5;\n let second_note_and_data = construct_note(VALUE, second_note_index_in_tx);\n\n // Both notes have the same preimage (and therefore packed representation), so both should be found in the same\n // call.\n assert_eq(first_note_and_data.note, second_note_and_data.note);\n let packed_note = first_note_and_data.note.pack();\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(first_note_index_in_tx, first_note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(second_note_index_in_tx, second_note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(packed_note),\n );\n\n assert_eq(discovered_notes.len(), 2);\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == first_note_and_data.note_nonce)\n & (discovered_note.note_hash == first_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == first_note_and_data.inner_nullifier)\n }));\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == second_note_and_data.note_nonce)\n & (discovered_note.note_hash == second_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == second_note_and_data.inner_nullifier)\n }));\n }\n\n #[test]\n unconstrained fn single_note_misaligned_nonce() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The note is not at the correct index\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn single_note_nonce_with_index_past_note_hashes_in_tx() {\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The nonce is computed with an index that does not exist in the tx\n let note_index_in_tx = unique_note_hashes_in_tx.len() + 5;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n // The note is inserted at an arbitrary index - its true index is out of the array's bounds\n unique_note_hashes_in_tx.set(2, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test(should_fail_with = \"identical note hashes for a transaction\")]\n unconstrained fn duplicate_unique_note_hashes() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The same unique note hash is present in two indices in the array, which is not allowed. Note that we don't\n // test all note hashes for uniqueness, only those that we actually find.\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let _ = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/nonce_discovery.nr","function_locations":[{"start":1866,"name":"attempt_note_nonce_discovery"},{"start":7210,"name":"bvec_filter"},{"start":8458,"name":"test::compute_note_hash"},{"start":9107,"name":"test::compute_note_nullifier"},{"start":9764,"name":"test::no_note_hashes"},{"start":10362,"name":"test::failed_hash_computation_is_ignored"},{"start":10959,"name":"test::failed_nullifier_computation_is_ignored"},{"start":12052,"name":"test::construct_note"},{"start":13085,"name":"test::single_note"},{"start":14249,"name":"test::multiple_notes_same_preimage"},{"start":16275,"name":"test::single_note_misaligned_nonce"},{"start":17515,"name":"test::single_note_nonce_with_index_past_note_hashes_in_tx"},{"start":18937,"name":"test::duplicate_unique_note_hashes"}]},"128":{"source":"use crate::{\n capsules::CapsuleArray,\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::partial_note::{decode_partial_note_private_message, MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN},\n processing::{\n enqueue_note_for_validation,\n get_pending_partial_notes_completion_logs,\n log_retrieval_response::{LogRetrievalResponse, MAX_LOG_CONTENT_LEN},\n },\n },\n utils::array,\n};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{address::AztecAddress, hash::sha256_to_field, traits::{Deserialize, Serialize}};\n\n/// The slot in the PXE capsules where we store a `CapsuleArray` of `DeliveredPendingPartialNote`.\npub(crate) global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT\".as_bytes(),\n);\n\n/// A partial note that was delivered but is still pending completion. Contains the information necessary to find the\n/// log that will complete it and lead to a note being discovered and delivered.\n#[derive(Serialize, Deserialize)]\npub(crate) struct DeliveredPendingPartialNote {\n pub(crate) owner: AztecAddress,\n pub(crate) randomness: Field,\n pub(crate) note_completion_log_tag: Field,\n pub(crate) note_type_id: Field,\n pub(crate) packed_private_note_content: BoundedVec,\n}\n\npub(crate) unconstrained fn process_partial_note_private_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n scope: AztecAddress,\n) {\n let decoded = decode_partial_note_private_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n // We store the information of the partial note we found in a persistent capsule in PXE, so that we can later\n // search for the public log that will complete it.\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content) = decoded.unwrap();\n\n let pending = DeliveredPendingPartialNote {\n owner,\n randomness,\n note_completion_log_tag,\n note_type_id,\n packed_private_note_content,\n };\n\n CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n )\n .push(pending);\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode partial note private message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Searches for logs that would result in the completion of pending partial notes, ultimately resulting in the notes\n/// being delivered to PXE if completed.\npub(crate) unconstrained fn fetch_and_process_partial_note_completion_logs(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n scope: AztecAddress,\n) {\n let pending_partial_notes = CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n );\n\n aztecnr_debug_log_format!(\"{} pending partial notes\")([pending_partial_notes.len() as Field]);\n\n // Each of the pending partial notes might get completed by a log containing its public values. For performance\n // reasons, we fetch all of these logs concurrently and then process them one by one, minimizing the amount of time\n // waiting for the node roundtrip.\n let maybe_completion_logs = get_pending_partial_notes_completion_logs(contract_address, pending_partial_notes);\n\n // Each entry in the maybe completion logs array corresponds to the entry in the pending partial notes array at the\n // same index. This means we can use the same index as we iterate through the responses to get both the partial\n // note and the log that might complete it.\n assert_eq(maybe_completion_logs.len(), pending_partial_notes.len());\n\n maybe_completion_logs.for_each(|i, maybe_log: Option| {\n let pending_partial_note = pending_partial_notes.get(i);\n\n if maybe_log.is_none() {\n aztecnr_debug_log_format!(\"Found no completion logs for partial note with tag {}\")(\n [pending_partial_note.note_completion_log_tag],\n );\n\n // Note that we're not removing the pending partial note from the capsule array, so we will continue\n // searching for this tagged log when performing message discovery in the future until we either find it or\n // the entry is somehow removed from the array.\n } else {\n aztecnr_debug_log_format!(\"Completion log found for partial note with tag {}\")([\n pending_partial_note.note_completion_log_tag,\n ]);\n let log = maybe_log.unwrap();\n\n // The first field in the completion log payload is the storage slot, followed by the public note\n // content fields.\n let storage_slot = log.log_payload.get(0);\n let public_note_content: BoundedVec = array::subbvec(log.log_payload, 1);\n\n // Public fields are assumed to all be placed at the end of the packed representation, so we combine\n // the private and public packed fields (i.e. the contents of the private message and public log\n // plaintext) to get the complete packed content.\n let complete_packed_note = array::append(\n pending_partial_note.packed_private_note_content,\n public_note_content,\n );\n\n let discovered_notes = attempt_note_nonce_discovery(\n log.unique_note_hashes_in_tx,\n log.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n pending_partial_note.note_type_id,\n complete_packed_note,\n );\n\n // TODO(#11627): is there anything reasonable we can do if we get a log but it doesn't result in a note\n // being found?\n if discovered_notes.len() == 0 {\n panic(\n f\"A partial note's completion log did not result in any notes being found - this should never happen\",\n );\n }\n\n aztecnr_debug_log_format!(\"Discovered {0} notes for partial note with tag {1}\")([\n discovered_notes.len() as Field,\n pending_partial_note.note_completion_log_tag,\n ]);\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n discovered_note.note_nonce,\n complete_packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n log.tx_hash,\n );\n });\n\n // Because there is only a single log for a given tag, once we've processed the tagged log then we simply\n // delete the pending work entry, regardless of whether it was actually completed or not.\n pending_partial_notes.remove(i);\n }\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr","function_locations":[{"start":1784,"name":"process_partial_note_private_msg"},{"start":3162,"name":"fetch_and_process_partial_note_completion_logs"}]},"129":{"source":"use crate::{\n event::event_interface::compute_private_serialized_event_commitment,\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::MAX_MESSAGE_CONTENT_LEN, logs::event::decode_private_event_message,\n processing::enqueue_event_for_validation,\n },\n};\nuse crate::protocol::{address::AztecAddress, traits::ToField};\n\npub(crate) unconstrained fn process_private_event_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n) {\n let decoded = decode_private_event_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (event_type_id, randomness, serialized_event) = decoded.unwrap();\n\n let event_commitment =\n compute_private_serialized_event_commitment(serialized_event, randomness, event_type_id.to_field());\n\n enqueue_event_for_validation(\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private event message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_events.nr","function_locations":[{"start":547,"name":"process_private_event_msg"}]},"130":{"source":"use crate::{\n logging::{aztecnr_debug_log_format, aztecnr_warn_log_format},\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::{decode_private_note_message, MAX_NOTE_PACKED_LEN},\n processing::enqueue_note_for_validation,\n },\n protocol::{address::AztecAddress, constants::MAX_NOTE_HASHES_PER_TX, traits::ToField},\n};\n\npub(crate) unconstrained fn process_private_note_msg(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n msg_metadata: u64,\n msg_content: BoundedVec,\n) {\n let decoded = decode_private_note_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (note_type_id, owner, storage_slot, randomness, packed_note) = decoded.unwrap();\n\n attempt_note_discovery(\n contract_address,\n tx_hash,\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private note message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Attempts discovery of a note given information about its contents and the transaction in which it is suspected the\n/// note was created.\npub unconstrained fn attempt_note_discovery(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) {\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n\n if discovered_notes.len() == 0 {\n // A private note message that results in no discovered notes means none of the computed note hashes matched\n // any unique note hash in the transaction. This could indicate a malformed or malicious message (e.g. a sender\n // providing bogus note content).\n aztecnr_warn_log_format!(\n \"Discarding private note message from tx {0} for contract {1}: no matching note hash found in the tx\",\n )(\n [tx_hash, contract_address.to_field()],\n );\n } else {\n aztecnr_debug_log_format!(\n \"Discovered {0} notes from a private message for contract {1}\",\n )(\n [discovered_notes.len() as Field, contract_address.to_field()],\n );\n }\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n owner,\n storage_slot,\n randomness,\n discovered_note.note_nonce,\n packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n tx_hash,\n );\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_notes.nr","function_locations":[{"start":861,"name":"process_private_note_msg"},{"start":2185,"name":"attempt_note_discovery"}]},"131":{"source":"use crate::messages::{\n discovery::{\n ComputeNoteHash, ComputeNoteNullifier, CustomMessageHandler, partial_notes::process_partial_note_private_msg,\n private_events::process_private_event_msg, private_notes::process_private_note_msg,\n },\n encoding::{decode_message, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN},\n encryption::{aes128::AES128, message_encryption::MessageEncryption},\n msg_type::{\n MIN_CUSTOM_MSG_TYPE_ID, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID, PRIVATE_EVENT_MSG_TYPE_ID, PRIVATE_NOTE_MSG_TYPE_ID,\n },\n processing::MessageContext,\n};\n\nuse crate::logging::{aztecnr_debug_log, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\n/// Processes a message that can contain notes, partial notes, or events.\n///\n/// Notes result in nonce discovery being performed prior to delivery, which requires knowledge of the transaction hash\n/// in which the notes would've been created (typically the same transaction in which the log was emitted), along with\n/// the list of unique note hashes in said transaction and the `compute_note_hash` and `compute_note_nullifier`\n/// functions. Once discovered, the notes are enqueued for validation.\n///\n/// Partial notes result in a pending partial note entry being stored in a PXE capsule, which will later be retrieved\n/// to search for the note's completion public log.\n///\n/// Events are processed by computing an event commitment from the serialized event data and its randomness field, then\n/// enqueueing the event data and commitment for validation.\npub unconstrained fn process_message_ciphertext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_ciphertext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n let message_plaintext_option = AES128::decrypt(message_ciphertext, recipient, contract_address);\n\n if message_plaintext_option.is_some() {\n process_message_plaintext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_plaintext_option.unwrap(),\n message_context,\n recipient,\n );\n } else {\n aztecnr_warn_log_format!(\"Could not decrypt message ciphertext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n\npub(crate) unconstrained fn process_message_plaintext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_plaintext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n // The first thing to do after decrypting the message is to determine what type of message we're processing. We\n // have 3 message types: private notes, partial notes and events.\n\n // We decode the message to obtain the message type id, metadata and content.\n let decoded = decode_message(message_plaintext);\n\n if decoded.is_some() {\n let (msg_type_id, msg_metadata, msg_content) = decoded.unwrap();\n\n if msg_type_id == PRIVATE_NOTE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private note msg\");\n\n process_private_note_msg(\n contract_address,\n message_context.tx_hash,\n message_context.unique_note_hashes_in_tx,\n message_context.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n msg_metadata,\n msg_content,\n );\n } else if msg_type_id == PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing partial note private msg\");\n\n process_partial_note_private_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n recipient,\n );\n } else if msg_type_id == PRIVATE_EVENT_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private event msg\");\n\n process_private_event_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n );\n } else if msg_type_id < MIN_CUSTOM_MSG_TYPE_ID {\n // The message type ID falls in the range reserved for aztec.nr built-in types but wasn't matched above.\n // This most likely means the message is malformed or a custom message was incorrectly assigned a reserved\n // ID. Custom message types must use IDs allocated via `custom_msg_type_id`.\n aztecnr_warn_log_format!(\n \"Message type ID {0} is in the reserved range but is not recognized, ignoring. See https://docs.aztec.network/errors/3\",\n )(\n [msg_type_id as Field],\n );\n } else if process_custom_message.is_some() {\n process_custom_message.unwrap()(\n contract_address,\n msg_type_id,\n msg_metadata,\n msg_content,\n message_context,\n recipient,\n );\n } else {\n // A custom message was received but no handler is configured. This likely means the contract emits custom\n // messages but forgot to register a handler via `AztecConfig::custom_message_handler`.\n aztecnr_warn_log_format!(\n \"Received custom message with type id {0} but no handler is configured, ignoring. See https://docs.aztec.network/errors/2\",\n )(\n [msg_type_id as Field],\n );\n }\n } else {\n aztecnr_warn_log_format!(\"Could not decode message plaintext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/process_message.nr","function_locations":[{"start":1975,"name":"process_message_ciphertext"},{"start":2968,"name":"process_message_plaintext"}]},"132":{"source":"// TODO(#12750): don't make these values assume we're using AES.\nuse crate::protocol::constants::PRIVATE_LOG_CIPHERTEXT_LEN;\nuse crate::utils::array;\n\n// We reassign to the constant here to communicate the distinction between a log and a message. In Aztec.nr, unlike in\n// protocol circuits, we have a concept of a message that can be emitted either as a private log or as an offchain\n// message. Message is a piece of data that is to be eventually delivered to a contract via the `process_message(...)`\n// utility function function that is injected by the #[aztec] macro. Note: PRIVATE_LOG_CIPHERTEXT_LEN is an amount of\n// fields, so MESSAGE_CIPHERTEXT_LEN is the size of the message in fields.\npub global MESSAGE_CIPHERTEXT_LEN: u32 = PRIVATE_LOG_CIPHERTEXT_LEN;\n\n// TODO(#12750): The global variables below should not be here as they are AES128 specific.\n// The header plaintext is 2 bytes (ciphertext length), padded to the 16-byte AES block size by PKCS#7.\npub(crate) global HEADER_CIPHERTEXT_SIZE_IN_BYTES: u32 = 16;\n// AES PKCS#7 always adds at least one byte of padding. Since each plaintext field is 32 bytes (a multiple of the\n// 16-byte AES block size), a full 16-byte padding block is always appended.\npub(crate) global AES128_PKCS7_EXPANSION_IN_BYTES: u32 = 16;\n\npub global EPH_PK_X_SIZE_IN_FIELDS: u32 = 1;\n\n// (15 - 1) * 31 - 16 - 16 = 402. Note: We multiply by 31 because ciphertext bytes are stored in fields using\n// encode_bytes_as_fields, which packs 31 bytes per field (since a Field is ~254 bits and can safely store 31 whole\n// bytes).\npub(crate) global MESSAGE_PLAINTEXT_SIZE_IN_BYTES: u32 = (MESSAGE_CIPHERTEXT_LEN - EPH_PK_X_SIZE_IN_FIELDS) * 31\n - HEADER_CIPHERTEXT_SIZE_IN_BYTES\n - AES128_PKCS7_EXPANSION_IN_BYTES;\n// The plaintext bytes represent Field values that were originally serialized using encode_fields_as_bytes, which\n// converts each Field to 32 bytes. To convert the plaintext bytes back to fields, we divide by 32. 402 / 32 = 12\npub global MESSAGE_PLAINTEXT_LEN: u32 = MESSAGE_PLAINTEXT_SIZE_IN_BYTES / 32;\n\npub global MESSAGE_EXPANDED_METADATA_LEN: u32 = 1;\n\n// The standard message layout is composed of:\n// - an initial field called the 'expanded metadata'\n// - an arbitrary number of fields following that called the 'message content'\n//\n// ```\n// message: [ msg_expanded_metadata, ...msg_content ]\n// ```\n//\n// The expanded metadata itself is interpreted as a u128, of which:\n// - the upper 64 bits are the message type id\n// - the lower 64 bits are called the 'message metadata'\n//\n// ```\n// msg_expanded_metadata: [ msg_type_id | msg_metadata ]\n// <--- 64 bits --->|<--- 64 bits --->\n// ```\n//\n// The meaning of the message metadata and message content depend on the value of the message type id. Note that there\n// is nothing special about the message metadata, it _can_ be considered part of the content. It just has a different\n// name to make it distinct from the message content given that it is not a full field.\n\n/// The maximum length of a message's content, i.e. not including the expanded message metadata.\npub global MAX_MESSAGE_CONTENT_LEN: u32 = MESSAGE_PLAINTEXT_LEN - MESSAGE_EXPANDED_METADATA_LEN;\n\n/// Encodes a message following aztec-nr's standard message encoding. This message can later be decoded with\n/// `decode_message` to retrieve the original values.\n///\n/// - The `msg_type` is an identifier that groups types of messages that are all processed the same way, e.g. private\n/// notes or events. Possible values are defined in `aztec::messages::msg_type`.\n/// - The `msg_metadata` and `msg_content` are the values stored in the message, whose meaning depends on the\n/// `msg_type`. The only special thing about `msg_metadata` that separates it from `msg_content` is that it is a u64\n/// instead of a full Field (due to details of how messages are encoded), allowing applications that can fit values\n/// into this smaller variable to achieve higher data efficiency.\npub fn encode_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; N],\n) -> [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] {\n std::static_assert(\n msg_content.len() <= MAX_MESSAGE_CONTENT_LEN,\n \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\",\n );\n\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n let mut message: [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] = std::mem::zeroed();\n\n message[0] = to_expanded_metadata(msg_type, msg_metadata);\n for i in 0..msg_content.len() {\n message[MESSAGE_EXPANDED_METADATA_LEN + i] = msg_content[i];\n }\n\n message\n}\n\n/// Decodes a standard aztec-nr message, i.e. one created via `encode_message`, returning the original encoded values.\n///\n/// Returns `None` if the message is empty or has invalid (>128 bit) expanded metadata.\n///\n/// Note that `encode_message` returns a fixed size array while this function takes a `BoundedVec`: this is because\n/// prior to decoding the message type is unknown, and consequentially not known at compile time. If working with\n/// fixed-size messages, consider using `BoundedVec::from_array` to convert them.\npub unconstrained fn decode_message(\n message: BoundedVec,\n) -> Option<(u64, u64, BoundedVec)> {\n Option::some(message)\n .and_then(|message| {\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring\n // of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n if message.len() < MESSAGE_EXPANDED_METADATA_LEN {\n Option::none()\n } else {\n Option::some(message.get(0))\n }\n })\n .and_then(|msg_expanded_metadata| from_expanded_metadata(msg_expanded_metadata))\n .map(|(msg_type_id, msg_metadata)| {\n let msg_content = array::subbvec(message, MESSAGE_EXPANDED_METADATA_LEN);\n (msg_type_id, msg_metadata, msg_content)\n })\n}\n\nglobal U64_SHIFT_MULTIPLIER: Field = 2.pow_32(64);\n\nfn to_expanded_metadata(msg_type: u64, msg_metadata: u64) -> Field {\n // We use multiplication instead of bit shifting operations to shift the type bits as bit shift operations are\n // expensive in circuits.\n let type_field: Field = (msg_type as Field) * U64_SHIFT_MULTIPLIER;\n let msg_metadata_field = msg_metadata as Field;\n\n type_field + msg_metadata_field\n}\n\nglobal TWO_POW_128: Field = 2.pow_32(128);\n\n/// Unpacks expanded metadata into (msg_type, msg_metadata). Returns `None` if `input >= 2^128`.\nfn from_expanded_metadata(input: Field) -> Option<(u64, u64)> {\n if input.lt(TWO_POW_128) {\n let msg_metadata = (input as u64);\n let msg_type = ((input - (msg_metadata as Field)) / U64_SHIFT_MULTIPLIER) as u64;\n // Use division instead of bit shift since bit shifts are expensive in circuits\n Option::some((msg_type, msg_metadata))\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray::subarray;\n use super::{\n decode_message, encode_message, from_expanded_metadata, MAX_MESSAGE_CONTENT_LEN, to_expanded_metadata,\n TWO_POW_128,\n };\n\n global U64_MAX: u64 = (2.pow_32(64) - 1) as u64;\n global U128_MAX: Field = (2.pow_32(128) - 1);\n\n #[test]\n unconstrained fn encode_decode_empty_message(msg_type: u64, msg_metadata: u64) {\n let encoded = encode_message(msg_type, msg_metadata, []);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), 0);\n }\n\n #[test]\n unconstrained fn encode_decode_short_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN / 2],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn encode_decode_full_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn to_expanded_metadata_packing() {\n // Test case 1: All bits set\n let packed = to_expanded_metadata(U64_MAX, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let packed = to_expanded_metadata(U64_MAX, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let packed = to_expanded_metadata(0, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let packed = to_expanded_metadata(0, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn from_expanded_metadata_packing() {\n // Test case 1: All bits set\n let input = U128_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let input = (U128_MAX - U64_MAX as Field);\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let input = U64_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let input = 0;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn to_from_expanded_metadata(original_msg_type: u64, original_msg_metadata: u64) {\n let packed = to_expanded_metadata(original_msg_type, original_msg_metadata);\n let (unpacked_msg_type, unpacked_msg_metadata) = from_expanded_metadata(packed).unwrap();\n\n assert_eq(original_msg_type, unpacked_msg_type);\n assert_eq(original_msg_metadata, unpacked_msg_metadata);\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_message() {\n let msg_type_id: u64 = 42;\n let msg_metadata: u64 = 99;\n let mut msg_content = [0; MAX_MESSAGE_CONTENT_LEN];\n for i in 0..MAX_MESSAGE_CONTENT_LEN {\n msg_content[i] = i as Field;\n }\n\n let encoded = encode_message(msg_type_id, msg_metadata, msg_content);\n let (decoded_type_id, decoded_metadata, decoded_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_type_id, msg_type_id);\n assert_eq(decoded_metadata, msg_metadata);\n assert_eq(decoded_content, BoundedVec::from_array(msg_content));\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_message_fails() {\n let msg_content = [0; MAX_MESSAGE_CONTENT_LEN + 1];\n let _ = encode_message(0, 0, msg_content);\n }\n\n #[test]\n unconstrained fn decode_empty_message_returns_none() {\n assert(decode_message(BoundedVec::new()).is_none());\n }\n\n #[test]\n unconstrained fn decode_message_with_oversized_metadata_returns_none() {\n let message = BoundedVec::from_array([TWO_POW_128]);\n assert(decode_message(message).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encoding.nr","function_locations":[{"start":4136,"name":"encode_message"},{"start":5594,"name":"decode_message"},{"start":6617,"name":"to_expanded_metadata"},{"start":7131,"name":"from_expanded_metadata"},{"start":7894,"name":"tests::encode_decode_empty_message"},{"start":8444,"name":"tests::encode_decode_short_message"},{"start":9090,"name":"tests::encode_decode_full_message"},{"start":9628,"name":"tests::to_expanded_metadata_packing"},{"start":10713,"name":"tests::from_expanded_metadata_packing"},{"start":11770,"name":"tests::to_from_expanded_metadata"},{"start":12151,"name":"tests::encode_decode_max_size_message"},{"start":12934,"name":"tests::encode_oversized_message_fails"},{"start":13123,"name":"tests::decode_empty_message_returns_none"},{"start":13280,"name":"tests::decode_message_with_oversized_metadata_returns_none"}]},"133":{"source":"use crate::protocol::{address::AztecAddress, public_keys::AddressPoint, traits::ToField};\n\nuse crate::{\n keys::{\n ecdh_shared_secret::{\n compute_app_siloed_shared_secret, derive_ecdh_shared_secret, derive_shared_secret_field_mask,\n derive_shared_secret_subkey,\n },\n ephemeral::generate_positive_ephemeral_key_pair,\n },\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::{\n EPH_PK_X_SIZE_IN_FIELDS, HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN,\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES,\n },\n encryption::message_encryption::MessageEncryption,\n logs::arithmetic_generics_utils::{\n get_arr_of_size__message_bytes__from_PT, get_arr_of_size__message_bytes_padding__from_PT,\n },\n },\n oracle::{aes128_decrypt::try_aes128_decrypt, random::random, shared_secret::get_shared_secret},\n utils::{\n array,\n conversion::{\n bytes_as_fields::{decode_bytes_from_fields, encode_bytes_as_fields},\n fields_as_bytes::{encode_fields_as_bytes, try_decode_fields_from_bytes},\n },\n point::point_from_x_coord_and_sign,\n },\n};\n\nuse std::aes128::aes128_encrypt;\n\n/// Computes N close-to-uniformly-random 256 bits from a given app-siloed shared secret.\n///\n/// NEVER re-use the same iv and sym_key. DO NOT call this function more than once with the same s_app.\n///\n/// This function is only known to be safe if s_app is derived from combining a random ephemeral key with an\n/// address point and a contract address. See big comment within the body of the function.\nfn extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app: Field) -> [[u8; 32]; N] {\n /*\n * Unsafe because of https://eprint.iacr.org/2010/264.pdf Page 13, Lemma 2 (and the two paragraphs below it).\n *\n * If you call this function, you need to be careful and aware of how the arg `s_app` has been derived.\n *\n * The paper says that the way you derive aes keys and IVs should be fine with poseidon2 (modelled as a RO),\n * as long as you _don't_ use Poseidon2 as a PRG to generate the two exponents x & y which multiply to the\n * shared secret S:\n *\n * S = [x*y]*G.\n *\n * (Otherwise, you would have to \"key\" poseidon2, i.e. generate a uniformly string K which can be public and\n * compute Hash(x) as poseidon(K,x)).\n * In that lemma, k would be 2*254=508, and m would be the number of points on the grumpkin curve (which is\n * close to r according to the Hasse bound).\n *\n * Our shared secret S is [esk * address_sk] * G, and the question is: Can we compute hash(S) using poseidon2\n * instead of sha256?\n *\n * Well, esk is random and not generated with poseidon2, so that's good.\n * What about address_sk?\n * Well, address_sk = poseidon2(stuff) + ivsk, so there was some discussion about whether address_sk is\n * independent of poseidon2. Given that ivsk is random and independent of poseidon2, the address_sk is also\n * independent of poseidon2.\n *\n * Tl;dr: we believe it's safe to hash S = [esk * address_sk] * G using poseidon2, in order to derive a\n * symmetric key.\n *\n * If you're calling this function for a differently-derived `s_app`, be careful.\n */\n \n\n /* The output of this function needs to be 32 random bytes.\n * A single field won't give us 32 bytes of entropy. So we compute two \"random\" fields, by poseidon-hashing\n * with two different indices. We then extract the last 16 (big endian) bytes of each \"random\" field.\n * Note: we use to_be_bytes because it's slightly more efficient. But we have to be careful not to take bytes\n * from the \"big end\", because the \"big\" byte is not uniformly random over the byte: it only has < 6 bits of\n * randomness, because it's the big end of a 254-bit field element.\n */\n\n let mut all_bytes: [[u8; 32]; N] = std::mem::zeroed();\n std::static_assert(N < 256, \"N too large\");\n for k in 0..N {\n let rand1: Field = derive_shared_secret_subkey(s_app, 2 * k);\n let rand2: Field = derive_shared_secret_subkey(s_app, 2 * k + 1);\n\n let rand1_bytes: [u8; 32] = rand1.to_be_bytes();\n let rand2_bytes: [u8; 32] = rand2.to_be_bytes();\n\n let mut bytes: [u8; 32] = [0; 32];\n for i in 0..16 {\n // We take bytes from the \"little end\" of the be-bytes arrays:\n let j = 32 - i - 1;\n bytes[i] = rand1_bytes[j];\n bytes[16 + i] = rand2_bytes[j];\n }\n\n all_bytes[k] = bytes;\n }\n\n all_bytes\n}\n\nfn derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(\n many_random_256_bits: [[u8; 32]; N],\n) -> [([u8; 16], [u8; 16]); N] {\n // Many (sym_key, iv) pairs:\n let mut many_pairs: [([u8; 16], [u8; 16]); N] = std::mem::zeroed();\n for k in 0..N {\n let random_256_bits = many_random_256_bits[k];\n let mut sym_key = [0; 16];\n let mut iv = [0; 16];\n for i in 0..16 {\n sym_key[i] = random_256_bits[i];\n iv[i] = random_256_bits[i + 16];\n }\n many_pairs[k] = (sym_key, iv);\n }\n\n many_pairs\n}\n\npub fn derive_aes_symmetric_key_and_iv_from_shared_secret(s_app: Field) -> [([u8; 16], [u8; 16]); N] {\n let many_random_256_bits: [[u8; 32]; N] = extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app);\n\n derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(many_random_256_bits)\n}\n\npub struct AES128 {}\n\nimpl MessageEncryption for AES128 {\n\n /// AES128-CBC encryption for Aztec protocol messages.\n ///\n /// ## Overview\n ///\n /// The plaintext is an array of up to `MESSAGE_PLAINTEXT_LEN` (12) fields. The output is always exactly\n /// `MESSAGE_CIPHERTEXT_LEN` (15) fields, regardless of plaintext size. All output fields except the\n /// ephemeral public key are uniformly random `Field` values to any observer without knowledge of the\n /// shared secret, making all encrypted messages indistinguishable by size or content.\n ///\n /// ## PKCS#7 Padding\n ///\n /// AES operates on 16-byte blocks, so the plaintext must be padded to a multiple of 16. PKCS#7 padding always\n /// adds at least 1 byte (so the receiver can always detect and strip it), which means:\n /// - 1 B plaintext -> 15 B padding -> 16 B total\n /// - 15 B plaintext -> 1 B padding -> 16 B total\n /// - 16 B plaintext -> 16 B padding -> 32 B total (full extra block)\n ///\n /// In general: if the plaintext is already a multiple of 16, a full 16-byte padding block is appended.\n ///\n /// ## Encryption Steps\n ///\n /// **1. Body encryption.** The plaintext fields are serialized to bytes (32 bytes per field) and AES-128-CBC\n /// encrypted. Since 32 is a multiple of 16, PKCS#7 always adds a full 16-byte padding block (see above):\n ///\n /// ```text\n /// +---------------------------------------------+\n /// | body ct |\n /// | PlaintextLen*32 + 16 B |\n /// +-------------------------------+--------------+\n /// | encrypted plaintext fields | PKCS#7 (16B) |\n /// | (serialized at 32 B each) | |\n /// +-------------------------------+--------------+\n /// ```\n ///\n /// **2. Header encryption.** The byte length of `body_ct` is stored as a 2-byte big-endian integer. This 2-byte\n /// header plaintext is then AES-encrypted; PKCS#7 pads the remaining 14 bytes to fill one 16-byte AES block,\n /// producing a 16-byte header ciphertext:\n ///\n /// ```text\n /// +---------------------------+\n /// | header ct |\n /// | 16 B |\n /// +--------+------------------+\n /// | body ct| PKCS#7 (14B) |\n /// | length | |\n /// | (2 B) | |\n /// +--------+------------------+\n /// ```\n ///\n /// ## Wire Format\n ///\n /// Messages are transmitted as fields, not bytes. A field is ~254 bits and can safely store 31 whole bytes, so\n /// we need to pack our byte data into 31-byte chunks. This packing drives the wire format.\n ///\n /// **Step 1 -- Assemble bytes.** The ciphertexts are laid out in a byte array, padded with zero bytes to a\n /// multiple of 31 so it divides evenly into fields:\n ///\n /// ```text\n /// +------------+-------------------------+---------+\n /// | header ct | body ct | byte pad|\n /// | 16 B | PlaintextLen*32 + 16 B | (zeros) |\n /// +------------+-------------------------+---------+\n /// |<-------- padded to a multiple of 31 B -------->|\n /// ```\n ///\n /// **Step 2 -- Pack and mask.** The byte array is split into 31-byte chunks, each stored in one field. A\n /// Poseidon2-derived mask (see `derive_shared_secret_field_mask`) is added to each so that the resulting\n /// fields appear as uniformly random `Field` values to any observer without knowledge of the shared secret,\n /// hiding the fact that the underlying ciphertext consists of 128-bit AES blocks.\n ///\n /// **Step 3 -- Assemble ciphertext.** The ephemeral public key x-coordinate is prepended and random field padding\n /// is appended to fill to 15 fields:\n ///\n /// ```text\n /// +----------+-------------------------+-------------------+\n /// | eph_pk.x | masked message fields | random field pad |\n /// | | (packed 31 B per field) | (fills to 15) |\n /// +----------+-------------------------+-------------------+\n /// |<---------- MESSAGE_CIPHERTEXT_LEN = 15 fields -------->|\n /// ```\n ///\n /// ## Key Derivation\n ///\n /// The raw ECDH shared secret point is first app-siloed into a scalar `s_app` by hashing with the contract\n /// address (see\n /// [`compute_app_siloed_shared_secret`](crate::keys::ecdh_shared_secret::compute_app_siloed_shared_secret)).\n /// Two (key, IV) pairs are then derived from `s_app` via indexed Poseidon2 hashing: one pair for the body\n /// ciphertext and one for the header ciphertext.\n fn encrypt(\n plaintext: [Field; PlaintextLen],\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> [Field; MESSAGE_CIPHERTEXT_LEN] {\n std::static_assert(\n PlaintextLen <= MESSAGE_PLAINTEXT_LEN,\n \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\",\n );\n\n // AES 128 operates on bytes, not fields, so we need to convert the fields to bytes. (This process is then\n // reversed when processing the message in `process_message_ciphertext`)\n let plaintext_bytes = encode_fields_as_bytes(plaintext);\n\n // Derive ECDH shared secret with recipient using a fresh ephemeral keypair.\n let (eph_sk, eph_pk) = generate_positive_ephemeral_key_pair();\n\n let raw_shared_secret = derive_ecdh_shared_secret(\n eph_sk,\n recipient\n .to_address_point()\n .unwrap_or_else(|| {\n aztecnr_warn_log_format!(\n \"Attempted to encrypt message for an invalid recipient ({0})\",\n )(\n [recipient.to_field()],\n );\n\n // Safety: if the recipient is an invalid address, then it is not possible to encrypt a message for\n // them because we cannot establish a shared secret. This is never expected to occur during normal\n // operation. However, it is technically possible for us to receive an invalid address, and we must\n // therefore handle it. We could simply fail, but that'd introduce a potential security issue in\n // which an attacker forces a contract to encrypt a message for an invalid address, resulting in an\n // impossible transaction - this is sometimes called a 'king of the hill' attack. We choose instead\n // to not fail and encrypt the plaintext regardless using the shared secret that results from a\n // random valid address. The sender is free to choose this address and hence shared secret, but\n // this has no security implications as they already know not only the full plaintext but also the\n // ephemeral private key anyway.\n unsafe {\n random_address_point()\n }\n })\n .inner,\n );\n\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n // It is safe to derive AES keys from `s_app` using Poseidon2 because `s_app` was derived from an ECDH shared\n // secret using an AztecAddress (the recipient). See the block comment in\n // `extract_many_close_to_uniformly_random_256_bits_using_poseidon2` for more info.\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n let ciphertext_bytes = aes128_encrypt(plaintext_bytes, body_iv, body_sym_key);\n\n // Each plaintext field is 32 bytes (a multiple of the 16-byte AES block\n // size), so PKCS#7 always appends a full 16-byte padding block:\n // |ciphertext| = PlaintextLen*32 + 16 = 16 * (1 + PlaintextLen*32 / 16)\n std::static_assert(\n ciphertext_bytes.len() == 16 * (1 + (PlaintextLen * 32) / 16),\n \"unexpected ciphertext length\",\n );\n\n // Encrypt a 2-byte header containing the body ciphertext length.\n let header_plaintext = encode_header(ciphertext_bytes.len());\n\n // Note: the aes128_encrypt builtin fn automatically appends bytes to the input, according to pkcs#7; hence why\n // the output `header_ciphertext_bytes` is 16 bytes larger than the input in this case.\n let header_ciphertext_bytes = aes128_encrypt(header_plaintext, header_iv, header_sym_key);\n // Verify expected header ciphertext size at compile time.\n std::static_assert(\n header_ciphertext_bytes.len() == HEADER_CIPHERTEXT_SIZE_IN_BYTES,\n \"unexpected ciphertext header length\",\n );\n\n // Assemble the message byte array:\n // [header_ct (16B)] [body_ct] [padding to mult of 31]\n let message_bytes_padding_to_mult_31 = get_arr_of_size__message_bytes_padding__from_PT::();\n\n let mut message_bytes = get_arr_of_size__message_bytes__from_PT::();\n\n std::static_assert(\n message_bytes.len() % 31 == 0,\n \"Unexpected error: message_bytes.len() should be divisible by 31, by construction.\",\n );\n\n let mut offset = 0;\n for i in 0..header_ciphertext_bytes.len() {\n message_bytes[offset + i] = header_ciphertext_bytes[i];\n }\n offset += header_ciphertext_bytes.len();\n\n for i in 0..ciphertext_bytes.len() {\n message_bytes[offset + i] = ciphertext_bytes[i];\n }\n offset += ciphertext_bytes.len();\n\n for i in 0..message_bytes_padding_to_mult_31.len() {\n message_bytes[offset + i] = message_bytes_padding_to_mult_31[i];\n }\n offset += message_bytes_padding_to_mult_31.len();\n\n // Ideally we would be able to have a static assert where we check that the offset would be such that we've\n // written to the entire log_bytes array, but we cannot since Noir does not treat the offset as a comptime\n // value (despite the values that it goes through being known at each stage). We instead check that the\n // computation used to obtain the offset computes the expected value (which we _can_ do in a static check), and\n // then add a cheap runtime check to also validate that the offset matches this.\n std::static_assert(\n header_ciphertext_bytes.len() + ciphertext_bytes.len() + message_bytes_padding_to_mult_31.len()\n == message_bytes.len(),\n \"unexpected message length\",\n );\n assert(offset == message_bytes.len(), \"unexpected encrypted message length\");\n\n // Pack message bytes into fields (31 bytes per field) and prepend eph_pk.x.\n let message_bytes_as_fields = encode_bytes_as_fields(message_bytes);\n\n let mut ciphertext: [Field; MESSAGE_CIPHERTEXT_LEN] = [0; MESSAGE_CIPHERTEXT_LEN];\n\n ciphertext[0] = eph_pk.x;\n\n // Mask each content field with a Poseidon2-derived value, so that they appear as uniformly random `Field`\n // values\n let mut offset = 1;\n for i in 0..message_bytes_as_fields.len() {\n let mask = derive_shared_secret_field_mask(s_app, i as u32);\n ciphertext[offset + i] = message_bytes_as_fields[i] + mask;\n }\n offset += message_bytes_as_fields.len();\n\n // Pad with random fields so that padding is indistinguishable from masked data fields.\n for i in offset..MESSAGE_CIPHERTEXT_LEN {\n // Safety: we assume that the sender wants for the message to be private - a malicious one could simply\n // reveal its contents publicly. It is therefore fine to trust the sender to provide random padding.\n ciphertext[i] = unsafe { random() };\n }\n\n ciphertext\n }\n\n unconstrained fn decrypt(\n ciphertext: BoundedVec,\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> Option> {\n // Extract the ephemeral public key x-coordinate and masked fields, returning None for empty ciphertext.\n if ciphertext.len() > 0 {\n let masked_fields: BoundedVec =\n array::subbvec(ciphertext, EPH_PK_X_SIZE_IN_FIELDS);\n Option::some((ciphertext.get(0), masked_fields))\n } else {\n Option::none()\n }\n .and_then(|(eph_pk_x, masked_fields)| {\n // With the x-coordinate of the ephemeral public key we can reconstruct the point as we know that the\n // y-coordinate must be positive. This may fail however, as not all x-coordinates are on the curve. In\n // that case, we simply return `Option::none`.\n point_from_x_coord_and_sign(eph_pk_x, true).and_then(|eph_pk| {\n let s_app = get_shared_secret(recipient, eph_pk, contract_address);\n\n let unmasked_fields = masked_fields.mapi(|i, field| {\n let unmasked = unmask_field(s_app, i, field);\n // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it\n // later, so we can simply set it to 0\n unmasked.unwrap_or(0)\n });\n let ciphertext_without_eph_pk_x = decode_bytes_from_fields(unmasked_fields);\n\n // Derive symmetric keys:\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n // Extract the header ciphertext\n let header_start = 0;\n let header_ciphertext: [u8; HEADER_CIPHERTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), header_start);\n // We need to convert the array to a BoundedVec because the oracle expects a BoundedVec as it's\n // designed to work with messages with unknown length at compile time. This would not be necessary\n // here as the header ciphertext length is fixed. But we do it anyway to not have to have duplicate\n // oracles.\n let header_ciphertext_bvec =\n BoundedVec::::from_array(header_ciphertext);\n\n try_aes128_decrypt(header_ciphertext_bvec, header_iv, header_sym_key)\n // Extract ciphertext length from header (2 bytes, big-endian)\n .and_then(|header_plaintext| extract_ciphertext_length(header_plaintext))\n .filter(|ciphertext_length| ciphertext_length <= MESSAGE_PLAINTEXT_SIZE_IN_BYTES)\n .map(|ciphertext_length| {\n // Extract and decrypt main ciphertext\n let ciphertext_start = header_start + HEADER_CIPHERTEXT_SIZE_IN_BYTES;\n let ciphertext_with_padding: [u8; MESSAGE_PLAINTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), ciphertext_start);\n BoundedVec::from_parts(ciphertext_with_padding, ciphertext_length)\n })\n // Decrypt main ciphertext and return it\n .and_then(|ciphertext| try_aes128_decrypt(ciphertext, body_iv, body_sym_key))\n // Convert bytes back to fields (32 bytes per field). Returns None if the actual bytes are\n // not valid.\n .and_then(|plaintext_bytes| try_decode_fields_from_bytes(plaintext_bytes))\n })\n })\n }\n}\n\n/// Encodes the body ciphertext length into a 2-byte big-endian header.\nfn encode_header(ciphertext_length: u32) -> [u8; 2] {\n [(ciphertext_length >> 8) as u8, ciphertext_length as u8]\n}\n\n/// Extracts the body ciphertext length from a decrypted header as a 2-byte big-endian integer.\n///\n/// Returns `Option::none()` if the header has fewer than 2 bytes.\nunconstrained fn extract_ciphertext_length(header: BoundedVec) -> Option {\n if header.len() >= 2 {\n Option::some(((header.get(0) as u32) << 8) | (header.get(1) as u32))\n } else {\n Option::none()\n }\n}\n\n/// 2^248: upper bound for values that fit in 31 bytes\nglobal TWO_POW_248: Field = 2.pow_32(248);\n\n/// Removes the Poseidon2-derived mask from a ciphertext field. Returns the unmasked value if it fits in 31 bytes\n/// (a content field), or `None` if it doesn't (random padding). Unconstrained to prevent accidental use in\n/// constrained context.\nunconstrained fn unmask_field(s_app: Field, index: u32, masked: Field) -> Option {\n let unmasked = masked - derive_shared_secret_field_mask(s_app, index);\n if unmasked.lt(TWO_POW_248) {\n Option::some(unmasked)\n } else {\n Option::none()\n }\n}\n\n/// Produces a random valid address point, i.e. one that is on the curve. This is equivalent to calling\n/// [`AztecAddress::to_address_point`] on a random valid address.\nunconstrained fn random_address_point() -> AddressPoint {\n let mut result = std::mem::zeroed();\n\n loop {\n // We simply produce random x coordinates until we find one that is on the curve. About half of the x\n // coordinates fulfill this condition, so this should only take a few iterations at most.\n let x_coord = random();\n let point = point_from_x_coord_and_sign(x_coord, true);\n if point.is_some() {\n result = AddressPoint { inner: point.unwrap() };\n break;\n }\n }\n\n result\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::{compute_app_siloed_shared_secret, derive_ecdh_shared_secret},\n messages::{\n encoding::{HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_PLAINTEXT_LEN, MESSAGE_PLAINTEXT_SIZE_IN_BYTES},\n encryption::message_encryption::MessageEncryption,\n },\n test::helpers::test_environment::TestEnvironment,\n };\n use crate::protocol::{address::AztecAddress, traits::FromField};\n use super::{AES128, encode_header, random_address_point};\n use std::{embedded_curve_ops::EmbeddedCurveScalar, test::OracleMock};\n\n #[test]\n unconstrained fn encrypt_decrypt_deterministic() {\n let env = TestEnvironment::new();\n\n // Message decryption requires oracles that are only available during private execution\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n\n let recipient = AztecAddress::from_field(\n 0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70c,\n );\n\n // Mock random values for deterministic test\n let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(eph_sk).times(1);\n\n let randomness = 0x0101010101010101010101010101010101010101010101010101010101010101;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(randomness).times(1000000);\n\n let _ = OracleMock::mock(\"aztec_prv_getNextAppTagAsSender\").returns(42);\n\n // Encrypt the message\n let encrypted_message = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n // Compute the same app-siloed shared secret that the oracle would return\n let raw_shared_secret = derive_ecdh_shared_secret(\n EmbeddedCurveScalar::from_field(eph_sk),\n recipient.to_address_point().unwrap().inner,\n );\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n let _ = OracleMock::mock(\"aztec_utl_getSharedSecret\").returns(s_app);\n\n // Decrypt the message\n let decrypted = AES128::decrypt(encrypted_message, recipient, contract_address).unwrap();\n\n // The decryption function spits out a BoundedVec because it's designed to work with messages with unknown\n // length at compile time. For this reason we need to convert the original input to a BoundedVec.\n let plaintext_bvec = BoundedVec::::from_array(plaintext);\n\n // Verify decryption matches original plaintext\n assert_eq(decrypted, plaintext_bvec, \"Decrypted bytes should match original plaintext\");\n\n // The following is a workaround of \"struct is never constructed\" Noir compilation error (we only ever use\n // static methods of the struct).\n let _ = AES128 {};\n });\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_random() {\n // Same as `encrypt_decrypt_deterministic`, except we don't mock any of the oracles and rely on\n // `TestEnvironment` instead.\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test]\n unconstrained fn encrypt_to_invalid_address() {\n // x = 3 is a non-residue for this curve, resulting in an invalid address\n let invalid_address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n\n let _ = AES128::encrypt([1, 2, 3, 4], invalid_address, contract_address);\n }\n\n // Documents the PKCS#7 padding behavior that `encrypt` relies on (see its static_assert).\n #[test]\n fn pkcs7_padding_always_adds_at_least_one_byte() {\n let key = [0 as u8; 16];\n let iv = [0 as u8; 16];\n\n // 1 byte input + 15 bytes padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 1], iv, key).len(), 16);\n\n // 15 bytes input + 1 byte padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 15], iv, key).len(), 16);\n\n // 16 bytes input (block-aligned) + full 16-byte padding block = 32 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 16], iv, key).len(), 32);\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_max_size_plaintext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let mut plaintext = [0; MESSAGE_PLAINTEXT_LEN];\n for i in 0..MESSAGE_PLAINTEXT_LEN {\n plaintext[i] = i as Field;\n }\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test(should_fail_with = \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\")]\n unconstrained fn encrypt_oversized_plaintext() {\n let address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n let plaintext: [Field; MESSAGE_PLAINTEXT_LEN + 1] = [0; MESSAGE_PLAINTEXT_LEN + 1];\n let _ = AES128::encrypt(plaintext, address, contract_address);\n }\n\n #[test]\n unconstrained fn random_address_point_produces_valid_points() {\n // About half of random addresses are invalid, so testing just a couple gives us high confidence that\n // `random_address_point` is indeed producing valid addresses.\n for _ in 0..10 {\n let random_address = AztecAddress { inner: random_address_point().inner.x };\n assert(random_address.to_address_point().is_some());\n }\n }\n\n #[test]\n unconstrained fn decrypt_invalid_ephemeral_public_key() {\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3, 4];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n // The first field of the ciphertext is the x-coordinate of the ephemeral public key. We set it to a known\n // non-residue (3), causing `decrypt` to fail to produce a decryption shared secret.\n let mut bad_ciphertext = BoundedVec::from_array(ciphertext);\n bad_ciphertext.set(0, 3);\n\n assert(AES128::decrypt(bad_ciphertext, recipient, contract_address).is_none());\n });\n }\n\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_ciphertext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n assert(AES128::decrypt(BoundedVec::new(), recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header AES decrypt oracle to return an empty result. The TS oracle never throws on invalid\n // input: it decrypts to garbage bytes or returns empty\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_header() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let empty_header = BoundedVec::::new();\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(empty_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header oracle to return a 2-byte header that decodes to a ciphertext_length one past the maximum\n // allowed value, verifying the edge case is handled correctly.\n #[test]\n unconstrained fn decrypt_returns_none_on_oversized_ciphertext_length() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let bad_header = BoundedVec::::from_array(encode_header(\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES + 1,\n ));\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(bad_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr","function_locations":[{"start":1764,"name":"extract_many_close_to_uniformly_random_256_bits_using_poseidon2"},{"start":4783,"name":"derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits"},{"start":5332,"name":"derive_aes_symmetric_key_and_iv_from_shared_secret"},{"start":10365,"name":"::encrypt"},{"start":17702,"name":"::decrypt"},{"start":21732,"name":"encode_header"},{"start":22063,"name":"extract_ciphertext_length"},{"start":22648,"name":"unmask_field"},{"start":23061,"name":"random_address_point"},{"start":24228,"name":"test::encrypt_decrypt_deterministic"},{"start":26706,"name":"test::encrypt_decrypt_random"},{"start":27552,"name":"test::encrypt_to_invalid_address"},{"start":28002,"name":"test::pkcs7_padding_always_adds_at_least_one_byte"},{"start":28566,"name":"test::encrypt_decrypt_max_size_plaintext"},{"start":29465,"name":"test::encrypt_oversized_plaintext"},{"start":29823,"name":"test::random_address_point_produces_valid_points"},{"start":30274,"name":"test::decrypt_invalid_ephemeral_public_key"},{"start":31119,"name":"test::decrypt_returns_none_on_empty_ciphertext"},{"start":31673,"name":"test::decrypt_returns_none_on_empty_header"},{"start":32599,"name":"test::decrypt_returns_none_on_oversized_ciphertext_length"}]},"138":{"source":"use crate::{\n event::{event_interface::EventInterface, EventSelector},\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n utils::array,\n};\nuse crate::protocol::traits::{FromField, Serialize, ToField};\n\n/// The number of fields in a private event message content that are not the event's serialized representation (1 field\n/// for randomness).\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 1;\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 0;\n\n/// The maximum length of the packed representation of an event's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, randomness, etc.).\npub global MAX_EVENT_SERIALIZED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_event_message`].\npub fn encode_private_event_message(\n event: Event,\n randomness: Field,\n) -> [Field; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Event: EventInterface + Serialize,\n{\n std::static_assert(\n ::N <= MAX_EVENT_SERIALIZED_LEN,\n \"event's serialized length exceeds the maximum allowed for private events\",\n );\n\n // We use `Serialize` because we want for events to be processable by off-chain actors, e.g. block explorers,\n // wallets and apps, without having to rely on contract invocation. If we used `Packable` we'd need to call utility\n // functions in order to unpack events, which would introduce a level of complexity we don't currently think is\n // worth the savings in DA (for public events) and proving time (when encrypting private event messages).\n let serialized_event = event.serialize();\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_plaintext = [0; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n\n for i in 0..serialized_event.len() {\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = serialized_event[i];\n }\n\n // The event type id is stored in the message metadata\n encode_message(\n PRIVATE_EVENT_MSG_TYPE_ID,\n Event::get_event_type_id().to_field() as u64,\n msg_plaintext,\n )\n}\n\n/// Decodes the plaintext from a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_event_message`].\n///\n/// Note that while [`encode_private_event_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_event_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(EventSelector, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let event_type_id = EventSelector::from_field(msg_metadata as Field);\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // destructuring of the private event message encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let randomness = msg_content.get(PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let serialized_event = array::subbvec(msg_content, PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((event_type_id, randomness, serialized_event))\n }\n}\n\nmod test {\n use crate::{\n event::event_interface::EventInterface,\n messages::{\n encoding::decode_message,\n logs::event::{decode_private_event_message, encode_private_event_message},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n };\n use crate::protocol::traits::Serialize;\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let event = MockEvent::new(VALUE).build_event();\n\n let message_plaintext = encode_private_event_message(event, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_EVENT_MSG_TYPE_ID);\n\n let (event_type_id, randomness, serialized_event) =\n decode_private_event_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(event_type_id, MockEvent::get_event_type_id());\n assert_eq(randomness, RANDOMNESS);\n assert_eq(serialized_event, BoundedVec::from_array(event.serialize()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_event_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0]);\n assert(decode_private_event_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/event.nr","function_locations":[{"start":1377,"name":"encode_private_event_message"},{"start":3755,"name":"decode_private_event_message"},{"start":5127,"name":"test::encode_decode"},{"start":5869,"name":"test::decode_empty_content_returns_none"},{"start":6064,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"140":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\n\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX: u32 = 1;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 2;\n\n/// The maximum length of the packed representation of a note's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, storage slot, randomness, etc.).\npub global MAX_NOTE_PACKED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_note_message`].\npub fn encode_private_note_message(\n note: Note,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n) -> [Field; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Note: NoteType + Packable,\n{\n let packed_note = note.pack();\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_content = [0; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX] = storage_slot;\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n for i in 0..packed_note.len() {\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_note[i];\n }\n\n // Notes use the note type id for metadata\n encode_message(PRIVATE_NOTE_MSG_TYPE_ID, Note::get_id() as u64, msg_content)\n}\n\n/// Decodes the plaintext from a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_note_message`].\n///\n/// Note that while [`encode_private_note_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_note_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(Field, AztecAddress, Field, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // decoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let owner = AztecAddress::from_field(msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX));\n let storage_slot = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX);\n let randomness = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let packed_note = array::subbvec(msg_content, PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((note_type_id, owner, storage_slot, randomness, packed_note))\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::note::{decode_private_note_message, encode_private_note_message, MAX_NOTE_PACKED_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global STORAGE_SLOT: Field = 9;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[derive(Packable)]\n struct MaxSizeNote {\n data: [Field; MAX_NOTE_PACKED_LEN],\n }\n\n impl NoteType for MaxSizeNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_note() {\n let mut data = [0; MAX_NOTE_PACKED_LEN];\n for i in 0..MAX_NOTE_PACKED_LEN {\n data[i] = i as Field;\n }\n let note = MaxSizeNote { data };\n\n let encoded = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n let (msg_type_id, msg_metadata, msg_content) = decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MaxSizeNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(data));\n }\n\n #[derive(Packable)]\n struct OversizedNote {\n data: [Field; MAX_NOTE_PACKED_LEN + 1],\n }\n\n impl NoteType for OversizedNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_note_fails() {\n let note = OversizedNote { data: [0; MAX_NOTE_PACKED_LEN + 1] };\n let _ = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_note_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0, 0, 0]);\n assert(decode_private_note_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/note.nr","function_locations":[{"start":1518,"name":"encode_private_note_message"},{"start":3312,"name":"decode_private_note_message"},{"start":5000,"name":"test::encode_decode"},{"start":5923,"name":"test::::get_id"},{"start":6019,"name":"test::encode_decode_max_size_note"},{"start":7035,"name":"test::::get_id"},{"start":7221,"name":"test::encode_oversized_note_fails"},{"start":7456,"name":"test::decode_empty_content_returns_none"},{"start":7650,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"141":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 1;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX: u32 = 2;\n\n/// Partial notes have a maximum packed length of their private fields bound by extra content in their private message\n/// (e.g. the storage slot, note completion log tag, etc.).\npub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 =\n MAX_MESSAGE_CONTENT_LEN - PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a partial note private message (i.e. one of type [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_partial_note_private_message`].\npub fn encode_partial_note_private_message(\n partial_note_private_content: PartialNotePrivateContent,\n owner: AztecAddress,\n randomness: Field,\n note_completion_log_tag: Field,\n ) -> [Field; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n PartialNotePrivateContent: NoteType + Packable,\n{\n let packed_private_content = partial_note_private_content.pack();\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail, then\n // the encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n let mut msg_content =\n [0; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX] = note_completion_log_tag;\n\n for i in 0..packed_private_content.len() {\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_private_content[i];\n }\n\n encode_message(\n PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n // Notes use the note type id for metadata\n PartialNotePrivateContent::get_id() as u64,\n msg_content,\n )\n}\n\n/// Decodes the plaintext from a partial note private message (i.e. one of type\n/// [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_partial_note_private_message`].\n///\n/// Note that while [`encode_partial_note_private_message`] returns a fixed-size array, this function takes a\n/// [`BoundedVec`] instead. This is because when decoding we're typically processing runtime-sized plaintexts, more\n/// specifically, those that originate from\n/// [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_partial_note_private_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(AztecAddress, Field, Field, Field, BoundedVec)> {\n if msg_content.len() < PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id: Field = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail,\n // then the destructuring of the partial note private message encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n // We currently have three fields that are not the partial note's packed representation, which are the owner,\n // the randomness, and the note completion log tag.\n let owner = AztecAddress::from_field(\n msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX),\n );\n let randomness = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let note_completion_log_tag = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX);\n\n let packed_private_note_content: BoundedVec = array::subbvec(\n msg_content,\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN,\n );\n\n Option::some(\n (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content),\n )\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::partial_note::{decode_partial_note_private_message, encode_partial_note_private_message},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global RANDOMNESS: Field = 10;\n global NOTE_COMPLETION_LOG_TAG: Field = 11;\n\n #[test]\n unconstrained fn encode_decode() {\n // Note that here we use MockNote as the private fields of a partial note\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_partial_note_private_message(note, OWNER, RANDOMNESS, NOTE_COMPLETION_LOG_TAG);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID);\n\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_note) =\n decode_partial_note_private_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(note_completion_log_tag, NOTE_COMPLETION_LOG_TAG);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_partial_note_private_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_succeeds_with_only_reserved_fields() {\n let content = BoundedVec::from_array([0, 0, 0]);\n let (_, _, _, _, packed_note) = decode_partial_note_private_message(0, content).unwrap();\n assert_eq(packed_note.len(), 0);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/partial_note.nr","function_locations":[{"start":1715,"name":"encode_partial_note_private_message"},{"start":3810,"name":"decode_partial_note_private_message"},{"start":6022,"name":"test::encode_decode"},{"start":6999,"name":"test::decode_empty_content_returns_none"},{"start":7197,"name":"test::decode_succeeds_with_only_reserved_fields"}]},"151":{"source":"pub(crate) mod event_validation_request;\npub mod offchain;\n\nmod message_context;\npub use message_context::MessageContext;\n\npub(crate) mod note_validation_request;\npub(crate) mod log_retrieval_request;\npub(crate) mod log_retrieval_response;\npub(crate) mod pending_tagged_log;\n\nuse crate::{\n capsules::CapsuleArray,\n ephemeral::EphemeralArray,\n event::EventSelector,\n messages::{\n discovery::partial_notes::DeliveredPendingPartialNote,\n encoding::MESSAGE_CIPHERTEXT_LEN,\n logs::{event::MAX_EVENT_SERIALIZED_LEN, note::MAX_NOTE_PACKED_LEN},\n processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse,\n note_validation_request::NoteValidationRequest,\n },\n },\n oracle::message_processing,\n};\nuse crate::protocol::{\n address::AztecAddress,\n constants::DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n hash::{compute_log_tag, sha256_to_field},\n traits::{Deserialize, Serialize},\n};\nuse event_validation_request::EventValidationRequest;\n\nglobal NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\n/// An offchain-delivered message with resolved context, ready for processing during sync.\n#[derive(Serialize, Deserialize)]\npub struct OffchainMessageWithContext {\n pub message_ciphertext: BoundedVec,\n pub message_context: MessageContext,\n}\n\n/// Enqueues a note for validation and storage by PXE.\n///\n/// Once validated, the note becomes retrievable via the `get_notes` oracle. The note will be scoped to\n/// `contract_address`, meaning other contracts will not be able to access it unless authorized.\n///\n/// In order for the note validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many note validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// The `packed_note` is what `getNotes` will later return. PXE indexes notes by `storage_slot`, so this value is\n/// typically used to filter notes that correspond to different state variables. `note_hash` and `nullifier` are the\n/// inner hashes, i.e. the raw hashes returned by `NoteHash::compute_note_hash` and `NoteHash::compute_nullifier`. PXE\n/// will verify that the siloed unique note hash was inserted into the tree at `tx_hash`, and will store the nullifier\n/// to later check for nullification.\n///\n/// `owner` is the address used in note hash and nullifier computation, often requiring knowledge of their nullifier\n/// secret key.\n///\n/// `scope` is the account to which the note message was delivered (i.e. the address the message was encrypted to).\n/// This determines which PXE account can see the note - other accounts will not be able to access it (e.g. other\n/// accounts will not be able to see one another's token balance notes, even in the same PXE) unless authorized. In\n/// most cases `recipient` equals `owner`, but they can differ in scenarios like delegated discovery.\npub unconstrained fn enqueue_note_for_validation(\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_nonce: Field,\n packed_note: BoundedVec,\n note_hash: Field,\n nullifier: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n NoteValidationRequest {\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_nonce,\n packed_note,\n note_hash,\n nullifier,\n tx_hash,\n },\n )\n}\n\n/// Enqueues an event for validation and storage by PXE.\n///\n/// This is the primary way for custom message handlers (registered via\n/// [`crate::macros::AztecConfig::custom_message_handler`]) to deliver reassembled events back to PXE after processing\n/// application-specific message formats.\n///\n/// In order for the event validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many event validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// Note that `validate_and_store_enqueued_notes_and_events` is called by Aztec.nr after processing messages, so custom\n/// message processors do not need to be concerned with this.\npub unconstrained fn enqueue_event_for_validation(\n contract_address: AztecAddress,\n event_type_id: EventSelector,\n randomness: Field,\n serialized_event: BoundedVec,\n event_commitment: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n EventValidationRequest {\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n },\n )\n}\n\n/// Validates and stores all enqueued notes and events.\n///\n/// Processes all requests enqueued via [`enqueue_note_for_validation`] and [`enqueue_event_for_validation`], inserting\n/// them into the note database and event store respectively, making them queryable via `get_notes` oracle and our TS\n/// API (PXE::getPrivateEvents).\npub unconstrained fn validate_and_store_enqueued_notes_and_events(scope: AztecAddress) {\n message_processing::validate_and_store_enqueued_notes_and_events(\n NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n MAX_NOTE_PACKED_LEN as Field,\n MAX_EVENT_SERIALIZED_LEN as Field,\n scope,\n );\n\n // Defensive clearing: purge the queues after processing to prevent double-processing if this function is called\n // more than once in the same call frame. It is currently defensive because we only call this once per sync run.\n let _ = EphemeralArray::::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n let _ = EphemeralArray::::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n}\n\n/// Efficiently queries the node for logs that result in the completion of all `DeliveredPendingPartialNote`s stored in\n/// a `CapsuleArray` by performing all node communication concurrently. Returns an `EphemeralArray` with Options\n/// for the responses that correspond to the pending partial notes at the same index.\n///\n/// For example, given an array with pending partial notes `[ p1, p2, p3 ]`, where `p1` and `p3` have corresponding\n/// completion logs but `p2` does not, the returned `EphemeralArray` will have contents `[some(p1_log), none(),\n/// some(p3_log)]`.\npub(crate) unconstrained fn get_pending_partial_notes_completion_logs(\n contract_address: AztecAddress,\n pending_partial_notes: CapsuleArray,\n) -> EphemeralArray> {\n let log_retrieval_requests = EphemeralArray::at(LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT);\n\n // We create a LogRetrievalRequest for each PendingPartialNote in the EphemeralArray. Because we need the indices in\n // the request array to match the indices in the partial note array, we can't use EphemeralArray::for_each, as that\n // function has arbitrary iteration order. Instead, we manually iterate the array from the beginning and push into\n // the requests array, which we expect to be empty.\n let mut i = 0;\n let pending_partial_notes_count = pending_partial_notes.len();\n while i < pending_partial_notes_count {\n let pending_partial_note = pending_partial_notes.get(i);\n // Partial note completion logs are emitted with a domain-separated tag. To find matching logs, we apply the\n // same domain separation to the stored raw tag.\n let log_tag = compute_log_tag(\n pending_partial_note.note_completion_log_tag,\n DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n );\n log_retrieval_requests.push(LogRetrievalRequest { contract_address, unsiloed_tag: log_tag });\n i += 1;\n }\n\n let responses = message_processing::get_logs_by_tag(log_retrieval_requests);\n\n // Defensive clearing: prevent stale requests if this function is called more than once in the same call frame.\n let _ = log_retrieval_requests.clear();\n\n responses\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/mod.nr","function_locations":[{"start":3763,"name":"enqueue_note_for_validation"},{"start":5177,"name":"enqueue_event_for_validation"},{"start":5884,"name":"validate_and_store_enqueued_notes_and_events"},{"start":7412,"name":"get_pending_partial_notes_completion_logs"}]},"153":{"source":"use crate::{\n capsules::CapsuleArray,\n context::UtilityContext,\n ephemeral::EphemeralArray,\n messages::{encoding::MESSAGE_CIPHERTEXT_LEN, processing::OffchainMessageWithContext},\n oracle::contract_sync::set_contract_sync_cache_invalid,\n protocol::{\n address::AztecAddress,\n constants::MAX_TX_LIFETIME,\n hash::sha256_to_field,\n traits::{Deserialize, Serialize},\n },\n};\n\n/// Base capsule slot for the persistent inbox of [`PendingOffchainMsg`] entries.\n///\n/// This is the slot where we accumulate messages received through [`receive`].\nglobal OFFCHAIN_INBOX_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_INBOX_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to pass tx hash resolution requests to PXE.\nglobal OFFCHAIN_CONTEXT_REQUESTS_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_CONTEXT_REQUESTS_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to collect messages ready for processing.\nglobal OFFCHAIN_READY_MESSAGES_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_READY_MESSAGES_SLOT\".as_bytes());\n\n/// Maximum number of offchain messages accepted by `offchain_receive` in a single call.\npub global MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL: u32 = 16;\n\n/// Tolerance added to the `MAX_TX_LIFETIME` cap for message expiration.\nglobal TX_EXPIRATION_TOLERANCE: u64 = 7200; // 2 hours\n\n/// Maximum time-to-live for a tx-bound offchain message.\n///\n/// After `anchor_block_timestamp + MAX_MSG_TTL`, the message is evicted from the inbox.\nglobal MAX_MSG_TTL: u64 = MAX_TX_LIFETIME + TX_EXPIRATION_TOLERANCE;\n\n/// A function that manages offchain-delivered messages for processing during sync.\n///\n/// Offchain messages are messages that are not broadcasted via onchain logs. They are instead delivered to the\n/// recipient by calling the `offchain_receive` utility function (injected by the `#[aztec]` macro). Message transport\n/// is the app's responsibility. Typical examples of transport methods are: messaging apps, email, QR codes, etc.\n///\n/// Once offchain messages are delivered to the recipient's private environment via `offchain_receive`, messages are\n/// locally stored in a persistent inbox.\n///\n/// This function determines when each message in said inbox is ready for processing, when it can be safely disposed\n/// of, etc.\n///\n/// The only current implementation of an `OffchainInboxSync` is [`sync_inbox`], which manages an inbox with expiration\n/// based eviction and automatic transaction context resolution.\npub(crate) type OffchainInboxSync = unconstrained fn[Env](\n/* contract_address */AztecAddress, /* scope */ AztecAddress) -> EphemeralArray;\n\n/// A message delivered via the `offchain_receive` utility function.\npub struct OffchainMessage {\n /// The encrypted message payload.\n pub ciphertext: BoundedVec,\n /// The intended recipient of the message.\n pub recipient: AztecAddress,\n /// The hash of the transaction that produced this message. `Option::none` indicates a tx-less message.\n pub tx_hash: Option,\n /// Anchor block timestamp at message emission.\n pub anchor_block_timestamp: u64,\n}\n\n/// An offchain message awaiting processing (or re-processing) in the inbox.\n///\n/// Messages remain in the inbox until they expire, even if they have already been processed. This is necessary to\n/// handle reorgs: a processed message may need to be re-processed if the transaction that provided its context is\n/// reverted. On each sync, resolved messages are promoted to [`OffchainMessageWithContext`] for processing.\n#[derive(Serialize, Deserialize)]\nstruct PendingOffchainMsg {\n /// The encrypted message payload.\n ciphertext: BoundedVec,\n /// The intended recipient of the message.\n recipient: AztecAddress,\n /// The hash of the transaction that produced this message. A value of 0 indicates a tx-less message.\n tx_hash: Field,\n /// Anchor block timestamp at message emission. Used to compute the effective expiration: messages are evicted\n /// after `anchor_block_timestamp + MAX_MSG_TTL`.\n anchor_block_timestamp: u64,\n}\n\n/// Delivers offchain messages to the given contract's offchain inbox for subsequent processing.\n///\n/// Offchain messages are transaction effects that are not broadcasted via onchain logs. Instead, the sender shares the\n/// message to the recipient through an external channel (e.g. a URL accessible by the recipient). The recipient then\n/// calls this function to hand the messages to the contract so they can be processed through the same mechanisms as\n/// onchain messages.\n///\n/// Each message is routed to the inbox scoped to its `recipient` field, so messages for different accounts are\n/// automatically isolated.\n///\n/// Messages are processed when their originating transaction is found onchain (providing the context needed to\n/// validate resulting notes and events).\n///\n/// Messages are kept in the inbox until they expire. The effective expiration is\n/// `anchor_block_timestamp + MAX_MSG_TTL`.\n///\n/// Processing order is not guaranteed.\npub unconstrained fn receive(\n contract_address: AztecAddress,\n messages: BoundedVec,\n) {\n // May contain duplicates if multiple messages target the same recipient. This is harmless since\n // cache invalidation on the TS side is idempotent (deleting an already-deleted key is a no-op).\n let mut scopes: BoundedVec = BoundedVec::new();\n let mut i = 0;\n let messages_len = messages.len();\n while i < messages_len {\n let msg = messages.get(i);\n let tx_hash = if msg.tx_hash.is_some() {\n msg.tx_hash.unwrap()\n } else {\n 0\n };\n let inbox: CapsuleArray =\n CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, msg.recipient);\n inbox.push(\n PendingOffchainMsg {\n ciphertext: msg.ciphertext,\n recipient: msg.recipient,\n tx_hash,\n anchor_block_timestamp: msg.anchor_block_timestamp,\n },\n );\n scopes.push(msg.recipient);\n i += 1;\n }\n\n set_contract_sync_cache_invalid(contract_address, scopes);\n}\n\n/// Returns offchain-delivered messages to process during sync.\n///\n/// Messages remain in the inbox and are reprocessed on each sync until their originating transaction is no longer at\n/// risk of being dropped by a reorg.\npub unconstrained fn sync_inbox(\n contract_address: AztecAddress,\n scope: AztecAddress,\n) -> EphemeralArray {\n let inbox: CapsuleArray = CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, scope);\n let context_resolution_requests: EphemeralArray = EphemeralArray::at(OFFCHAIN_CONTEXT_REQUESTS_SLOT).clear();\n let ready_to_process: EphemeralArray =\n EphemeralArray::at(OFFCHAIN_READY_MESSAGES_SLOT).clear();\n\n // Build a request list aligned with the inbox indices.\n let mut i = 0;\n let inbox_len = inbox.len();\n while i < inbox_len {\n let msg = inbox.get(i);\n context_resolution_requests.push(msg.tx_hash);\n i += 1;\n }\n\n // Ask PXE to resolve contexts for all requested tx hashes. The oracle returns responses in a new\n // ephemeral array.\n let resolved_contexts =\n crate::oracle::message_processing::get_message_contexts_by_tx_hash(context_resolution_requests);\n\n assert_eq(resolved_contexts.len(), inbox_len);\n\n let now = UtilityContext::new().timestamp();\n\n let mut j = inbox_len;\n while j > 0 {\n // This loop decides what to do with each message in the offchain message inbox. We need to handle 3\n // different scenarios for each message.\n //\n // 1. The TX that emitted this message is still not known to PXE: in this case we can't yet process this\n // message, as any notes or events discovered will fail to be validated. So we leave the message in the inbox,\n // awaiting for future syncs to detect that the TX became available.\n //\n // 2. The message is not associated to a TX to begin with. The current version of offchain message processing\n // does not support this case, but in the future it will. Right now, a message without an associated TX will\n // sit in the inbox until it expires.\n //\n // 3. The TX that emitted this message has been found by PXE. That gives us all the information needed to\n // process the message. We add the message to the `ready_to_process` EphemeralArray so that the `sync_state`\n // loop\n // processes it.\n //\n // In all cases, if the message has expired (i.e. `now > anchor_block_timestamp + MAX_MSG_TTL`), we remove it\n // from the inbox.\n //\n // Note: the loop runs backwards because it might call `inbox.remove(j)` to purge expired messages and we also\n // need to align it with `resolved_contexts.get(j)`. Going from last to first simplifies the algorithm as\n // not yet visited element indexes remain stable.\n j -= 1;\n let maybe_ctx = resolved_contexts.get(j);\n let msg = inbox.get(j);\n\n // Compute the message's effective expiration timestamp to determine if we can purge it from the inbox.\n let effective_expiration = msg.anchor_block_timestamp + MAX_MSG_TTL;\n\n // Message expired. We remove it from the inbox.\n if now > effective_expiration {\n inbox.remove(j);\n }\n\n // Scenario 1: associated TX not yet available. We keep the message in the inbox, as it might become\n // processable as new blocks get mined.\n // Scenario 2: no TX associated to message. The message will sit in the inbox until it expires.\n if maybe_ctx.is_none() {\n continue;\n }\n\n // Scenario 3: Message is ready to process, add to result array. Note we still keep it in the inbox unless we\n // consider it has expired: this is because we need to account for reorgs. If reorg occurs after we processed\n // a message, the effects of processing the message get rewind. However, the associated TX can be included in\n // a subsequent block. Should that happen, the message must be re-processed to ensure consistency.\n let message_context = maybe_ctx.unwrap();\n ready_to_process.push(OffchainMessageWithContext { message_ciphertext: msg.ciphertext, message_context });\n }\n\n ready_to_process\n}\n\nmod test {\n use crate::{\n capsules::CapsuleArray, oracle::random::random, protocol::address::AztecAddress,\n test::helpers::test_environment::TestEnvironment,\n };\n use super::{\n MAX_MSG_TTL, MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL, OFFCHAIN_INBOX_SLOT, OffchainMessage, PendingOffchainMsg,\n receive, sync_inbox,\n };\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n /// Creates an `OffchainMessage` with dummy ciphertext and the given scope as recipient.\n fn make_msg(recipient: AztecAddress, tx_hash: Option, anchor_block_timestamp: u64) -> OffchainMessage {\n OffchainMessage { ciphertext: BoundedVec::new(), recipient, tx_hash, anchor_block_timestamp }\n }\n\n /// Advances the TXE block timestamp by `offset` seconds and returns the resulting timestamp.\n unconstrained fn advance_by(env: TestEnvironment, offset: u64) -> u64 {\n env.advance_next_block_timestamp_by(offset);\n env.mine_block();\n env.last_block_timestamp()\n }\n\n #[test]\n unconstrained fn empty_inbox_returns_empty_result() {\n let (env, scope) = setup();\n env.utility_context(|context| {\n let result = sync_inbox(context.this_address(), scope);\n let inbox: CapsuleArray =\n CapsuleArray::at(context.this_address(), OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0);\n assert_eq(inbox.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_not_expired_before_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance, but not past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn tx_less_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::none(), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn unresolved_tx_stays_in_inbox() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // not resolved, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn multiple_messages_mixed_expiration() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n let survivor_tx_hash = random();\n\n env.utility_context(|context| {\n let address = context.this_address();\n let mut msgs: BoundedVec = BoundedVec::new();\n // Message 0: tx-bound, anchor_ts in the past so it expires at\n // anchor_ts + MAX_MSG_TTL. We set anchor to 0 so it expires quickly.\n msgs.push(make_msg(scope, Option::some(random()), 0));\n // Message 1: tx-bound, anchor_ts is recent so it survives.\n msgs.push(make_msg(scope, Option::some(survivor_tx_hash), anchor_ts));\n // Message 2: tx-less, anchor_ts=0 so it also expires.\n msgs.push(make_msg(scope, Option::none(), 0));\n receive(address, msgs);\n });\n\n // Advance past MAX_MSG_TTL for anchor_ts=0, but not for anchor_ts=anchor_ts.\n let _now = advance_by(env, MAX_MSG_TTL);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // all contexts are None\n // Message 0 expired (anchor=0), message 1 survived (anchor=anchor_ts),\n // Message 2 expired (anchor=0).\n assert_eq(inbox.len(), 1);\n assert_eq(inbox.get(0).tx_hash, survivor_tx_hash);\n });\n }\n\n // -- Resolved context (ready to process) ------------------------------\n\n #[test]\n unconstrained fn resolved_msg_is_ready_to_process() {\n let (env, scope) = setup();\n // TestEnvironment::new() deploys protocol contracts, creating blocks with tx effects.\n // In TXE, tx hashes equal Fr(blockNumber), so Fr(1) is the tx effect from block 1.\n // We use this as a \"known resolvable\" tx hash.\n let known_tx_hash: Field = 1;\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(known_tx_hash), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n // The message should be ready to process since its tx context was resolved.\n assert_eq(result.len(), 1);\n\n let ctx = result.get(0).message_context;\n assert_eq(ctx.tx_hash, known_tx_hash);\n assert(ctx.first_nullifier_in_tx != 0, \"resolved context must have a first nullifier\");\n\n // Message stays in inbox (not expired) for potential reorg reprocessing.\n assert_eq(inbox.len(), 1);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/offchain.nr","function_locations":[{"start":5298,"name":"receive"},{"start":6741,"name":"sync_inbox"},{"start":11111,"name":"test::setup"},{"start":11441,"name":"test::make_msg"},{"start":11724,"name":"test::advance_by"},{"start":11915,"name":"test::empty_inbox_returns_empty_result"},{"start":12378,"name":"test::tx_bound_msg_expires_after_max_msg_ttl"},{"start":13343,"name":"test::tx_bound_msg_not_expired_before_max_msg_ttl"},{"start":14301,"name":"test::tx_less_msg_expires_after_max_msg_ttl"},{"start":15243,"name":"test::unresolved_tx_stays_in_inbox"},{"start":16137,"name":"test::multiple_messages_mixed_expiration"},{"start":17876,"name":"test::resolved_msg_is_ready_to_process"}]},"171":{"source":"#[oracle(aztec_utl_decryptAes128)]\nunconstrained fn aes128_decrypt_oracle(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {}\n\n/// Attempts to decrypt a ciphertext using AES128.\n///\n/// Returns `Option::some(plaintext)` on success, or `Option::none()` if decryption fails (e.g. due to malformed\n/// ciphertext or invalid PKCS#7 padding). Note that decryption with the wrong key will almost always return `None`\n/// because the decrypted garbage data will have invalid PKCS#7 padding.\n///\n/// Note that we accept ciphertext as a BoundedVec, not as an array. This is because this function is typically used\n/// when processing logs and at that point we don't have comptime information about the length of the ciphertext as\n/// the log is not specific to any individual note.\n// TODO(F-498): review naming consistency\npub unconstrained fn try_aes128_decrypt(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {\n aes128_decrypt_oracle(ciphertext, iv, sym_key)\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::compute_app_siloed_shared_secret,\n messages::encryption::aes128::derive_aes_symmetric_key_and_iv_from_shared_secret,\n utils::{array::subarray::subarray, point::point_from_x_coord},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::try_aes128_decrypt;\n use std::aes128::aes128_encrypt;\n\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress { inner: 42 };\n global TEST_PLAINTEXT_LENGTH: u32 = 10;\n global TEST_CIPHERTEXT_LENGTH: u32 = 16;\n global TEST_PADDING_LENGTH: u32 = TEST_CIPHERTEXT_LENGTH - TEST_PLAINTEXT_LENGTH;\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n\n let received_plaintext = try_aes128_decrypt(ciphertext_bvec, iv, sym_key).unwrap();\n assert_eq(received_plaintext.len(), TEST_PLAINTEXT_LENGTH);\n assert_eq(received_plaintext.max_len(), TEST_CIPHERTEXT_LENGTH);\n assert_eq(subarray::<_, _, TEST_PLAINTEXT_LENGTH>(received_plaintext.storage(), 0), plaintext);\n assert_eq(\n subarray::<_, _, TEST_PADDING_LENGTH>(received_plaintext.storage(), TEST_PLAINTEXT_LENGTH),\n [0 as u8; TEST_PADDING_LENGTH],\n );\n })\n }\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt_with_bad_sym_key_is_caught() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n // Decrypting with the wrong key results in garbage data with invalid PKCS#7 padding,\n // so the oracle returns None.\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let mut bad_sym_key = sym_key;\n bad_sym_key[0] = 0;\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n // Decryption with wrong key returns None because the garbage output has invalid PKCS#7 padding.\n let result = try_aes128_decrypt(ciphertext_bvec, iv, bad_sym_key);\n assert(result.is_none(), \"decryption with bad key should return None\");\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/aes128_decrypt.nr","function_locations":[{"start":194,"name":"aes128_decrypt_oracle"},{"start":1046,"name":"try_aes128_decrypt"},{"start":1860,"name":"test::aes_encrypt_then_decrypt"},{"start":3150,"name":"test::aes_encrypt_then_decrypt_with_bad_sym_key_is_caught"}]},"176":{"source":"use crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Stores arbitrary information in a per-contract non-volatile database, which can later be retrieved with `load`. If\n/// data was already stored at this slot, it is overwritten.\n// TODO(F-498): review naming consistency\npub unconstrained fn store(contract_address: AztecAddress, slot: Field, value: T, scope: AztecAddress)\nwhere\n T: Serialize,\n{\n let serialized = value.serialize();\n set_capsule_oracle(contract_address, slot, serialized, scope);\n}\n\n/// Returns data previously stored via `storeCapsule` in the per-contract non-volatile database. Returns\n/// Option::none() if nothing was stored at the given slot.\n// TODO(F-498): review naming consistency\npub unconstrained fn load(contract_address: AztecAddress, slot: Field, scope: AztecAddress) -> Option\nwhere\n T: Deserialize,\n{\n let serialized_option = get_capsule_oracle(contract_address, slot, ::N, scope);\n serialized_option.map(|arr| Deserialize::deserialize(arr))\n}\n\n/// Deletes data in the per-contract non-volatile database. Does nothing if no data was present.\npub unconstrained fn delete(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {\n delete_oracle(contract_address, slot, scope);\n}\n\n/// Copies a number of contiguous entries in the per-contract non-volatile database. This allows for efficient data\n/// structures by avoiding repeated calls to `loadCapsule` and `storeCapsule`. Supports overlapping source and\n/// destination regions (which will result in the overlapped source values being overwritten). All copied slots must\n/// exist in the database (i.e. have been stored and not deleted)\npub unconstrained fn copy(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {\n copy_oracle(contract_address, src_slot, dst_slot, num_entries, scope);\n}\n\n#[oracle(aztec_utl_setCapsule)]\nunconstrained fn set_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n values: [Field; N],\n scope: AztecAddress,\n) {}\n\n/// We need to pass in `array_len` (the value of N) as a parameter to tell the oracle how many fields the response must\n/// have.\n///\n/// Note that the oracle returns an Option<[Field; N]> because we cannot return an Option directly. That would\n/// require for the oracle resolver to know the shape of T (e.g. if T were a struct of 3 u32 values then the expected\n/// response shape would be 3 single items, whereas it were a struct containing `u32, [Field;10], u32` then the\n/// expected shape would be single, array, single.). Instead, we return the serialization and deserialize in Noir.\n#[oracle(aztec_utl_getCapsule)]\nunconstrained fn get_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n array_len: u32,\n scope: AztecAddress,\n) -> Option<[Field; N]> {}\n\n#[oracle(aztec_utl_deleteCapsule)]\nunconstrained fn delete_oracle(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {}\n\n#[oracle(aztec_utl_copyCapsule)]\nunconstrained fn copy_oracle(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {}\n\nmod test {\n // These tests are sort of redundant since we already test the oracle implementation directly in TypeScript, but\n // they are cheap regardless and help ensure both that the TXE implementation works accordingly and that the Noir\n // oracles are hooked up correctly.\n\n use crate::{\n oracle::capsules::{copy, delete, load, store},\n test::{helpers::test_environment::TestEnvironment, mocks::MockStruct},\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, ToField}};\n\n global SLOT: Field = 1;\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n #[test]\n unconstrained fn stores_and_loads() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), value);\n });\n }\n\n #[test]\n unconstrained fn store_overwrites() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n let new_value = MockStruct::new(7, 8);\n store(contract_address, SLOT, new_value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), new_value);\n });\n }\n\n #[test]\n unconstrained fn loads_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_stored_value() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n delete(contract_address, SLOT, scope);\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n delete(contract_address, SLOT, scope);\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn copies_non_overlapping_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 5;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 10;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_src_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 1;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 2;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[1] and src[2] should have been overwritten since they are also dst[0] and dst[1]\n assert_eq(load(contract_address, src, scope).unwrap(), values[0]); // src[0] (unchanged)\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[0]); // dst[0]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[1]); // dst[1]\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_dst_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 2;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 1;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[0] and src[1] should have been overwritten since they are also dst[1] and dst[2]\n assert_eq(load(contract_address, src, scope).unwrap(), values[1]); // dst[1]\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[2]); // dst[2]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[2]); // src[2] (unchanged)\n });\n }\n\n #[test(should_fail_with = \"copy empty slot\")]\n unconstrained fn cannot_copy_empty_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n copy(contract_address, SLOT, SLOT, 1, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_store_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let value = MockStruct::new(5, 6);\n store(other_contract_address, SLOT, value, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_load_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let _: Option = load(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_delete_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n delete(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_copy_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n copy(other_contract_address, SLOT, SLOT, 0, scope);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/capsules.nr","function_locations":[{"start":433,"name":"store"},{"start":886,"name":"load"},{"start":1247,"name":"delete"},{"start":1866,"name":"copy"},{"start":2131,"name":"set_capsule_oracle"},{"start":2931,"name":"get_capsule_oracle"},{"start":3067,"name":"delete_oracle"},{"start":3261,"name":"copy_oracle"},{"start":3884,"name":"test::setup"},{"start":4060,"name":"test::stores_and_loads"},{"start":4450,"name":"test::store_overwrites"},{"start":4957,"name":"test::loads_empty_slot"},{"start":5311,"name":"test::deletes_stored_value"},{"start":5819,"name":"test::deletes_empty_slot"},{"start":6233,"name":"test::copies_non_overlapping_values"},{"start":7106,"name":"test::copies_overlapping_values_with_src_ahead"},{"start":8366,"name":"test::copies_overlapping_values_with_dst_ahead"},{"start":9648,"name":"test::cannot_copy_empty_values"},{"start":9970,"name":"test::cannot_store_other_contract"},{"start":10443,"name":"test::cannot_load_other_contract"},{"start":10891,"name":"test::cannot_delete_other_contract"},{"start":11311,"name":"test::cannot_copy_other_contract"}]},"177":{"source":"use crate::protocol::address::AztecAddress;\n\n#[oracle(aztec_utl_setContractSyncCacheInvalid)]\nunconstrained fn set_contract_sync_cache_invalid_oracle(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {}\n\n/// Forces the PXE to re-sync the given contract for a set of scopes on the next query.\n///\n/// Call this after writing data (e.g. offchain messages) that the contract's `sync_state` function needs to discover.\n/// Without invalidation, the sync cache would skip re-running `sync_state` until the next block.\npub unconstrained fn set_contract_sync_cache_invalid(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {\n set_contract_sync_cache_invalid_oracle(contract_address, scopes);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/contract_sync.nr","function_locations":[{"start":242,"name":"set_contract_sync_cache_invalid_oracle"},{"start":700,"name":"set_contract_sync_cache_invalid"}]},"179":{"source":"use crate::context::UtilityContext;\n\n#[oracle(aztec_utl_getUtilityContext)]\nunconstrained fn get_utility_context_oracle() -> UtilityContext {}\n\n/// Returns a utility context built from the global variables of anchor block and the contract address of the function\n/// being executed.\npub unconstrained fn get_utility_context() -> UtilityContext {\n get_utility_context_oracle()\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/execution.nr","function_locations":[{"start":140,"name":"get_utility_context_oracle"},{"start":344,"name":"get_utility_context"}]},"189":{"source":"use crate::ephemeral::EphemeralArray;\nuse crate::messages::processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse, MessageContext,\n pending_tagged_log::PendingTaggedLog,\n};\nuse crate::protocol::address::AztecAddress;\n\n/// Finds new private logs that may have been sent to all registered accounts in PXE in the current contract and\n/// returns them in an ephemeral array with an oracle-allocated base slot.\npub(crate) unconstrained fn get_pending_tagged_logs(scope: AztecAddress) -> EphemeralArray {\n let result_slot = get_pending_tagged_logs_oracle(scope);\n EphemeralArray::at(result_slot)\n}\n\n#[oracle(aztec_utl_getPendingTaggedLogs_v2)]\nunconstrained fn get_pending_tagged_logs_oracle(scope: AztecAddress) -> Field {}\n\n/// Validates note/event requests stored in ephemeral arrays.\npub(crate) unconstrained fn validate_and_store_enqueued_notes_and_events(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {\n validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot,\n event_validation_requests_array_slot,\n max_note_packed_len,\n max_event_serialized_len,\n scope,\n );\n}\n\n#[oracle(aztec_utl_validateAndStoreEnqueuedNotesAndEvents_v2)]\nunconstrained fn validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {}\n\n/// Fetches logs by tag from an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_logs_by_tag(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_logs_by_tag_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getLogsByTag_v2)]\nunconstrained fn get_logs_by_tag_v2_oracle(request_array_slot: Field) -> Field {}\n\n/// Resolves message contexts for tx hashes in an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_message_contexts_by_tx_hash(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_message_contexts_by_tx_hash_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getMessageContextsByTxHash_v2)]\nunconstrained fn get_message_contexts_by_tx_hash_v2_oracle(request_array_slot: Field) -> Field {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/message_processing.nr","function_locations":[{"start":570,"name":"get_pending_tagged_logs"},{"start":795,"name":"get_pending_tagged_logs_oracle"},{"start":1128,"name":"validate_and_store_enqueued_notes_and_events"},{"start":1692,"name":"validate_and_store_enqueued_notes_and_events_oracle"},{"start":1938,"name":"get_logs_by_tag"},{"start":2163,"name":"get_logs_by_tag_v2_oracle"},{"start":2423,"name":"get_message_contexts_by_tx_hash"},{"start":2694,"name":"get_message_contexts_by_tx_hash_v2_oracle"}]},"196":{"source":"use crate::protocol::address::aztec_address::AztecAddress;\nuse crate::protocol::point::Point;\n\n#[oracle(aztec_utl_getSharedSecret)]\nunconstrained fn get_shared_secret_oracle(\n address: AztecAddress,\n ephPk: Point,\n contract_address: AztecAddress,\n) -> Field {}\n\n/// Returns an app-siloed shared secret between `address` and someone who knows the secret key behind an ephemeral\n/// public key `ephPk`.\n///\n/// The returned value is a Field `s_app`, computed as:\n///\n/// ```text\n/// S = address_secret * ephPk (raw ECDH point)\n/// s_app = h(DOM_SEP, S.x, S.y, contract) (app-siloed scalar)\n/// ```\n///\n/// where `contract` is the address of the calling contract. The oracle host validates this matches its execution\n/// context.\n///\n/// Without app-siloing, a malicious contract could call this oracle with public information (address, ephPk) and\n/// obtain the same raw secret as the legitimate contract, enabling cross-contract decryption. By including the\n/// contract address in the hash, each contract receives a different `s_app`, preventing this attack.\n///\n/// Callers derive indexed subkeys from `s_app` via\n/// [`derive_shared_secret_subkey`](crate::keys::ecdh_shared_secret::derive_shared_secret_subkey).\npub unconstrained fn get_shared_secret(address: AztecAddress, ephPk: Point, contract_address: AztecAddress) -> Field {\n get_shared_secret_oracle(address, ephPk, contract_address)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr","function_locations":[{"start":267,"name":"get_shared_secret_oracle"},{"start":1354,"name":"get_shared_secret"}]},"245":{"source":"/// Appends the elements of the second `BoundedVec` to the end of the first one. The resulting `BoundedVec` can have\n/// any arbitrary maximum length, but it must be large enough to fit all of the elements of both the first and second\n/// vectors.\npub fn append(\n a: BoundedVec,\n b: BoundedVec,\n) -> BoundedVec {\n let mut dst = BoundedVec::new();\n\n dst.extend_from_bounded_vec(a);\n dst.extend_from_bounded_vec(b);\n\n dst\n}\n\nmod test {\n use super::append;\n\n #[test]\n unconstrained fn append_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::new();\n let b: BoundedVec<_, 14> = BoundedVec::new();\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 0);\n assert_eq(result.storage(), std::mem::zeroed());\n }\n\n #[test]\n unconstrained fn append_non_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 6);\n assert_eq(result.storage(), [1, 2, 3, 4, 5, 6, std::mem::zeroed(), std::mem::zeroed()]);\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn append_non_empty_vecs_insufficient_max_len() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let _: BoundedVec = append(a, b);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/append.nr","function_locations":[{"start":396,"name":"append"},{"start":608,"name":"test::append_empty_vecs"},{"start":933,"name":"test::append_non_empty_vecs"},{"start":1387,"name":"test::append_non_empty_vecs_insufficient_max_len"}]},"248":{"source":"/// Returns `DstLen` elements from a source array, starting at `offset`. `DstLen` must not be larger than the number of\n/// elements past `offset`.\n///\n/// Examples:\n/// ```\n/// let foo: [Field; 2] = subarray([1, 2, 3, 4, 5], 2);\n/// assert_eq(foo, [3, 4]);\n///\n/// let bar: [Field; 5] = subarray([1, 2, 3, 4, 5], 2); // fails - we can't return 5 elements since only 3 remain\n/// ```\npub fn subarray(src: [T; SrcLen], offset: u32) -> [T; DstLen] {\n assert(offset + DstLen <= SrcLen, \"DstLen too large for offset\");\n\n let mut dst: [T; DstLen] = std::mem::zeroed();\n for i in 0..DstLen {\n dst[i] = src[i + offset];\n }\n\n dst\n}\n\nmod test {\n use super::subarray;\n\n #[test]\n unconstrained fn subarray_into_empty() {\n // In all of these cases we're setting DstLen to be 0, so we always get back an empty array.\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 2), []);\n }\n\n #[test]\n unconstrained fn subarray_complete() {\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), [1, 2, 3, 4, 5]);\n }\n\n #[test]\n unconstrained fn subarray_different_end_sizes() {\n // We implicitly select how many values to read in the size of the return array\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4, 5]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2]);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subarray_offset_too_large() {\n // With an offset of 1 we can only request up to 4 elements\n let _: [_; 5] = subarray([1, 2, 3, 4, 5], 1);\n }\n\n #[test(should_fail)]\n unconstrained fn subarray_bad_return_value() {\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [3, 3, 4, 5]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr","function_locations":[{"start":483,"name":"subarray"},{"start":776,"name":"test::subarray_into_empty"},{"start":1100,"name":"test::subarray_complete"},{"start":1294,"name":"test::subarray_different_end_sizes"},{"start":1736,"name":"test::subarray_offset_too_large"},{"start":1941,"name":"test::subarray_bad_return_value"}]},"249":{"source":"use crate::utils::array;\n\n/// Returns `DstMaxLen` elements from a source BoundedVec, starting at `offset`. `offset` must not be larger than the\n/// original length, and `DstLen` must not be larger than the total number of elements past `offset` (including the\n/// zeroed elements past `len()`).\n///\n/// Only elements at the beginning of the vector can be removed: it is not possible to also remove elements at the end\n/// of the vector by passing a value for `DstLen` that is smaller than `len() - offset`.\n///\n/// Examples:\n/// ```\n/// let foo = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n/// assert_eq(subbvec(foo, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n///\n/// let bar: BoundedVec<_, 1> = subbvec(foo, 2); // fails - we can't return just 1 element since 3 remain\n/// let baz: BoundedVec<_, 10> = subbvec(foo, 3); // fails - we can't return 10 elements since only 7 remain\n/// ```\npub fn subbvec(\n bvec: BoundedVec,\n offset: u32,\n) -> BoundedVec {\n // from_parts_unchecked does not verify that the elements past len are zeroed, but that is not an issue in our case\n // because we're constructing the new storage array as a subarray of the original one (which should have zeroed\n // storage past len), guaranteeing correctness. This is because `subarray` does not allow extending arrays past\n // their original length.\n BoundedVec::from_parts_unchecked(array::subarray(bvec.storage(), offset), bvec.len() - offset)\n}\n\nmod test {\n use super::subbvec;\n\n #[test]\n unconstrained fn subbvec_empty() {\n let bvec = BoundedVec::::from_array([]);\n assert_eq(subbvec(bvec, 0), bvec);\n }\n\n #[test]\n unconstrained fn subbvec_complete() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), bvec);\n\n let smaller_capacity = BoundedVec::<_, 5>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), smaller_capacity);\n }\n\n #[test]\n unconstrained fn subbvec_partial() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 3>::from_array([3, 4, 5]));\n }\n\n #[test]\n unconstrained fn subbvec_into_empty() {\n let bvec: BoundedVec<_, 10> = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 5), BoundedVec::<_, 5>::from_array([]));\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_offset_past_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n let _: BoundedVec<_, 1> = subbvec(bvec, 6);\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_insufficient_dst_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // We're not providing enough space to hold all of the items inside the original BoundedVec. subbvec can cause\n // for the capacity to reduce, but not the length (other than by len - offset).\n let _: BoundedVec<_, 1> = subbvec(bvec, 2);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_causes_enlarge() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // subbvec does not support capacity increases\n let _: BoundedVec<_, 11> = subbvec(bvec, 0);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_too_large_for_offset() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // This effectively requests a capacity increase, since there'd be just one element plus the 5 empty slots,\n // which is less than 7.\n let _: BoundedVec<_, 7> = subbvec(bvec, 4);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr","function_locations":[{"start":1041,"name":"subbvec"},{"start":1612,"name":"test::subbvec_empty"},{"start":1775,"name":"test::subbvec_complete"},{"start":2083,"name":"test::subbvec_partial"},{"start":2376,"name":"test::subbvec_into_empty"},{"start":2609,"name":"test::subbvec_offset_past_len"},{"start":2816,"name":"test::subbvec_insufficient_dst_len"},{"start":3270,"name":"test::subbvec_dst_len_causes_enlarge"},{"start":3579,"name":"test::subbvec_dst_len_too_large_for_offset"}]},"252":{"source":"use std::static_assert;\n\n/// Encodes an array of bytes as fields.\n///\n/// Use\n/// [`decode_bytes_from_fields`](crate::utils::conversion::bytes_as_fields::decode_bytes_from_fields) to recover\n/// the original bytes.\n///\n/// The `bytes` array length must be a multiple of 31. If padding is added, it will need to be manually removed\n/// after decoding.\n///\n/// ## Encoding\n///\n/// Each 31-byte chunk is interpreted as a big-endian integer and stored in a `Field`. For input `[1, 10, 3, ..., 0]`\n/// (31 bytes), the resulting `Field` is `1 * 256^30 + 10 * 256^29 + 3 * 256^28 + ... + 0`.\npub fn encode_bytes_as_fields(bytes: [u8; N]) -> [Field; N / 31] {\n static_assert(N % 31 == 0, \"N must be a multiple of 31\");\n\n let mut fields = [0; N / 31];\n for i in 0..N / 31 {\n let mut field = 0;\n for j in 0..31 {\n field = field * 256 + bytes[i * 31 + j] as Field;\n }\n fields[i] = field;\n }\n\n fields\n}\n\n/// Decodes fields back into bytes.\n///\n/// Inverse of\n/// [`encode_bytes_as_fields`](crate::utils::conversion::bytes_as_fields::encode_bytes_as_fields).\n/// Each input `Field` must fit in 248 bits; `Field::to_be_bytes::<31>()` fails the proof otherwise.\npub fn decode_bytes_from_fields(fields: BoundedVec) -> BoundedVec {\n let mut bytes = BoundedVec::new();\n for i in 0..fields.len() {\n let chunk: [u8; 31] = fields.get(i).to_be_bytes();\n for j in 0..31 {\n bytes.push(chunk[j]);\n }\n }\n bytes\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_bytes_from_fields, encode_bytes_as_fields};\n\n #[test]\n unconstrained fn round_trips_bytes(input: [u8; 93]) {\n let fields = encode_bytes_as_fields(input);\n\n // In production the fields fly through the system and arrive as a BoundedVec on the other end.\n let fields_bvec = BoundedVec::<_, 6>::from_array(fields);\n let bytes_back = decode_bytes_from_fields(fields_bvec);\n\n assert_eq(bytes_back.len(), input.len());\n assert_eq(subarray(bytes_back.storage(), 0), input);\n }\n\n #[test(should_fail_with = \"N must be a multiple of 31\")]\n unconstrained fn encode_rejects_length_not_multiple_of_31() {\n let _fields = encode_bytes_as_fields([0; 32]);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 31 limbs\")]\n unconstrained fn decode_rejects_oversized_field() {\n // `Field::to_be_bytes::<31>()` fails the proof when a field has any bit above position 247 set.\n let oversized: Field = (1 as Field) * 2.pow_32(249);\n let input = BoundedVec::<_, 1>::from_array([oversized]);\n let _bytes = decode_bytes_from_fields(input);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/bytes_as_fields.nr","function_locations":[{"start":662,"name":"encode_bytes_as_fields"},{"start":1313,"name":"decode_bytes_from_fields"},{"start":1719,"name":"tests::round_trips_bytes"},{"start":2252,"name":"tests::encode_rejects_length_not_multiple_of_31"},{"start":2454,"name":"tests::decode_rejects_oversized_field"}]},"253":{"source":"/// Encodes an array of fields as bytes.\n///\n/// Losslessly preserves any field value; use\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes) to\n/// recover the original fields.\n///\n/// ## Encoding\n///\n/// Each field is written as 32 big-endian bytes and the chunks are concatenated. The field array `[5, 42]` becomes:\n///\n/// ```text\n/// [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, // First field (32 bytes)\n/// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42] // Second field (32 bytes)\n/// ```\n///\n/// ## Privacy\n///\n/// The BN254 modulus is `< 2^254`, so every 32-byte chunk has its top bit at zero and the next bit biased. The output\n/// is therefore distinguishable from uniform random bytes; take this into account when feeding it into anything that\n/// assumes uniform randomness (e.g. ciphertexts meant to look random).\npub fn encode_fields_as_bytes(fields: [Field; N]) -> [u8; 32 * N] {\n let mut bytes = [0; 32 * N];\n for i in 0..N {\n let chunk: [u8; 32] = fields[i].to_be_bytes();\n for j in 0..32 {\n bytes[i * 32 + j] = chunk[j];\n }\n }\n bytes\n}\n\n/// Decodes bytes back into fields.\n///\n/// Panics if the input length is not a multiple of 32 or if any chunk exceeds the BN254 field modulus. See\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes)\n/// for a non-panicking variant.\npub fn decode_fields_from_bytes(bytes: BoundedVec) -> BoundedVec {\n assert(bytes.len() % 32 == 0, \"Input length must be a multiple of 32\");\n try_decode_fields_from_bytes(bytes).expect(f\"Value does not fit in field\")\n}\n\n/// Decodes bytes back into fields, returning None on failure.\n///\n/// Inverse of\n/// [`encode_fields_as_bytes`](crate::utils::conversion::fields_as_bytes::encode_fields_as_bytes).\n/// Returns `Option::none()` if the input length is not a multiple of 32, or if any 32-byte chunk is `>=` the BN254\n/// field modulus.\npub fn try_decode_fields_from_bytes(bytes: BoundedVec) -> Option> {\n if bytes.len() % 32 == 0 {\n let num_chunks = bytes.len() / 32;\n let mut fields: BoundedVec = BoundedVec::new();\n for i in 0..num_chunks {\n let maybe_field = try_decode_field_from_bytes(bytes, i * 32);\n if maybe_field.is_some() {\n fields.push(maybe_field.unwrap());\n }\n }\n if fields.len() == num_chunks {\n Option::some(fields)\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n}\n\nfn try_decode_field_from_bytes(bytes: BoundedVec, offset: u32) -> Option {\n // Field arithmetic silently wraps values >= the modulus, so we compare each chunk against the modulus\n // byte-by-byte (big-endian) while building `field`. cmp: 0 = equal so far, 1 = less than modulus, 2 = exceeds.\n let p = std::field::modulus_be_bytes();\n let mut field = 0;\n let mut cmp: u8 = 0;\n for j in 0..32 {\n let byte = bytes.get(offset + j);\n field = field * 256 + byte as Field;\n if cmp == 0 {\n if byte < p[j] {\n cmp = 1;\n } else if byte > p[j] {\n cmp = 2;\n }\n }\n }\n\n if cmp == 1 {\n Option::some(field)\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_fields_from_bytes, encode_fields_as_bytes, try_decode_fields_from_bytes};\n\n #[test]\n unconstrained fn round_trips_fields(input: [Field; 3]) {\n let bytes = encode_fields_as_bytes(input);\n\n // In production the bytes fly through the system and arrive as a BoundedVec on the other end. 113 is an\n // arbitrary max length larger than the input length of 96.\n let bytes_bvec = BoundedVec::<_, 113>::from_array(bytes);\n let fields_back = try_decode_fields_from_bytes(bytes_bvec).unwrap();\n\n assert_eq(fields_back.len(), input.len());\n assert_eq(subarray(fields_back.storage(), 0), input);\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_length_not_multiple_of_32() {\n let input = BoundedVec::<_, 64>::from_parts([0 as u8; 64], 33);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test]\n unconstrained fn try_decode_accepts_max_field() {\n // -1 in field arithmetic wraps to `modulus - 1`, the largest valid field value.\n let max_field_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let input = BoundedVec::<_, 32>::from_array(max_field_as_bytes);\n\n let fields = try_decode_fields_from_bytes(input).unwrap();\n\n assert_eq(fields.get(0), -1);\n }\n\n // Verifies the overflow check: take the max allowed value, bump a random byte, feed it in.\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n // Skip if the selected byte is already 255. Acceptable under fuzz testing.\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_equal_to_modulus() {\n // The field modulus itself is not a valid field value (it wraps to 0).\n let p: [u8; 32] = std::field::modulus_be_bytes().as_array();\n let input = BoundedVec::::from_array(p);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test(should_fail_with = \"Input length must be a multiple of 32\")]\n unconstrained fn decode_asserts_length_multiple_of_32() {\n let input = BoundedVec::<_, 143>::from_array([\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n 30, 31, 32, 33,\n ]);\n let _fields = decode_fields_from_bytes(input);\n }\n\n #[test(should_fail_with = \"Value does not fit in field\")]\n unconstrained fn decode_panics_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n let _fields = decode_fields_from_bytes(input);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/fields_as_bytes.nr","function_locations":[{"start":1007,"name":"encode_fields_as_bytes"},{"start":1603,"name":"decode_fields_from_bytes"},{"start":2190,"name":"try_decode_fields_from_bytes"},{"start":2829,"name":"try_decode_field_from_bytes"},{"start":3733,"name":"tests::round_trips_fields"},{"start":4320,"name":"tests::try_decode_returns_none_on_length_not_multiple_of_32"},{"start":4528,"name":"tests::try_decode_accepts_max_field"},{"start":5063,"name":"tests::try_decode_returns_none_on_chunk_above_modulus"},{"start":5718,"name":"tests::try_decode_returns_none_on_chunk_equal_to_modulus"},{"start":6128,"name":"tests::decode_asserts_length_multiple_of_32"},{"start":6544,"name":"tests::decode_panics_on_chunk_above_modulus"}]},"256":{"source":"use crate::protocol::{point::Point, utils::field::sqrt};\n\n// I am storing the modulus minus 1 divided by 2 here because full modulus would throw \"String literal too large\" error\n// Full modulus is 21888242871839275222246405745257275088548364400416034343698204186575808495617\nglobal BN254_FR_MODULUS_DIV_2: Field = 10944121435919637611123202872628637544274182200208017171849102093287904247808;\n\n/// Returns: true if p.y <= MOD_DIV_2, else false.\npub fn get_sign_of_point(p: Point) -> bool {\n // We store only a \"sign\" of the y coordinate because the rest can be derived from the x coordinate. To get the\n // sign we check if the y coordinate is less or equal than the field's modulus minus 1 divided by 2. Ideally we'd\n // do `y <= MOD_DIV_2`, but there's no `lte` function, so instead we do `!(y > MOD_DIV_2)`, which is equivalent,\n // and then rewrite that as `!(MOD_DIV_2 < y)`, since we also have no `gt` function.\n !BN254_FR_MODULUS_DIV_2.lt(p.y)\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\npub fn point_from_x_coord(x: Field) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n sqrt(rhs).map(|y| Point { x, y, is_infinite: false })\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate and sign for the y coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\n///\n/// @param x - The x coordinate of the point @param sign - The \"sign\" of the y coordinate - determines whether y <=\n/// (Fr.MODULUS - 1) / 2\npub fn point_from_x_coord_and_sign(x: Field, sign: bool) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n\n sqrt(rhs).map(|y| {\n // If there is a square root, we need to ensure it has the correct \"sign\"\n let y_is_positive = !BN254_FR_MODULUS_DIV_2.lt(y);\n let final_y = if y_is_positive == sign { y } else { -y };\n Point { x, y: final_y, is_infinite: false }\n })\n}\n\nmod test {\n use crate::protocol::point::Point;\n use crate::utils::point::{\n BN254_FR_MODULUS_DIV_2, get_sign_of_point, point_from_x_coord, point_from_x_coord_and_sign,\n };\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign() {\n // Test positive y coordinate\n let x = 0x1af41f5de96446dc3776a1eb2d98bb956b7acd9979a67854bec6fa7c2973bd73;\n let sign = true;\n let p = point_from_x_coord_and_sign(x, sign).unwrap();\n\n assert_eq(p.x, x);\n assert_eq(p.y, 0x07fc22c7f2c7057571f137fe46ea9c95114282bc95d37d71ec4bfb88de457d4a);\n assert_eq(p.is_infinite, false);\n\n // Test negative y coordinate\n let x2 = 0x247371652e55dd74c9af8dbe9fb44931ba29a9229994384bd7077796c14ee2b5;\n let sign2 = false;\n let p2 = point_from_x_coord_and_sign(x2, sign2).unwrap();\n\n assert_eq(p2.x, x2);\n assert_eq(p2.y, 0x26441aec112e1ae4cee374f42556932001507ad46e255ffb27369c7e3766e5c0);\n assert_eq(p2.is_infinite, false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_valid() {\n // x = 8 is a known quadratic residue - should give a valid point\n let result = point_from_x_coord(Field::from(8));\n assert(result.is_some());\n\n let point = result.unwrap();\n assert_eq(point.x, Field::from(8));\n // Check curve equation y^2 = x^3 - 17\n assert_eq(point.y * point.y, point.x * point.x * point.x - 17);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_invalid() {\n // x = 3 is a non-residue for this curve - should give None\n let x = Field::from(3);\n let maybe_point = point_from_x_coord(x);\n assert(maybe_point.is_none());\n }\n\n #[test]\n unconstrained fn test_both_roots_satisfy_curve() {\n // Derive a point from x = 8 (known to be valid from test_point_from_x_coord_valid)\n let x: Field = 8;\n let point = point_from_x_coord(x).unwrap();\n\n // Check y satisfies curve equation\n assert_eq(point.y * point.y, x * x * x - 17);\n\n // Check -y also satisfies curve equation\n let neg_y = 0 - point.y;\n assert_eq(neg_y * neg_y, x * x * x - 17);\n\n // Verify they are different (unless y = 0)\n assert(point.y != neg_y);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign_invalid() {\n // x = 3 has no valid point on the curve (from test_point_from_x_coord_invalid)\n let x = Field::from(3);\n let result_positive = point_from_x_coord_and_sign(x, true);\n let result_negative = point_from_x_coord_and_sign(x, false);\n\n assert(result_positive.is_none());\n assert(result_negative.is_none());\n }\n\n #[test]\n unconstrained fn test_get_sign_of_point() {\n // Derive a point from x = 8, then test both possible y values\n let point = point_from_x_coord(8).unwrap();\n let neg_point = Point { x: point.x, y: 0 - point.y, is_infinite: false };\n\n // One should be \"positive\" (y <= MOD_DIV_2) and one \"negative\"\n let sign1 = get_sign_of_point(point);\n let sign2 = get_sign_of_point(neg_point);\n assert(sign1 != sign2);\n\n // y = 0 should return true (0 <= MOD_DIV_2)\n let zero_y_point = Point { x: 0, y: 0, is_infinite: false };\n assert(get_sign_of_point(zero_y_point) == true);\n\n // y = MOD_DIV_2 should return true (exactly at boundary)\n let boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2, is_infinite: false };\n assert(get_sign_of_point(boundary_point) == true);\n\n // y = MOD_DIV_2 + 1 should return false (just over boundary)\n let over_boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2 + 1, is_infinite: false };\n assert(get_sign_of_point(over_boundary_point) == false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_zero() {\n // x = 0: y^2 = 0^3 - 17 = -17, which is not a quadratic residue in BN254 scalar field\n let result = point_from_x_coord(0);\n assert(result.is_none());\n }\n\n #[test]\n unconstrained fn test_bn254_fr_modulus_div_2() {\n // Verify that BN254_FR_MODULUS_DIV_2 == (p - 1) / 2 This means: 2 * BN254_FR_MODULUS_DIV_2 + 1 == p == 0 (in\n // the field)\n assert_eq(2 * BN254_FR_MODULUS_DIV_2 + 1, 0);\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/point.nr","function_locations":[{"start":488,"name":"get_sign_of_point"},{"start":1371,"name":"point_from_x_coord"},{"start":2088,"name":"point_from_x_coord_and_sign"},{"start":2697,"name":"test::test_point_from_x_coord_and_sign"},{"start":3524,"name":"test::test_point_from_x_coord_valid"},{"start":3966,"name":"test::test_point_from_x_coord_invalid"},{"start":4228,"name":"test::test_both_roots_satisfy_curve"},{"start":4803,"name":"test::test_point_from_x_coord_and_sign_invalid"},{"start":5214,"name":"test::test_get_sign_of_point"},{"start":6328,"name":"test::test_point_from_x_coord_zero"},{"start":6573,"name":"test::test_bn254_fr_modulus_div_2"}]},"266":{"source":"use std::default::Default;\nuse std::hash::Hasher;\n\nglobal RATE: u32 = 3;\n\npub struct Poseidon2 {\n cache: [Field; 3],\n state: [Field; 4],\n cache_size: u32,\n squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2 {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2::hash_internal(input, message_size)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2 {\n let mut result =\n Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n self.state[0] += self.cache[0];\n self.state[1] += self.cache[1];\n self.state[2] += self.cache[2];\n self.state = crate::poseidon2_permutation(self.state);\n }\n\n fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(input: [Field; N], in_len: u32) -> Field {\n let two_pow_64 = 18446744073709551616;\n let iv: Field = (in_len as Field) * two_pow_64;\n let mut state = [0; 4];\n state[RATE] = iv;\n\n if std::runtime::is_unconstrained() {\n for i in 0..(in_len / RATE) {\n state[0] += input[i * RATE];\n state[1] += input[i * RATE + 1];\n state[2] += input[i * RATE + 2];\n state = crate::poseidon2_permutation(state);\n }\n\n // handle remaining elements after last full RATE-sized chunk\n let num_extra_fields = in_len % RATE;\n if num_extra_fields != 0 {\n let remainder_start = in_len - num_extra_fields;\n state[0] += input[remainder_start];\n if num_extra_fields > 1 {\n state[1] += input[remainder_start + 1];\n }\n }\n } else {\n let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];\n states[0] = state;\n\n // process all full RATE-sized chunks, storing state after each permutation\n for chunk_idx in 0..(N / RATE) {\n for i in 0..RATE {\n state[i] += input[chunk_idx * RATE + i];\n }\n state = crate::poseidon2_permutation(state);\n states[chunk_idx + 1] = state;\n }\n\n // get state at the last full block before in_len\n let first_partially_filled_chunk = in_len / RATE;\n state = states[first_partially_filled_chunk];\n\n // handle remaining elements after last full RATE-sized chunk\n let remainder_start = (in_len / RATE) * RATE;\n for j in 0..RATE {\n let idx = remainder_start + j;\n if idx < in_len {\n state[j] += input[idx];\n }\n }\n }\n\n // always run final permutation unless we just completed a full chunk\n // still need to permute once if in_len is 0\n if (in_len == 0) | (in_len % RATE != 0) {\n state = crate::poseidon2_permutation(state);\n };\n\n state[0]\n }\n}\n\npub struct Poseidon2Hasher {\n _state: [Field],\n}\n\nimpl Hasher for Poseidon2Hasher {\n fn finish(self) -> Field {\n let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)\n let mut sponge = Poseidon2::new(iv);\n for i in 0..self._state.len() {\n sponge.absorb(self._state[i]);\n }\n sponge.squeeze()\n }\n\n fn write(&mut self, input: Field) {\n self._state = self._state.push_back(input);\n }\n}\n\nimpl Default for Poseidon2Hasher {\n fn default() -> Self {\n Poseidon2Hasher { _state: @[] }\n }\n}\n","path":"/Users/maximvezenov/nargo/github.com/noir-lang/poseidon/v0.3.0/src/poseidon2.nr","function_locations":[{"start":333,"name":"Poseidon2::hash"},{"start":442,"name":"Poseidon2::new"},{"start":649,"name":"Poseidon2::perform_duplex"},{"start":923,"name":"Poseidon2::absorb"},{"start":1453,"name":"Poseidon2::squeeze"},{"start":1814,"name":"Poseidon2::hash_internal"},{"start":4105,"name":"::finish"},{"start":4426,"name":"::write"},{"start":4549,"name":"::default"}]},"355":{"source":"mod poseidon2_chunks;\n\nuse crate::{\n abis::{\n contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage,\n function_selector::FunctionSelector, nullifier::Nullifier, private_log::PrivateLog,\n transaction::tx_request::TxRequest,\n },\n address::{AztecAddress, EthAddress},\n constants::{\n CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, DOM_SEP__NOTE_HASH_NONCE,\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__SILOED_NOTE_HASH, DOM_SEP__SILOED_NULLIFIER,\n DOM_SEP__UNIQUE_NOTE_HASH, FUNCTION_TREE_HEIGHT, NULL_MSG_SENDER_CONTRACT_ADDRESS,\n TWO_POW_64,\n },\n merkle_tree::root_from_sibling_path,\n messaging::l2_to_l1_message::L2ToL1Message,\n poseidon2::Poseidon2Sponge,\n side_effect::{Counted, Scoped},\n traits::{FromField, Hash, ToField},\n utils::field::{field_from_bytes, field_from_bytes_32_trunc},\n};\n\npub use poseidon2_chunks::poseidon2_absorb_in_chunks_existing_sponge;\nuse poseidon2_chunks::poseidon2_absorb_in_chunks;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\n// TODO: refactor these into their own files: sha256, poseidon2, some protocol-specific hash computations, some merkle computations.\n\npub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field {\n let sha256_hashed = sha256::digest(bytes_to_hash);\n let hash_in_a_field = field_from_bytes_32_trunc(sha256_hashed);\n\n hash_in_a_field\n}\n\npub fn private_functions_root_from_siblings(\n selector: FunctionSelector,\n vk_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT],\n) -> Field {\n let function_leaf_preimage = ContractClassFunctionLeafPreimage { selector, vk_hash };\n let function_leaf = function_leaf_preimage.hash();\n root_from_sibling_path(\n function_leaf,\n function_leaf_index,\n function_leaf_sibling_path,\n )\n}\n\n/// Siloing in the context of Aztec refers to the process of hashing a note hash with a contract address (this way\n/// the note hash is scoped to a specific contract). This is used to prevent intermingling of notes between contracts.\npub fn compute_siloed_note_hash(contract_address: AztecAddress, note_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), note_hash],\n DOM_SEP__SILOED_NOTE_HASH,\n )\n}\n\n/// Computes unique, siloed note hashes from siloed note hashes.\n///\n/// The protocol injects uniqueness into every note_hash, so that every single note_hash in the\n/// tree is unique. This prevents faerie gold attacks, where a malicious sender could create\n/// two identical note_hashes for a recipient (meaning only one would be nullifiable in future).\n///\n/// Most privacy protocols will inject the note's leaf_index (its position in the Note Hashes Tree)\n/// into the note, but this requires the creator of a note to wait until their tx is included in\n/// a block to know the note's final note hash (the unique, siloed note hash), because inserting\n/// leaves into trees is the job of a block producer.\n///\n/// We took a different approach so that the creator of a note will know each note's unique, siloed\n/// note hash before broadcasting their tx to the network.\n/// (There was also a historical requirement relating to \"chained transactions\" -- a feature that\n/// Aztec Connect had to enable notes to be spent from distinct txs earlier in the same block,\n/// and hence before an archive block root had been established for that block -- but that feature\n/// was abandoned for the Aztec Network for having too many bad tradeoffs).\n///\n/// (\n/// Edit: it is no longer true that all final note_hashes will be known by the creator of a tx\n/// before they send it to the network. If a tx makes public function calls, then _revertible_\n/// note_hashes that are created in private will not be made unique in private by the Reset circuit,\n/// but will instead be made unique by the AVM, because the `note_index_in_tx` will not be known\n/// until the AVM has executed the public functions of the tx. (See an explanation in\n/// reset_output_composer.nr for why).\n/// For some such txs, the `note_index_in_tx` might still be predictable through simulation, but\n/// for txs whose public functions create a varying number of non-revertible notes (determined at\n/// runtime), the `note_index_in_tx` will not be deterministically derivable before submitting the\n/// tx to the network.\n/// )\n///\n/// We use the `first_nullifier` of a tx as a seed of uniqueness. We have a guarantee that there will\n/// always be at least one nullifier per tx, because the init circuit will create one if one isn't\n/// created naturally by any functions of the tx. (Search \"protocol_nullifier\").\n/// We combine the `first_nullifier` with the note's index (its position within this tx's new\n/// note_hashes array) (`note_index_in_tx`) to get a truly unique value to inject into a note, which\n/// we call a `note_nonce`.\npub fn compute_unique_note_hash(note_nonce: Field, siloed_note_hash: Field) -> Field {\n let inputs = [note_nonce, siloed_note_hash];\n poseidon2_hash_with_separator(inputs, DOM_SEP__UNIQUE_NOTE_HASH)\n}\n\npub fn compute_note_hash_nonce(first_nullifier_in_tx: Field, note_index_in_tx: u32) -> Field {\n // Hashing the first nullifier with note index in tx is guaranteed to be unique (because all nullifiers are also\n // unique).\n poseidon2_hash_with_separator(\n [first_nullifier_in_tx, note_index_in_tx as Field],\n DOM_SEP__NOTE_HASH_NONCE,\n )\n}\n\npub fn compute_note_nonce_and_unique_note_hash(\n siloed_note_hash: Field,\n first_nullifier: Field,\n note_index_in_tx: u32,\n) -> Field {\n let note_nonce = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n compute_unique_note_hash(note_nonce, siloed_note_hash)\n}\n\npub fn compute_siloed_nullifier(contract_address: AztecAddress, nullifier: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), nullifier],\n DOM_SEP__SILOED_NULLIFIER,\n )\n}\n\npub fn create_protocol_nullifier(tx_request: TxRequest) -> Scoped> {\n // The protocol nullifier is ascribed a special side-effect counter of 1. No other side-effect\n // can have counter 1 (see `validate_as_first_call` for that assertion).\n Nullifier { value: tx_request.hash(), note_hash: 0 }.count(1).scope(\n NULL_MSG_SENDER_CONTRACT_ADDRESS,\n )\n}\n\npub fn compute_log_tag(raw_tag: Field, dom_sep: u32) -> Field {\n poseidon2_hash_with_separator([raw_tag], dom_sep)\n}\n\npub fn compute_siloed_private_log_first_field(\n contract_address: AztecAddress,\n field: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), field],\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD,\n )\n}\n\npub fn compute_siloed_private_log(contract_address: AztecAddress, log: PrivateLog) -> PrivateLog {\n let mut fields = log.fields;\n fields[0] = compute_siloed_private_log_first_field(contract_address, fields[0]);\n PrivateLog::new(fields, log.length)\n}\n\npub fn compute_contract_class_log_hash(log: [Field; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS]) -> Field {\n poseidon2_hash(log)\n}\n\npub fn compute_app_siloed_secret_key(\n master_secret_key: EmbeddedCurveScalar,\n app_address: AztecAddress,\n key_type_domain_separator: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [master_secret_key.hi, master_secret_key.lo, app_address.to_field()],\n key_type_domain_separator,\n )\n}\n\npub fn compute_l2_to_l1_message_hash(\n message: Scoped,\n rollup_version_id: Field,\n chain_id: Field,\n) -> Field {\n let contract_address_bytes: [u8; 32] = message.contract_address.to_field().to_be_bytes();\n let recipient_bytes: [u8; 20] = message.inner.recipient.to_be_bytes();\n let content_bytes: [u8; 32] = message.inner.content.to_be_bytes();\n let rollup_version_id_bytes: [u8; 32] = rollup_version_id.to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n\n let mut bytes: [u8; 148] = std::mem::zeroed();\n for i in 0..32 {\n bytes[i] = contract_address_bytes[i];\n bytes[i + 32] = rollup_version_id_bytes[i];\n // 64 - 84 are for recipient.\n bytes[i + 84] = chain_id_bytes[i];\n bytes[i + 116] = content_bytes[i];\n }\n\n for i in 0..20 {\n bytes[64 + i] = recipient_bytes[i];\n }\n\n sha256_to_field(bytes)\n}\n\n// TODO: consider a variant that enables domain separation with a u32 (we seem to have standardised u32s for domain separators)\n/// Computes sha256 hash of 2 input fields.\n///\n/// @returns A truncated field (i.e., the first byte is always 0).\npub fn accumulate_sha256(v0: Field, v1: Field) -> Field {\n // Concatenate two fields into 32 x 2 = 64 bytes\n let v0_as_bytes: [u8; 32] = v0.to_be_bytes();\n let v1_as_bytes: [u8; 32] = v1.to_be_bytes();\n let hash_input_flattened = v0_as_bytes.concat(v1_as_bytes);\n\n sha256_to_field(hash_input_flattened)\n}\n\npub fn poseidon2_hash(inputs: [Field; N]) -> Field {\n poseidon::poseidon2::Poseidon2::hash(inputs, N)\n}\n\n#[no_predicates]\npub fn poseidon2_hash_with_separator(inputs: [Field; N], separator: T) -> Field\nwhere\n T: ToField,\n{\n let inputs_with_separator = [separator.to_field()].concat(inputs);\n poseidon2_hash(inputs_with_separator)\n}\n\n/// Computes a Poseidon2 hash over a dynamic-length subarray of the given input.\n/// Only the first `in_len` fields of `input` are absorbed; any remaining fields are ignored.\n/// The caller is responsible for ensuring that the input is padded with zeros if required.\n#[no_predicates]\npub fn poseidon2_hash_subarray(input: [Field; N], in_len: u32) -> Field {\n let mut sponge = poseidon2_absorb_in_chunks(input, in_len);\n sponge.squeeze()\n}\n\n// This function is unconstrained because it is intended to be used in unconstrained context only as\n// in constrained contexts it would be too inefficient.\npub unconstrained fn poseidon2_hash_with_separator_bounded_vec(\n inputs: BoundedVec,\n separator: T,\n) -> Field\nwhere\n T: ToField,\n{\n let in_len = inputs.len() + 1;\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n sponge.absorb(separator.to_field());\n\n for i in 0..inputs.len() {\n sponge.absorb(inputs.get(i));\n }\n\n sponge.squeeze()\n}\n\n#[no_predicates]\npub fn poseidon2_hash_bytes(inputs: [u8; N]) -> Field {\n let mut fields = [0; (N + 30) / 31];\n let mut field_index = 0;\n let mut current_field = [0; 31];\n for i in 0..inputs.len() {\n let index = i % 31;\n current_field[index] = inputs[i];\n if index == 30 {\n fields[field_index] = field_from_bytes(current_field, false);\n current_field = [0; 31];\n field_index += 1;\n }\n }\n if field_index != fields.len() {\n fields[field_index] = field_from_bytes(current_field, false);\n }\n poseidon2_hash(fields)\n}\n\n#[test]\nfn subarray_hash_matches_fixed() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash the entire values_to_hash.\n let fixed_len_hash = poseidon::poseidon2::Poseidon2::hash(values_to_hash, values_to_hash.len());\n\n assert_eq(subarray_hash, fixed_len_hash);\n}\n\n#[test]\nfn subarray_hash_matches_variable() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash up to values_to_hash.len() fields of the padded array.\n let variable_len_hash = poseidon::poseidon2::Poseidon2::hash(padded, values_to_hash.len());\n\n assert_eq(subarray_hash, variable_len_hash);\n}\n\n#[test]\nfn smoke_sha256_to_field() {\n let full_buffer = [\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\n 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,\n 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,\n 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,\n 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,\n 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,\n 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\n ];\n let result = sha256_to_field(full_buffer);\n\n assert(result == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184c7);\n\n // to show correctness of the current ver (truncate one byte) vs old ver (mod full bytes):\n let result_bytes = sha256::digest(full_buffer);\n let truncated_field = crate::utils::field::field_from_bytes_32_trunc(result_bytes);\n assert(truncated_field == result);\n let mod_res = result + (result_bytes[31] as Field);\n assert(mod_res == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184e0);\n}\n\n#[test]\nfn unique_siloed_note_hash_matches_typescript() {\n let inner_note_hash = 1;\n let contract_address = AztecAddress::from_field(2);\n let first_nullifier = 3;\n let note_index_in_tx = 4;\n\n let siloed_note_hash = compute_siloed_note_hash(contract_address, inner_note_hash);\n let siloed_note_hash_from_ts =\n 0x1986a4bea3eddb1fff917d629a13e10f63f514f401bdd61838c6b475db949169;\n assert_eq(siloed_note_hash, siloed_note_hash_from_ts);\n\n let nonce: Field = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n let note_hash_nonce_from_ts =\n 0x28e7799791bf066a57bb51fdd0fbcaf3f0926414314c7db515ea343f44f5d58b;\n assert_eq(nonce, note_hash_nonce_from_ts);\n\n let unique_siloed_note_hash_from_nonce = compute_unique_note_hash(nonce, siloed_note_hash);\n let unique_siloed_note_hash = compute_note_nonce_and_unique_note_hash(\n siloed_note_hash,\n first_nullifier,\n note_index_in_tx,\n );\n assert_eq(unique_siloed_note_hash_from_nonce, unique_siloed_note_hash);\n\n let unique_siloed_note_hash_from_ts =\n 0x29949aef207b715303b24639737c17fbfeb375c1d965ecfa85c7e4f0febb7d16;\n assert_eq(unique_siloed_note_hash, unique_siloed_note_hash_from_ts);\n}\n\n#[test]\nfn siloed_nullifier_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let nullifier = 456;\n\n let res = compute_siloed_nullifier(contract_address, nullifier);\n\n let siloed_nullifier_from_ts =\n 0x169b50336c1f29afdb8a03d955a81e485f5ac7d5f0b8065673d1e407e5877813;\n\n assert_eq(res, siloed_nullifier_from_ts);\n}\n\n#[test]\nfn siloed_private_log_first_field_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let field = 456;\n let res = compute_siloed_private_log_first_field(contract_address, field);\n\n let siloed_private_log_first_field_from_ts =\n 0x29480984f7b9257fded523d50addbcfc8d1d33adcf2db73ef3390a8fd5cdffaa;\n\n assert_eq(res, siloed_private_log_first_field_from_ts);\n}\n\n#[test]\nfn empty_l2_to_l1_message_hash_matches_typescript() {\n // All zeroes\n let res = compute_l2_to_l1_message_hash(\n L2ToL1Message { recipient: EthAddress::zero(), content: 0 }.scope(AztecAddress::from_field(\n 0,\n )),\n 0,\n 0,\n );\n\n let empty_l2_to_l1_msg_hash_from_ts =\n 0x003b18c58c739716e76429634a61375c45b3b5cd470c22ab6d3e14cee23dd992;\n\n assert_eq(res, empty_l2_to_l1_msg_hash_from_ts);\n}\n\n#[test]\nfn l2_to_l1_message_hash_matches_typescript() {\n let message = L2ToL1Message { recipient: EthAddress::from_field(1), content: 2 }.scope(\n AztecAddress::from_field(3),\n );\n let version = 4;\n let chainId = 5;\n\n let hash = compute_l2_to_l1_message_hash(message, version, chainId);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let l2_to_l1_message_hash_from_ts =\n 0x0081edf209e087ad31b3fd24263698723d57190bd1d6e9fe056fc0c0a68ee661;\n\n assert_eq(hash, l2_to_l1_message_hash_from_ts);\n}\n\n#[test]\nunconstrained fn poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version() {\n let inputs = BoundedVec::::from_array([1, 2, 3]);\n let separator = 42;\n\n // Hash using bounded vec version\n let bounded_result = poseidon2_hash_with_separator_bounded_vec(inputs, separator);\n\n // Hash using regular version\n let regular_result = poseidon2_hash_with_separator([1, 2, 3], separator);\n\n // Results should match\n assert_eq(bounded_result, regular_result);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr","function_locations":[{"start":1253,"name":"sha256_to_field"},{"start":1605,"name":"private_functions_root_from_siblings"},{"start":2202,"name":"compute_siloed_note_hash"},{"start":5031,"name":"compute_unique_note_hash"},{"start":5247,"name":"compute_note_hash_nonce"},{"start":5663,"name":"compute_note_nonce_and_unique_note_hash"},{"start":5899,"name":"compute_siloed_nullifier"},{"start":6116,"name":"create_protocol_nullifier"},{"start":6480,"name":"compute_log_tag"},{"start":6651,"name":"compute_siloed_private_log_first_field"},{"start":6882,"name":"compute_siloed_private_log"},{"start":7142,"name":"compute_contract_class_log_hash"},{"start":7333,"name":"compute_app_siloed_secret_key"},{"start":7628,"name":"compute_l2_to_l1_message_hash"},{"start":8709,"name":"accumulate_sha256"},{"start":9037,"name":"poseidon2_hash"},{"start":9228,"name":"poseidon2_hash_with_separator"},{"start":9714,"name":"poseidon2_hash_subarray"},{"start":10126,"name":"poseidon2_hash_with_separator_bounded_vec"},{"start":10487,"name":"poseidon2_hash_bytes"},{"start":11063,"name":"subarray_hash_matches_fixed"},{"start":11462,"name":"subarray_hash_matches_variable"},{"start":11878,"name":"smoke_sha256_to_field"},{"start":13280,"name":"unique_siloed_note_hash_matches_typescript"},{"start":14502,"name":"siloed_nullifier_matches_typescript"},{"start":14882,"name":"siloed_private_log_first_field_matches_typescript"},{"start":15292,"name":"empty_l2_to_l1_message_hash_matches_typescript"},{"start":15743,"name":"l2_to_l1_message_hash_matches_typescript"},{"start":16359,"name":"poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version"}]},"357":{"source":"// Log levels matching the JS logger:\n\n// global SILENT_LOG_LEVEL: u8 = 0;\nglobal FATAL_LOG_LEVEL: u8 = 1;\nglobal ERROR_LOG_LEVEL: u8 = 2;\nglobal WARN_LOG_LEVEL: u8 = 3;\nglobal INFO_LOG_LEVEL: u8 = 4;\nglobal VERBOSE_LOG_LEVEL: u8 = 5;\nglobal DEBUG_LOG_LEVEL: u8 = 6;\nglobal TRACE_LOG_LEVEL: u8 = 7;\n\n// --- Per-level log functions (no format args) ---\n\npub fn fatal_log(msg: str) {\n fatal_log_format(msg, []);\n}\n\npub fn error_log(msg: str) {\n error_log_format(msg, []);\n}\n\npub fn warn_log(msg: str) {\n warn_log_format(msg, []);\n}\n\npub fn info_log(msg: str) {\n info_log_format(msg, []);\n}\n\npub fn verbose_log(msg: str) {\n verbose_log_format(msg, []);\n}\n\npub fn debug_log(msg: str) {\n debug_log_format(msg, []);\n}\n\npub fn trace_log(msg: str) {\n trace_log_format(msg, []);\n}\n\n// --- Per-level log functions (with format args) ---\n\npub fn fatal_log_format(msg: str, args: [Field; N]) {\n log_format(FATAL_LOG_LEVEL, msg, args);\n}\n\npub fn error_log_format(msg: str, args: [Field; N]) {\n log_format(ERROR_LOG_LEVEL, msg, args);\n}\n\npub fn warn_log_format(msg: str, args: [Field; N]) {\n log_format(WARN_LOG_LEVEL, msg, args);\n}\n\npub fn info_log_format(msg: str, args: [Field; N]) {\n log_format(INFO_LOG_LEVEL, msg, args);\n}\n\npub fn verbose_log_format(msg: str, args: [Field; N]) {\n log_format(VERBOSE_LOG_LEVEL, msg, args);\n}\n\npub fn debug_log_format(msg: str, args: [Field; N]) {\n log_format(DEBUG_LOG_LEVEL, msg, args);\n}\n\npub fn trace_log_format(msg: str, args: [Field; N]) {\n log_format(TRACE_LOG_LEVEL, msg, args);\n}\n\nfn log_format(log_level: u8, msg: str, args: [Field; N]) {\n // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe\n // to call.\n unsafe { log_oracle_wrapper(log_level, msg, args) };\n}\n\nunconstrained fn log_oracle_wrapper(\n log_level: u8,\n msg: str,\n args: [Field; N],\n) {\n log_oracle(log_level, msg, N, args);\n}\n\n// While the length parameter might seem unnecessary given that we have N, we keep it around because at the AVM\n// bytecode level we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally\n// take that route. The AVM transpiler maps this oracle to the DEBUGLOG opcode, which reads the fields size from memory.\n#[oracle(aztec_utl_log)]\nunconstrained fn log_oracle(\n log_level: u8,\n msg: str,\n length: u32,\n args: [Field; N],\n) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/logging.nr","function_locations":[{"start":395,"name":"fatal_log"},{"start":473,"name":"error_log"},{"start":550,"name":"warn_log"},{"start":626,"name":"info_log"},{"start":705,"name":"verbose_log"},{"start":785,"name":"debug_log"},{"start":863,"name":"trace_log"},{"start":1033,"name":"fatal_log_format"},{"start":1161,"name":"error_log_format"},{"start":1288,"name":"warn_log_format"},{"start":1414,"name":"info_log_format"},{"start":1543,"name":"verbose_log_format"},{"start":1673,"name":"debug_log_format"},{"start":1801,"name":"trace_log_format"},{"start":1934,"name":"log_format"},{"start":2248,"name":"log_oracle_wrapper"},{"start":2801,"name":"log_oracle"}]},"376":{"source":"use crate::constants::TWO_POW_64;\nuse crate::traits::{Deserialize, Serialize};\nuse std::meta::derive;\n// NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr\n// It exists as we sometimes need to perform custom absorption, but the stdlib version\n// has a private absorb() method (it's also designed to just be a hasher)\n// Can be removed when standalone noir poseidon lib exists: See noir#6679\n// TODO: Poseidon is stand-alone now\n\nglobal RATE: u32 = 3;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct Poseidon2Sponge {\n pub cache: [Field; 3],\n pub state: [Field; 4],\n pub cache_size: u32,\n pub squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2Sponge {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2Sponge::hash_internal(input, message_size, message_size != N)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2Sponge {\n let mut result =\n Poseidon2Sponge { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n for i in 0..RATE {\n // We effectively zero-pad the cache by only adding to the state\n // cache that is less than the specified `cache_size`\n if i < self.cache_size {\n self.state[i] += self.cache[i];\n }\n }\n self.state = std::hash::poseidon2_permutation(self.state);\n }\n\n pub fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n pub fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(\n input: [Field; N],\n in_len: u32,\n is_variable_length: bool,\n ) -> Field {\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n for i in 0..input.len() {\n if i < in_len {\n sponge.absorb(input[i]);\n }\n }\n\n sponge.squeeze()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr","function_locations":[{"start":798,"name":"Poseidon2Sponge::hash"},{"start":938,"name":"Poseidon2Sponge::new"},{"start":1151,"name":"Poseidon2Sponge::perform_duplex"},{"start":1592,"name":"Poseidon2Sponge::absorb"},{"start":2126,"name":"Poseidon2Sponge::squeeze"},{"start":2544,"name":"Poseidon2Sponge::hash_internal"}]},"395":{"source":"use crate::utils::field::field_from_bytes;\n\npub trait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n #[inline_always]\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for bool {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u8 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u16 {\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u32 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u64 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u128 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for str {\n #[inline_always]\n fn to_field(self) -> Field {\n assert(N < 32, \"String doesn't fit in a field, consider using Serialize instead\");\n field_from_bytes(self.as_bytes(), true)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/traits/to_field.nr","function_locations":[{"start":176,"name":"::to_field"},{"start":276,"name":"::to_field"},{"start":382,"name":"::to_field"},{"start":468,"name":"::to_field"},{"start":575,"name":"::to_field"},{"start":682,"name":"::to_field"},{"start":790,"name":"::to_field"},{"start":912,"name":">::to_field"}]},"403":{"source":"pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n\n// Convert a 32 byte array to a field element by truncating the final byte\npub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..15 {\n // covers bytes 16..30 (31 is truncated and ignored)\n low = low + (bytes32[15 + 15 - i] as Field) * v;\n v = v * 256;\n // covers bytes 0..14\n high = high + (bytes32[14 - i] as Field) * v;\n }\n // covers byte 15\n low = low + (bytes32[15] as Field) * v;\n\n low + high * v\n}\n\npub fn min(f1: Field, f2: Field) -> Field {\n if f1.lt(f2) {\n f1\n } else {\n f2\n }\n}\n\n// TODO: write doc-comments and tests for these magic constants.\n\nglobal KNOWN_NON_RESIDUE: Field = 5; // This is a non-residue in Noir's native Field.\nglobal C1: u32 = 28;\nglobal C3: Field = 40770029410420498293352137776570907027550720424234931066070132305055;\nglobal C5: Field = 19103219067921713944291392827692070036145651957329286315305642004821462161904;\n\n// @dev: only use this for _huge_ exponents y, when writing a constrained function.\n// If you're only exponentiating by a small value, first consider writing-out the multiplications by hand.\n// Only after you've measured the gates of that approach, consider using the native Field::pow_32 function.\n// Only if your exponent is larger than 32 bits, resort to using this function.\npub fn pow(x: Field, y: Field) -> Field {\n let mut r = 1 as Field;\n let b: [bool; 254] = y.to_le_bits();\n\n for i in 0..254 {\n r *= r;\n r *= (b[254 - 1 - i] as Field) * x + (1 - b[254 - 1 - i] as Field);\n }\n\n r\n}\n\n/// Returns Option::some(sqrt) if there is a square root, and Option::none() if there isn't.\npub fn sqrt(x: Field) -> Option {\n // Safety: if the hint returns the square root of x, then we simply square it\n // check the result equals x. If x is not square, we return a value that\n // enables us to prove that fact (see the `else` clause below).\n let (is_sq, maybe_sqrt) = unsafe { __sqrt(x) };\n\n if is_sq {\n let sqrt = maybe_sqrt;\n validate_sqrt_hint(x, sqrt);\n Option::some(sqrt)\n } else {\n let not_sqrt_hint = maybe_sqrt;\n validate_not_sqrt_hint(x, not_sqrt_hint);\n Option::none()\n }\n}\n\n// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.\nunconstrained fn is_square(x: Field) -> bool {\n let v = pow(x, -1 / 2);\n v * (v - 1) == 0\n}\n\n// Tonelli-Shanks algorithm for computing the square root of a Field element.\n// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field\n// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),\n// and C5 = ZETA^C2, where ZETA is a non-square element of Field.\n// These are pre-computed above as globals.\nunconstrained fn tonelli_shanks_sqrt(x: Field) -> Field {\n let mut z = pow(x, C3);\n let mut t = z * z * x;\n z *= x;\n let mut b = t;\n let mut c = C5;\n\n for i in 0..(C1 - 1) {\n for _j in 1..(C1 - i - 1) {\n b *= b;\n }\n\n z *= if b == 1 { 1 } else { c };\n\n c *= c;\n\n t *= if b == 1 { 1 } else { c };\n\n b = t;\n }\n\n z\n}\n\n// NB: this doesn't return an option, because in the case of there _not_ being a square root, we still want to return a field element that allows us to then assert in the _constrained_ sqrt function that there is no sqrt.\nunconstrained fn __sqrt(x: Field) -> (bool, Field) {\n let is_sq = is_square(x);\n if is_sq {\n let sqrt = tonelli_shanks_sqrt(x);\n (true, sqrt)\n } else {\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // sq * sq = sq // 1 * 1 = 1\n // non-sq * non-sq = sq // -1 * -1 = 1\n // sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n let not_sqrt = tonelli_shanks_sqrt(demo_x_not_square);\n (false, not_sqrt)\n }\n}\n\nfn validate_sqrt_hint(x: Field, hint: Field) {\n assert(hint * hint == x, f\"The claimed_sqrt {hint} is not the sqrt of x {x}\");\n}\n\nfn validate_not_sqrt_hint(x: Field, hint: Field) {\n // We need this assertion, because x = 0 would pass the other assertions in this\n // function, and we don't want people to be able to prove that 0 is not square!\n assert(x != 0, \"0 has a square root; you cannot claim it is not square\");\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n //\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // 1. sq * sq = sq // 1 * 1 = 1\n // 2. non-sq * non-sq = sq // -1 * -1 = 1\n // 3. sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n //\n // We want to demonstrate that this below multiplication falls under bullet-point (2):\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n // I.e. we want to demonstrate that `demo_x_not_square` has Legendre symbol 1\n // (i.e. that it is a square), so we prove that it is square below.\n // Why do we want to prove that it has LS 1?\n // Well, since it was computed with a known-non-residue, its squareness implies we're\n // in case 2 (something multiplied by a known-non-residue yielding a result which\n // has a LS of 1), which implies that x must be a non-square. The unconstrained\n // function gave us the sqrt of demo_x_not_square, so all we need to do is\n // assert its squareness:\n assert(\n hint * hint == demo_x_not_square,\n f\"The hint {hint} does not demonstrate that {x} is not a square\",\n );\n}\n\n#[test]\nunconstrained fn bytes_field_test() {\n // Tests correctness of field_from_bytes_32_trunc against existing methods\n // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7\n let inputs = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167,\n ];\n let field = field_from_bytes(inputs, true);\n let return_bytes: [u8; 31] = field.to_be_bytes();\n assert_eq(inputs, return_bytes);\n // 32 bytes - we remove the final byte, and check it matches the field\n let inputs2 = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158,\n ];\n let field2 = field_from_bytes_32_trunc(inputs2);\n let return_bytes2: [u8; 31] = field2.to_be_bytes();\n\n assert_eq(return_bytes2, return_bytes);\n assert_eq(field2, field);\n}\n\n#[test]\nunconstrained fn max_field_test() {\n // Tests the hardcoded value in constants.nr vs underlying modulus\n // NB: We can't use 0-1 in constants.nr as it will be transpiled incorrectly to ts and sol constants files\n let max_value = crate::constants::MAX_FIELD_VALUE;\n assert_eq(max_value, 0 - 1);\n // modulus == 0 is tested elsewhere, so below is more of a sanity check\n let max_bytes: [u8; 32] = max_value.to_be_bytes();\n let mod_bytes = std::field::modulus_be_bytes();\n for i in 0..31 {\n assert_eq(max_bytes[i], mod_bytes[i]);\n }\n assert_eq(max_bytes[31], mod_bytes[31] - 1);\n}\n\n#[test]\nunconstrained fn sqrt_valid_test() {\n let x = 16; // examples: 16, 9, 25, 81\n let result = sqrt(x);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), x);\n}\n\n#[test]\nunconstrained fn sqrt_invalid_test() {\n let x = KNOWN_NON_RESIDUE; // has no square root in the field\n let result = sqrt(x);\n assert(result.is_none());\n}\n\n#[test]\nunconstrained fn sqrt_zero_test() {\n let result = sqrt(0);\n assert(result.is_some());\n assert_eq(result.unwrap(), 0);\n}\n\n#[test]\nunconstrained fn sqrt_one_test() {\n let result = sqrt(1);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), 1);\n}\n\n#[test]\nunconstrained fn field_from_bytes_empty_test() {\n let empty: [u8; 0] = [];\n let result = field_from_bytes(empty, true);\n assert_eq(result, 0);\n\n let result_le = field_from_bytes(empty, false);\n assert_eq(result_le, 0);\n}\n\n#[test]\nunconstrained fn field_from_bytes_little_endian_test() {\n // Test little-endian conversion: [0x01, 0x02] should be 0x0201 = 513\n let bytes = [0x01, 0x02];\n let result_le = field_from_bytes(bytes, false);\n assert_eq(result_le, 0x0201);\n\n // Compare with big-endian: [0x01, 0x02] should be 0x0102 = 258\n let result_be = field_from_bytes(bytes, true);\n assert_eq(result_be, 0x0102);\n}\n\n#[test]\nunconstrained fn pow_test() {\n assert_eq(pow(2, 0), 1);\n assert_eq(pow(2, 1), 2);\n assert_eq(pow(2, 10), 1024);\n assert_eq(pow(3, 5), 243);\n assert_eq(pow(0, 5), 0);\n assert_eq(pow(1, 100), 1);\n}\n\n#[test]\nunconstrained fn min_test() {\n assert_eq(min(5, 10), 5);\n assert_eq(min(10, 5), 5);\n assert_eq(min(7, 7), 7);\n assert_eq(min(0, 1), 0);\n}\n\n#[test]\nunconstrained fn sqrt_has_two_roots_test() {\n // Every square has two roots: r and -r (i.e., p - r)\n // sqrt(16) can return 4 or -4\n let x = 16;\n let result = sqrt(x).unwrap();\n assert(result * result == x);\n // The other root is -result\n let other_root = 0 - result;\n assert(other_root * other_root == x);\n // Verify they are different (unless x = 0)\n assert(result != other_root);\n\n // Same for 9: roots are 3 and -3\n let y = 9;\n let result_y = sqrt(y).unwrap();\n assert(result_y * result_y == y);\n let other_root_y = 0 - result_y;\n assert(other_root_y * other_root_y == y);\n assert(result_y != other_root_y);\n}\n\n#[test]\nunconstrained fn sqrt_negative_one_test() {\n let x = 0 - 1;\n let result = sqrt(x);\n assert(result.unwrap() == 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636);\n}\n\n#[test]\nunconstrained fn validate_sqrt_hint_valid_test() {\n // 4 is a valid sqrt of 16\n validate_sqrt_hint(16, 4);\n // -4 is also a valid sqrt of 16\n validate_sqrt_hint(16, 0 - 4);\n // 0 is a valid sqrt of 0\n validate_sqrt_hint(0, 0);\n // 1 is a valid sqrt of 1\n validate_sqrt_hint(1, 1);\n // -1 is also a valid sqrt of 1\n validate_sqrt_hint(1, 0 - 1);\n}\n\n#[test(should_fail_with = \"is not the sqrt of x\")]\nunconstrained fn validate_sqrt_hint_invalid_test() {\n // 5 is not a valid sqrt of 16\n validate_sqrt_hint(16, 5);\n}\n\n#[test]\nunconstrained fn validate_not_sqrt_hint_valid_test() {\n // 5 (KNOWN_NON_RESIDUE) is not a square.\n let x = KNOWN_NON_RESIDUE;\n let hint = tonelli_shanks_sqrt(x * KNOWN_NON_RESIDUE);\n validate_not_sqrt_hint(x, hint);\n}\n\n#[test(should_fail_with = \"0 has a square root\")]\nunconstrained fn validate_not_sqrt_hint_zero_test() {\n // 0 has a square root, so we cannot claim it is not square\n validate_not_sqrt_hint(0, 0);\n}\n\n#[test(should_fail_with = \"does not demonstrate that\")]\nunconstrained fn validate_not_sqrt_hint_wrong_hint_test() {\n // Provide a wrong hint for a non-square\n let x = KNOWN_NON_RESIDUE;\n validate_not_sqrt_hint(x, 123);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr","function_locations":[{"start":79,"name":"field_from_bytes"},{"start":553,"name":"field_from_bytes_32_trunc"},{"start":1054,"name":"min"},{"start":1899,"name":"pow"},{"start":2233,"name":"sqrt"},{"start":2915,"name":"is_square"},{"start":3343,"name":"tonelli_shanks_sqrt"},{"start":3951,"name":"__sqrt"},{"start":4795,"name":"validate_sqrt_hint"},{"start":4932,"name":"validate_not_sqrt_hint"},{"start":6570,"name":"bytes_field_test"},{"start":7553,"name":"max_field_test"},{"start":8177,"name":"sqrt_valid_test"},{"start":8379,"name":"sqrt_invalid_test"},{"start":8548,"name":"sqrt_zero_test"},{"start":8685,"name":"sqrt_one_test"},{"start":8854,"name":"field_from_bytes_empty_test"},{"start":9107,"name":"field_from_bytes_little_endian_test"},{"start":9492,"name":"pow_test"},{"start":9715,"name":"min_test"},{"start":9889,"name":"sqrt_has_two_roots_test"},{"start":10562,"name":"sqrt_negative_one_test"},{"start":10768,"name":"validate_sqrt_hint_valid_test"},{"start":11199,"name":"validate_sqrt_hint_invalid_test"},{"start":11331,"name":"validate_not_sqrt_hint_valid_test"},{"start":11611,"name":"validate_not_sqrt_hint_zero_test"},{"start":11828,"name":"validate_not_sqrt_hint_wrong_hint_test"}]},"409":{"source":"pub struct Reader {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Reader {\n pub fn new(data: [Field; N]) -> Self {\n Self { data, offset: 0 }\n }\n\n pub fn read(&mut self) -> Field {\n let result = self.data[self.offset];\n self.offset += 1;\n result\n }\n\n pub fn read_u32(&mut self) -> u32 {\n self.read() as u32\n }\n\n pub fn read_u64(&mut self) -> u64 {\n self.read() as u64\n }\n\n pub fn read_bool(&mut self) -> bool {\n self.read() != 0\n }\n\n pub fn read_array(&mut self) -> [Field; K] {\n let mut result = [0; K];\n for i in 0..K {\n result[i] = self.data[self.offset + i];\n }\n self.offset += K;\n result\n }\n\n pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T {\n let result = deserialise(self.read_array());\n result\n }\n\n pub fn read_struct_array(\n &mut self,\n deserialise: fn([Field; K]) -> T,\n mut result: [T; C],\n ) -> [T; C] {\n for i in 0..C {\n result[i] = self.read_struct(deserialise);\n }\n result\n }\n\n pub fn peek_offset(&mut self, offset: u32) -> Field {\n self.data[self.offset + offset]\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) {\n assert_eq(self.offset, self.data.len(), \"Reader did not read all data\");\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/reader.nr","function_locations":[{"start":144,"name":"Reader::new"},{"start":222,"name":"Reader::read"},{"start":355,"name":"Reader::read_u32"},{"start":429,"name":"Reader::read_u64"},{"start":505,"name":"Reader::read_bool"},{"start":598,"name":"Reader::read_array"},{"start":855,"name":"Reader::read_struct"},{"start":1094,"name":"Reader::read_struct_array"},{"start":1263,"name":"Reader::peek_offset"},{"start":1362,"name":"Reader::advance_offset"},{"start":1426,"name":"Reader::finish"}]},"410":{"source":"use crate::{reader::Reader, writer::Writer};\n\n/// Trait for serializing Noir types into arrays of Fields.\n///\n/// An implementation of the Serialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait (and Deserialize) are\n/// typically used to communicate between Noir and TypeScript (via oracles and function arguments).\n///\n/// # On Following Noir's Intrinsic Serialization\n/// When calling a Noir function from TypeScript (TS), first the function arguments are serialized into an array\n/// of fields. This array is then included in the initial witness. Noir's intrinsic serialization is then used\n/// to deserialize the arguments from the witness. When the same Noir function is called from Noir this Serialize trait\n/// is used instead of the serialization in TS. For this reason we need to have a match between TS serialization,\n/// Noir's intrinsic serialization and the implementation of this trait. If there is a mismatch, the function calls\n/// fail with an arguments hash mismatch error message.\n///\n/// # Associated Constants\n/// * `N` - The length of the output Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Serialize for str {\n/// let N: u32 = N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// let bytes = self.as_bytes();\n/// for i in 0..bytes.len() {\n/// writer.write(bytes[i] as Field);\n/// }\n/// }\n/// }\n/// ```\n#[derive_via(derive_serialize)]\npub trait Serialize {\n let N: u32;\n\n fn serialize(self) -> [Field; Self::N];\n\n fn stream_serialize(self, writer: &mut Writer);\n}\n\n/// Generates a `Serialize` trait implementation for a struct type.\n///\n/// # Parameters\n/// - `s`: The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A quoted code block containing the trait implementation\n///\n/// # Example\n/// For a struct defined as:\n/// ```\n/// struct Log {\n/// fields: [Field; N],\n/// length: u32\n/// }\n/// ```\n///\n/// This function generates code equivalent to:\n/// ```\n/// impl Serialize for Log {\n/// let N: u32 = <[Field; N] as Serialize>::N + ::N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// #[inline_always]\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// Serialize::stream_serialize(self.fields, writer);\n/// Serialize::stream_serialize(self.length, writer);\n/// }\n/// }\n/// ```\npub comptime fn derive_serialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n\n // We care only about the name and type so we drop the last item of the tuple\n let params = nested_struct.0.fields(nested_struct.1).map(|(name, typ, _)| (name, typ));\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Serialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_serialize_clause = get_where_trait_clause(s, quote {Serialize});\n\n let params_len_quote = get_params_len_quote(params);\n\n let function_body = params\n .map(|(name, _typ): (Quoted, Type)| {\n quote {\n $crate::serialization::Serialize::stream_serialize(self.$name, writer);\n }\n })\n .join(quote {});\n\n quote {\n impl$generics_declarations $crate::serialization::Serialize for $typ\n $where_serialize_clause\n {\n let N: u32 = $params_len_quote;\n\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n $crate::serialization::Serialize::stream_serialize(self, &mut writer);\n writer.finish()\n }\n\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n $function_body\n }\n }\n }\n}\n\n/// Trait for deserializing Noir types from arrays of Fields.\n///\n/// An implementation of the Deserialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait is typically used when\n/// deserializing return values from function calls in Noir. Since the same function could be called from TypeScript\n/// (TS), in which case the TS deserialization would get used, we need to have a match between the 2.\n///\n/// # Associated Constants\n/// * `N` - The length of the input Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Deserialize for str {\n/// let N: u32 = M;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let mut bytes = [0 as u8; M];\n/// for i in 0..M {\n/// bytes[i] = reader.read() as u8;\n/// }\n/// str::::from(bytes)\n/// }\n/// }\n/// ```\n#[derive_via(derive_deserialize)]\npub trait Deserialize {\n let N: u32;\n\n fn deserialize(fields: [Field; Self::N]) -> Self;\n\n fn stream_deserialize(reader: &mut Reader) -> Self;\n}\n\n/// Generates a `Deserialize` trait implementation for a given struct `s`.\n///\n/// # Arguments\n/// * `s` - The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A `Quoted` block containing the generated trait implementation\n///\n/// # Requirements\n/// Each struct member type must implement the `Deserialize` trait (it gets used in the generated code).\n///\n/// # Example\n/// For a struct like:\n/// ```\n/// struct MyStruct {\n/// x: AztecAddress,\n/// y: Field,\n/// }\n/// ```\n///\n/// This generates:\n/// ```\n/// impl Deserialize for MyStruct {\n/// let N: u32 = ::N + ::N;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// #[inline_always]\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let x = ::stream_deserialize(reader);\n/// let y = ::stream_deserialize(reader);\n/// Self { x, y }\n/// }\n/// }\n/// ```\npub comptime fn derive_deserialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n let params = nested_struct.0.fields(nested_struct.1);\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Deserialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_deserialize_clause = get_where_trait_clause(s, quote {Deserialize});\n\n // The following will give us:\n // ::N + ::N + ...\n // (or 0 if the struct has no members)\n let right_hand_side_of_definition_of_n = if params.len() > 0 {\n params\n .map(|(_, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n <$param_type as $crate::serialization::Deserialize>::N\n }\n })\n .join(quote {+})\n } else {\n quote {0}\n };\n\n // For structs containing a single member, we can enhance performance by directly deserializing the input array,\n // bypassing the need for loop-based array construction. While this optimization yields significant benefits in\n // Brillig where the loops are expected to not be optimized, it is not relevant in ACIR where the loops are\n // expected to be optimized away.\n let function_body = if params.len() > 1 {\n // This generates deserialization code for each struct member and concatenates them together.\n let deserialization_of_struct_members = params\n .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n let $param_name = <$param_type as Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote {});\n\n // We join the struct member names with a comma to be used in the `Self { ... }` syntax\n // This will give us e.g. `a, b, c` for a struct with three fields named `a`, `b`, and `c`.\n let struct_members = params\n .map(|(param_name, _, _): (Quoted, Type, Quoted)| quote { $param_name })\n .join(quote {,});\n\n quote {\n $deserialization_of_struct_members\n\n Self { $struct_members }\n }\n } else if params.len() == 1 {\n let param_name = params[0].0;\n quote {\n Self { $param_name: $crate::serialization::Deserialize::stream_deserialize(reader) }\n }\n } else {\n quote {\n Self {}\n }\n };\n\n quote {\n impl$generics_declarations $crate::serialization::Deserialize for $typ\n $where_deserialize_clause\n {\n let N: u32 = $right_hand_side_of_definition_of_n;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $function_body\n }\n }\n }\n}\n\n/// Generates a quoted expression that computes the total serialized length of function parameters.\n///\n/// # Parameters\n/// * `params` - An array of tuples where each tuple contains a quoted parameter name and its Type. The type needs\n/// to implement the Serialize trait.\n///\n/// # Returns\n/// A quoted expression that evaluates to:\n/// * `0` if there are no parameters\n/// * `(::N + ::N + ...)` for one or more parameters\ncomptime fn get_params_len_quote(params: [(Quoted, Type)]) -> Quoted {\n if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::serialization::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n }\n}\n\ncomptime fn get_generics_declarations(s: TypeDefinition) -> Quoted {\n let generics = s.generics();\n\n if generics.len() > 0 {\n let generics_declarations_items = generics\n .map(|(name, maybe_integer_typ)| {\n // The second item in the generics tuple is an Option of an integer type that is Some only if\n // the generic is numeric.\n if maybe_integer_typ.is_some() {\n // The generic is numeric, so we return a quote defined as e.g. \"let N: u32\"\n let integer_type = maybe_integer_typ.unwrap();\n quote {let $name: $integer_type}\n } else {\n // The generic is not numeric, so we return a quote containing the name of the generic (e.g. \"T\")\n quote {$name}\n }\n })\n .join(quote {,});\n quote {<$generics_declarations_items>}\n } else {\n // The struct doesn't have any generics defined, so we just return an empty quote.\n quote {}\n }\n}\n\ncomptime fn get_where_trait_clause(s: TypeDefinition, trait_name: Quoted) -> Quoted {\n let generics = s.generics();\n\n // The second item in the generics tuple is an Option of an integer type that is Some only if the generic is\n // numeric.\n let non_numeric_generics =\n generics.filter(|(_, maybe_integer_typ)| maybe_integer_typ.is_none());\n\n if non_numeric_generics.len() > 0 {\n let non_numeric_generics_declarations =\n non_numeric_generics.map(|(name, _)| quote {$name: $trait_name}).join(quote {,});\n quote {where $non_numeric_generics_declarations}\n } else {\n // There are no non-numeric generics, so we return an empty quote.\n quote {}\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/serialization.nr","function_locations":[{"start":3018,"name":"derive_serialize"},{"start":7206,"name":"derive_deserialize"},{"start":10928,"name":"get_params_len_quote"},{"start":11387,"name":"get_generics_declarations"},{"start":12469,"name":"get_where_trait_clause"}]},"412":{"source":"use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};\nuse std::embedded_curve_ops::EmbeddedCurvePoint;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\nglobal BOOL_SERIALIZED_LEN: u32 = 1;\nglobal U8_SERIALIZED_LEN: u32 = 1;\nglobal U16_SERIALIZED_LEN: u32 = 1;\nglobal U32_SERIALIZED_LEN: u32 = 1;\nglobal U64_SERIALIZED_LEN: u32 = 1;\nglobal U128_SERIALIZED_LEN: u32 = 1;\nglobal FIELD_SERIALIZED_LEN: u32 = 1;\nglobal I8_SERIALIZED_LEN: u32 = 1;\nglobal I16_SERIALIZED_LEN: u32 = 1;\nglobal I32_SERIALIZED_LEN: u32 = 1;\nglobal I64_SERIALIZED_LEN: u32 = 1;\n\nimpl Serialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> bool {\n reader.read() != 0\n }\n}\n\nimpl Serialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8\n }\n}\n\nimpl Serialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16\n }\n}\n\nimpl Serialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32\n }\n}\n\nimpl Serialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64\n }\n}\n\nimpl Serialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u128\n }\n}\n\nimpl Serialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self);\n }\n}\n\nimpl Deserialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read()\n }\n}\n\nimpl Serialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u8 as Field);\n }\n}\n\nimpl Deserialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8 as i8\n }\n}\n\nimpl Serialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u16 as Field);\n }\n}\n\nimpl Deserialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16 as i16\n }\n}\n\nimpl Serialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u32 as Field);\n }\n}\n\nimpl Deserialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32 as i32\n }\n}\n\nimpl Serialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u64 as Field);\n }\n}\n\nimpl Deserialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64 as i64\n }\n}\n\nimpl Serialize for [T; M]\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n for i in 0..M {\n self[i].stream_serialize(writer);\n }\n }\n}\n\nimpl Deserialize for [T; M]\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut result: [T; M] = std::mem::zeroed();\n for i in 0..M {\n result[i] = T::stream_deserialize(reader);\n }\n result\n }\n}\n\nimpl Serialize for Option\nwhere\n T: Serialize,\n{\n let N: u32 = ::N + 1;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write_bool(self.is_some());\n if self.is_some() {\n self.unwrap_unchecked().stream_serialize(writer);\n } else {\n writer.advance_offset(::N);\n }\n }\n}\n\nimpl Deserialize for Option\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n if reader.read_bool() {\n Option::some(::stream_deserialize(reader))\n } else {\n reader.advance_offset(::N);\n Option::none()\n }\n }\n}\n\nglobal SCALAR_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurveScalar {\n\n let N: u32 = SCALAR_SIZE;\n\n fn serialize(self) -> [Field; SCALAR_SIZE] {\n [self.lo, self.hi]\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.lo);\n writer.write(self.hi);\n }\n}\n\nimpl Deserialize for EmbeddedCurveScalar {\n let N: u32 = SCALAR_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { lo: fields[0], hi: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { lo: reader.read(), hi: reader.read() }\n }\n}\n\nglobal POINT_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn serialize(self) -> [Field; Self::N] {\n [self.x, self.y]\n }\n\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.x);\n writer.write(self.y);\n }\n}\n\nimpl Deserialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { x: fields[0], y: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { x: reader.read(), y: reader.read() }\n }\n}\n\nimpl Deserialize for str {\n let N: u32 = M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);\n str::::from(u8_arr)\n }\n}\n\nimpl Serialize for str {\n let N: u32 = M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.as_bytes().stream_serialize(writer);\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Deserialize for BoundedVec\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut new_bounded_vec: BoundedVec = BoundedVec::new();\n let payload_len = Self::N - 1;\n\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n let len = reader.peek_offset(payload_len) as u32;\n\n for i in 0..M {\n if i < len {\n new_bounded_vec.push(::stream_deserialize(reader));\n }\n }\n\n // +1 for the length of the BoundedVec\n reader.advance_offset((M - len) * ::N + 1);\n\n new_bounded_vec\n }\n}\n\n// This may cause issues if used as program input, because noir disallows empty arrays for program input.\n// I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint\n// if someone does run into this in the future.\nimpl Deserialize for () {\n let N: u32 = 0;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(_reader: &mut Reader) -> Self {\n ()\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Serialize for BoundedVec\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M + 1; // +1 for the length of the BoundedVec\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.storage().stream_serialize(writer);\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n writer.write_u32(self.len() as u32);\n }\n}\n\n// Create a slice of the given length with each element made from `f(i)` where `i` is the current index\ncomptime fn make_slice(length: u32, f: fn[Env](u32) -> T) -> [T] {\n let mut slice = @[];\n for i in 0..length {\n slice = slice.push_back(f(i));\n }\n slice\n}\n\n// Implements Serialize and Deserialize for an arbitrary tuple type\ncomptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {\n // `T0`, `T1`, `T2`\n let type_names = make_slice(length, |i| f\"T{i}\".quoted_contents());\n\n // `result0`, `result1`, `result2`\n let result_names = make_slice(length, |i| f\"result{i}\".quoted_contents());\n\n // `T0, T1, T2`\n let field_generics = type_names.join(quote [,]);\n\n // `::N + ::N + ::N`\n let full_size_serialize = type_names\n .map(|type_name| quote {\n <$type_name as Serialize>::N\n })\n .join(quote [+]);\n\n // `::N + ::N + ::N`\n let full_size_deserialize = type_names\n .map(|type_name| quote {\n <$type_name as Deserialize>::N\n })\n .join(quote [+]);\n\n // `T0: Serialize, T1: Serialize, T2: Serialize,`\n let serialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Serialize,\n })\n .join(quote []);\n\n // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`\n let deserialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Deserialize,\n })\n .join(quote []);\n\n // Statements to serialize each field\n let serialized_fields = type_names\n .mapi(|i, _type_name| quote {\n $crate::serialization::Serialize::stream_serialize(self.$i, writer);\n })\n .join(quote []);\n\n // Statements to deserialize each field\n let deserialized_fields = type_names\n .mapi(|i, type_name| {\n let result_name = result_names[i];\n quote {\n let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote []);\n let deserialize_results = result_names.join(quote [,]);\n\n quote {\n impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {\n let N: u32 = $full_size_serialize;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n\n $serialized_fields\n }\n }\n\n impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {\n let N: u32 = $full_size_deserialize;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n \n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $deserialized_fields\n ($deserialize_results)\n }\n }\n }\n}\n\n// Keeping these manual impls. They are more efficient since they do not\n// require copying sub-arrays from any serialized arrays.\nimpl Serialize for (T1,)\nwhere\n T1: Serialize,\n{\n let N: u32 = ::N;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: crate::writer::Writer = crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.0.stream_serialize(writer);\n }\n}\n\nimpl Deserialize for (T1,)\nwhere\n T1: Deserialize,\n{\n let N: u32 = ::N;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n (::stream_deserialize(reader),)\n }\n}\n\n#[impl_serialize_for_tuple(2)]\n#[impl_serialize_for_tuple(3)]\n#[impl_serialize_for_tuple(4)]\n#[impl_serialize_for_tuple(5)]\n#[impl_serialize_for_tuple(6)]\nmod impls {\n use crate::serialization::{Deserialize, Serialize};\n}\n\n#[test]\nunconstrained fn bounded_vec_serialization() {\n // Test empty BoundedVec\n let empty_vec: BoundedVec = BoundedVec::from_array([]);\n let serialized = empty_vec.serialize();\n let deserialized = BoundedVec::::deserialize(serialized);\n assert_eq(empty_vec, deserialized);\n assert_eq(deserialized.len(), 0);\n\n // Test partially filled BoundedVec\n let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);\n let serialized = partial_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(partial_vec, deserialized);\n assert_eq(deserialized.len(), 1);\n assert_eq(deserialized.get(0), [1, 2]);\n\n // Test full BoundedVec\n let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);\n let serialized = full_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(full_vec, deserialized);\n assert_eq(deserialized.len(), 3);\n assert_eq(deserialized.get(0), [1, 2]);\n assert_eq(deserialized.get(1), [3, 4]);\n assert_eq(deserialized.get(2), [5, 6]);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/type_impls.nr","function_locations":[{"start":693,"name":"::serialize"},{"start":914,"name":"::stream_serialize"},{"start":1082,"name":"::deserialize"},{"start":1328,"name":"::stream_deserialize"},{"start":1470,"name":"::serialize"},{"start":1691,"name":"::stream_serialize"},{"start":1855,"name":"::deserialize"},{"start":2101,"name":"::stream_deserialize"},{"start":2246,"name":"::serialize"},{"start":2467,"name":"::stream_serialize"},{"start":2633,"name":"::deserialize"},{"start":2879,"name":"::stream_deserialize"},{"start":3025,"name":"::serialize"},{"start":3246,"name":"::stream_serialize"},{"start":3412,"name":"::deserialize"},{"start":3658,"name":"::stream_deserialize"},{"start":3804,"name":"::serialize"},{"start":4025,"name":"::stream_serialize"},{"start":4191,"name":"::deserialize"},{"start":4437,"name":"::stream_deserialize"},{"start":4585,"name":"::serialize"},{"start":4806,"name":"::stream_serialize"},{"start":4974,"name":"::deserialize"},{"start":5220,"name":"::stream_deserialize"},{"start":5371,"name":"::serialize"},{"start":5592,"name":"::stream_serialize"},{"start":5753,"name":"::deserialize"},{"start":5999,"name":"::stream_deserialize"},{"start":6136,"name":"::serialize"},{"start":6357,"name":"::stream_serialize"},{"start":6527,"name":"::deserialize"},{"start":6773,"name":"::stream_deserialize"},{"start":6924,"name":"::serialize"},{"start":7145,"name":"::stream_serialize"},{"start":7318,"name":"::deserialize"},{"start":7564,"name":"::stream_deserialize"},{"start":7717,"name":"::serialize"},{"start":7938,"name":"::stream_serialize"},{"start":8111,"name":"::deserialize"},{"start":8357,"name":"::stream_deserialize"},{"start":8510,"name":"::serialize"},{"start":8731,"name":"::stream_serialize"},{"start":8904,"name":"::deserialize"},{"start":9150,"name":"::stream_deserialize"},{"start":9350,"name":"::serialize"},{"start":9571,"name":"::stream_serialize"},{"start":9831,"name":"::deserialize"},{"start":10077,"name":"::stream_deserialize"},{"start":10389,"name":">::serialize"},{"start":10610,"name":">::stream_serialize"},{"start":10997,"name":">::deserialize"},{"start":11243,"name":">::stream_deserialize"},{"start":11621,"name":"::serialize"},{"start":11744,"name":"::stream_serialize"},{"start":11944,"name":"::deserialize"},{"start":12090,"name":"::stream_deserialize"},{"start":12297,"name":"::serialize"},{"start":12397,"name":"::stream_serialize"},{"start":12593,"name":"::deserialize"},{"start":12737,"name":"::stream_deserialize"},{"start":12916,"name":">::deserialize"},{"start":13162,"name":">::stream_deserialize"},{"start":13395,"name":">::serialize"},{"start":13616,"name":">::stream_serialize"},{"start":13997,"name":">::deserialize"},{"start":14243,"name":">::stream_deserialize"},{"start":15299,"name":"::deserialize"},{"start":15546,"name":"::stream_deserialize"},{"start":15911,"name":">::serialize"},{"start":16132,"name":">::stream_serialize"},{"start":16617,"name":"make_slice"},{"start":16867,"name":"impl_serialize_for_tuple"},{"start":20158,"name":"::serialize"},{"start":20409,"name":"::stream_serialize"},{"start":20616,"name":"::deserialize"},{"start":20877,"name":"::stream_deserialize"},{"start":21226,"name":"bounded_vec_serialization"}]},"413":{"source":"pub struct Writer {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Writer {\n pub fn new() -> Self {\n Self { data: [0; N], offset: 0 }\n }\n\n pub fn write(&mut self, value: Field) {\n self.data[self.offset] = value;\n self.offset += 1;\n }\n\n pub fn write_u32(&mut self, value: u32) {\n self.write(value as Field);\n }\n\n pub fn write_u64(&mut self, value: u64) {\n self.write(value as Field);\n }\n\n pub fn write_bool(&mut self, value: bool) {\n self.write(value as Field);\n }\n\n pub fn write_array(&mut self, value: [Field; K]) {\n for i in 0..K {\n self.data[i + self.offset] = value[i];\n }\n self.offset += K;\n }\n\n pub fn write_struct(&mut self, value: T, serialize: fn(T) -> [Field; K]) {\n self.write_array(serialize(value));\n }\n\n pub fn write_struct_array(\n &mut self,\n value: [T; C],\n serialize: fn(T) -> [Field; K],\n ) {\n for i in 0..C {\n self.write_struct(value[i], serialize);\n }\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) -> [Field; N] {\n assert_eq(self.offset, self.data.len(), \"Writer did not write all data\");\n self.data\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/writer.nr","function_locations":[{"start":128,"name":"Writer::new"},{"start":220,"name":"Writer::write"},{"start":339,"name":"Writer::write_u32"},{"start":428,"name":"Writer::write_u64"},{"start":519,"name":"Writer::write_bool"},{"start":629,"name":"Writer::write_array"},{"start":841,"name":"Writer::write_struct"},{"start":1040,"name":"Writer::write_struct_array"},{"start":1185,"name":"Writer::advance_offset"},{"start":1263,"name":"Writer::finish"}]}}} \ No newline at end of file diff --git a/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json b/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json deleted file mode 100644 index 4dd4989aa8e1..000000000000 --- a/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json +++ /dev/null @@ -1 +0,0 @@ -{"noir_version":"1.0.0-beta.20+f39ac4f5748a1ea5dc7bcb8eb5b2c2a8032a2199","name":"AuthorizeOnceBeforeExternal","functions":[{"name":"__aztec_nr_internals__foo","hash":"17058486681893845468","is_unconstrained":true,"custom_attributes":["abi_public"],"abi":{"parameters":[{"name":"from","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"},{"name":"authwit_nonce","type":{"kind":"field"},"visibility":"private"}],"return_type":null,"error_types":{"26387131971136782":{"error_kind":"string","string":"Invalid response from registry"},"7136484461999155778":{"error_kind":"string","string":"Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"},"8502498164115016271":{"error_kind":"string","string":"semantic length returned from oracle does not match data"},"9894212961085021188":{"error_kind":"string","string":"Message not authorized by account"}}},"bytecode":"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","debug_symbols":"tZndTis7DIXfpddcJLbjJLzKFkIFylalqqBuONIR4t2PzdiZKVJy6M++Ya22zFfHsZPM9GP1tHl4/32/3T+//Fnd/vpYPRy2u9329/3u5XH9tn3Zy7sfq6B/Yl3d4s0K5EUWiavbGEVBVN9GU7L3kymLJtFsWkzrpBhMlSdclOtBrkO5HoSHbJrt/WIq14NcR8E0moKpxANFlEyTKZtm02JaJ03BVHlVFEyFh/K9iUyFh/I9iU2zaTGtk3IwjabCQ+ExmpJpMhUeyXg5mxbTOmkOptEUTNGUTJOp8bLxsvGy8YrxivIkvgKmaEqmyZRNs6nyWLROWoWXQDSagimakmkyZdNsWkzrpDEEN9ENuEE35EappIbdZDfFTTUTg5voRslJDbpRMqtJ/g67yW6Km2pGe2QySi5qwA26ITfJDbvJbpRc1VQz2i6MaqIbcINuyE1yw26ym+KmmiEnk5O1lVhHob00GSVnNUrWeLSdclST3RQ31Yy21GSiG3CDbshNcuPk5OTk5ORkdjI7mZ3MTmYns5PZyexkdjI7WdsqBzXohtwoR/OjrTWZ7Ka4qWa0rbKWlvbVZNCNAjWr2lqTUaAWmzbXZIoZbausmde+mgy4UWD+/LxZ+Zp9/3bYbHTJXizisrS/rg+b/dvqdv++292s/lnv3r/+6c/rev+lb+uDfCpD3OyfRAX4vN1t1H3ezFeH/qWAIdnVgJAaQHrmCBEHiEDayBMjEHODcDliwICRixMqzUFk+vE4uLATcindcVAfgUSeCiSeU5HhiJCukAn+i5lIiB5DQsqLTOARovQRJOuaIUi6u5eJOhiFXNbGIctB7GUihtGEVJ8P7qdiHMVcFbK8lG4Ug9IkCHMuaiOks5K5GMe3ZMZBZdbohVlhHgPFn5YEhjiXBMZuSUS+MA2jsgx6BJtioDiIYZDKWGrxkpDlVa5sYXxL5jVKEy4uzXiN2oRLa/OEjAL0MgqXlucwihra0iueYzeK0cIJ1CZFfMZuQvMAQrUt4NIq3ZkdB5K0mS2QBLUbyHg0Jc0QDD0Ijqo05ValcxRQyikzU6jNjJzVezODMDxj0HzICP2OQxz1CzSGHNq6GzzS5bM7jmNmwNFa+i2O0eTK6bUxYN6iy3HL4KBQKzC0pqtzGDLlx4zB5HJoCyEHnsPAn0cxnx4rEnSjoEGRSu+jM0INfUYcLceOwMXZD76VF41qNOZ5NS50HgMQ27TyIA4anRZyW9IhLE5vPw8Da/adVmzthvE/+0I7yUrfx27f02gxhVDmFVnuMruQcoUSq5eXWAqXlliKl5fYkPHDEkt4cYkNw0hQ54U0nzeURLExGM9iYG07LVbql3rKfzUdV+m4GiHOHbe49/vWLBxGkNq2awhy6u9CBqORp0DohSq+f5BiGO0tBG1vWdxC4ilhVJ8YeQyVuycgHu34YXHITv0dfxhImvda8aV7fOHRls+5HV+48pmBILbDWMLUf7xQRs8X5kcUOZ8dSAyLQHIvkDx6YlO4ZUROmWcGQm09FD8IZLRfErRjsjy/6QcyGozcOrUVMcDiscsJ3SsX1paSgP3D9gkQ4B5kwCBsSxHhovG+7tXv5OX6cXs4+rnpU2GH7fpht7GXz+/7x8Wnb/+++if+c9Xr4eVx8/R+2Chp/s1K/vyKlW/kwHCnD+jlpbSuvMx3n/rt/wE="},{"name":"offchain_receive","hash":"16664779991078358632","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]},"visibility":"private"}],"return_type":null,"error_types":{"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"}}},"bytecode":"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","debug_symbols":"tZndbhs5DEbfxde+GFI/FPMqQVG4qbswYDiBmyywKPLuS2b0acZZSPDa7U10kniOKQ4paexfm+/7b29/fT2cfjz/3Dw8/tp8Ox+Ox8NfX4/PT7vXw/PJ/vprM/mPzGXzELY26uYh2ximOlIduY6hjrGOqY65jlLHUsfqi9UXqy9WX7LXiY3Z/q4+ch3NT+SQAPYO5CFmARSAVpAJQAAGBEAEJADMArPALDAXmAvMBeYCc4G5wFxgLjAXmAvMCrPCrDArzAqzVrNMflVyIAAD/DXZIQMEYO/Ok4NWoAlAAAYEgL07++WUABkgADeLg1bgCeBmdTBz8OA5ACIgATJAAAWgFbw2ZyAAzAHmALMXaPC0eIXOIAA3e4RepB/gVTqDX+4xR3txJAd7cXRh1AppAlgYMTowIAAiIAEyQABu9niSVsgTgABu9sByAESAm4tDBgigALSCN8gMBHCzz9QbZIYISAAzJ0+CN8gMBWDmxAbeIDMQgAEBEAEJ4GbPoTfIDAWgFbxBkifKGyR5sXmDzBAAbvZseIPMkAECKACdoXgTzeDm4sCAAIgAX+kmhwwQgC925KAVvK0yOxCAAQHgS2h2cLO/hbfVDAIoAK3gbTUDAdysDgFgZvEwvK1myAAzi7+7t9UMWsHbagYCMCAA3BwcEiADBODm6KAVvK1mIIBflRwEUAB+lc/L+2sGAng8PkHvrxkiIAEyQAAFYObi98v7awYCMMDN+f19u8Em+fX1vN/7HrnaNW0vfdmd96fXzcPp7Xjcbv7eHd8+XvTzZXf6GF93Z/uvKfen7zaa8MfhuHd63y5XT/1LabJFrF5uLNQUNF1KqC+Jvjh/KGKUJpDL67l/fUiYQZCyBFDo+llYl7VZlJK6s4h9ScocqiPZSWJRpHihSH0FZ+aqYDt8NEW+OgbbKhGD7VLdGAYKOzRJVdgsYldR+grb06vBlvJFIHr9NFoMyTacbgw0uKeBSVEVHFInl2ODtroKU+kZBoUZiWGIFPSG+2mLIxJRYugnYuBQgkJ5mUSkq2PQhA7PE8ebamoKiyL2FSSDHtWMqiKVxZEuq4oGdUlCaC+yU0JXoaNkIggtq6XGlp2rDbqsl5S6Ch6sl8wRDubUvafMoxWvrTQ0JeqHEYbFya04V10a6fKu8rAyJl2Ka+o7RqtmTG3RlJWBbisM7ReGjO5JoHZPVp36ScGDKHJKLRdJ401RUMbCafF0owiDVS+mthlLvy7CaDunzG3V0/U95UvHqD5TuyEprAzp+ii4VVZkkX4Ug+okLtjSKRD14xg4goS2D5Wp9OPIf9ZBmWLLaSYJ3V4LgxrVpMiIrmv0P45hJGFZA+2zln7Xx9HunJdDX+zemaEhtqRerF6fDKP9fQpYeuyoJP15DBwcMA9OfFMUXNr6V3K/RmV0dJ3aSm5l0p9H/g25yHfnIt+di3x/LtJ0fy5GjutyMTTcnQsLvrR5ZLqp26/ORfqzjivzme7O53BP0jaPMFjHk/6GPWlUn4KVL60fVD+fYkcHjVBwTOD1U+L/OatEaqfYtDqCflLkcO9ZJY9250nR7ZbM/p6Y0+g5MS9PmoVvdLSpmK70HXJvhQ/zeVVdjI7z3NJpX870n1dlUJz2BQdSYd9shM5D89BQuH2EYZ/U3WSQ0gxyw4O7fQUVWiJC/4l3eNbK7QSrmfJt57W1I/TrW37Djihy/woud9f30NBfwb/Yr7unw/nia8d3V50Pu2/Hff31x9vpafXf139e8B98bflyfn7af3877920fHdpPx6LfapclL9sN/b57aOdwbeZxX7zj98fi+pWJ/ry7rH8Cw=="},{"name":"public_dispatch","hash":"10014804801067860817","is_unconstrained":true,"custom_attributes":["abi_public"],"abi":{"parameters":[{"name":"selector","type":{"kind":"field"},"visibility":"private"}],"return_type":null,"error_types":{"26387131971136782":{"error_kind":"string","string":"Invalid response from registry"},"7136484461999155778":{"error_kind":"string","string":"Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"},"8502498164115016271":{"error_kind":"string","string":"semantic length returned from oracle does not match data"},"9894212961085021188":{"error_kind":"string","string":"Message not authorized by account"},"11194752367584870169":{"error_kind":"fmtstring","length":27,"item_types":[{"kind":"field"}]}}},"bytecode":"H4sIAAAAAAAA/+1bXWwUVRTen5nZ2Z3drUCjMRjCkz8PGAtGTXyiLZQiUEKpISFAxt2hbNjurrO71aImziMmJrstjSa+KP2xiqBERXjRhGBMtFVffDE8CL4YjYkmGt/Eme7OzJ37N/fuzhAa6dN0ds53zj33O+fce+ZOfLr5xoeV+nPFQu5YvlCtqLXciUjTONevF4rFwviAWiyeMf9fHC2UxovaTKM5fW1zhP4Xjfg+EmnMNBr+QM1Io2FqhO27Hi0aCwPlUrU2YywOFnQtV4sZ7w6Xatq4ps+NbdvqjwzLR7nkXx2G5SN8+oeNecuzzbSDs3RAK6q1wqQW73QkDoLAhxAxPrBsyas1daBcmXKGtAu0CQCf21uenHZvxNznW2Naj1oU4/VOt16JGPOjtXKl6bETAINmb2BhZ0Er5q9tfiy/T7/R9/Yjl/fvuGQYh448vO2XXVNXKs2BG3/P/GHBQoKDtmCEdZbagjtYBId+XKnCgjs5HHHL/IPlh/gcGV88oNXqegkzIywjeOfBn44a5/sLJVWfWn18pHIG4NLijufrarHqM0kYEpwd62PgwOLu+kRl+DhAAuE+Y9662Vy+2XXcYCJP5EOIwbEkuekIwU5wTpyZwlfdbgqNVGYd4Lnt+bwF4GoCNJwfLuVbAQEpl3hd41XuqnDUo2OOGed2lnWtMF6y0sjsJfVUTcsdUycnjuWA9NQ03tulqZXtuq5OAZ5LxJrGQuvmarGaqBS1FkFj08b5vdpEWZ8yVetatQpOOOkXcdoG8Qwcf5NnrIDu+T1lNQ8OAbwkYMpUTBHBlMFLj3svuu5VW6NvEr0hQS5tNMLD+sjFqmqlvKZzQRFTTRJJNQ7vBoy5fWWQ7ClAzEw0VlnzBIMCPNrSTNabmttbL2JFJdIcS21TLdWuIWAWRPOa9CiaMBTuknlQV62SiWYGhTxACXFsAvQkYlWS1yrMYJe/aWfxrbeFO3Jn3JHvFO7IPtx5OmTucBQ5mbeAchc5OfwiJ4dV5OQoqchFyUUuSS5/ARQ5mbPIeQoSJTi8RECeBHQo7TCCWCZTWKaEvpRSyCyTA2KZgnpeDoRlyp23lMKOlcIyBbwkYKapmOhSKg1eoit/lt3QD1t+PonJeT6icfsCpniGQvEsH8tEfopnyRTPBETxLDpFGZfikDd6QNMWzN2/ruF/FUnqelB1Pa46GqQSPGQ6eEgZdpkYXCUWA63EYniVGCAQe7IRXaGl/qKaO9lfftH4ZH+5qhXy5dLW/Zo+Ua+ZT5ZL02AJEsCUJHAYKTKX0M4SUabvzY8xZdFHVLAvYB6lKTzKhM6jDJlH6YB4lEGnKE1MRFnQNCQeswyJCJP3spQQz4Lbj8AhpeAhFZ5EJIVOICn8RCRRCUQQSgWViCQwEaUEDiOpiUjyuJC8izVRsUJ2PWoPKQ6qhbrWAi8JWq8iVqL9xN2n2OmWBmG2DMbf3RLr2eyGzGz5NjC7sxL70L0Xj/PsSVN88yHwkyEV/p40Rd2TQt4AW2FoUCkMdRKzUlMoFQiATAQPSayTIvtG/YJ3o95ozMLbauctIN/9QcL9IXwLQIzPcmzaPT0C/CP4fkLcO/pPgfZtPZczzWx1KYidhSaizOx7wi8ULruo+uqrTKv9MVo4pbE0hz2jMJE5AjrB20LtqM9D7XwsdLkejnPFOaDFfwKsmSV3kxLG+xYtnzWHWNbBDA+MjtRWagk1Iap10h+VeDpXoefWNJUHSGZKg0Rgh0yzQna70YtzGKWAWrjrXrrrOMB03vydm5kbLEzy9h6y7fc3XrkEaPkFczD5grUQUoumVWewj2Wwd7OYtz/Z5c+InSY/YzIYvB4Tz158j2F+F5ev2kcwriDZSwS5zV5ORQppZYZ1hMSVYumLw1RAYSBSU2yK+OJT1yY1vdZo8CdXkSHz4ZOrPaFXiYPxY5KAZcqXDpMOkZAFytQNIVMngJfEHauIvO8VnGNbWDu/duw8bLvie8zxIsazYhEey2Q/H37n2HaUYpvImxCDPp60xLZVS8CZWHATfpB9HyG8vo9ASVZSZ8lKYoXstrnGk60Ehq0R3T18iTdxW4aSoCRea21LS7zJ0BIv9TDj2bGnfL0xRksJLAAlGrdYAE7SZpQFoExrsLEAvEA7rMQCsJm2GmABqNKOKrAAaLSlLgtAkbauZwHI0V5FswDUUIAeLgAdBbiHC+AlFGAdF8ArcJFaT2kTbOBLWw/wl7kN5DK3PqAytwHNmeuJfb9e0DSkXvWCKYygrhdV10spgb0MVbVzSGlNWJkIHlJeEwNPBg+ZCh5SCR4yvSaszAQPmV0T0dOzJqh+z93ouRs9/4/oWUffQ/V1vjoScYfyPZ9UYho31tGFbrfrm+ClVyK40wibOjmNgLw+AyxjeoHyxONkw946/MU/uw/fup/jpILs25BPUle23XZ/NxJPwCS9vwioF51jLIByu9Wndv3dzUYuLwJaMA145x10RxND6+jHOoO0P1YB2AeEWLvt1H5acicHS/gE2NqGZWJuZNuPr0RH4Qnk7mA6pMAKJGGBuCvg0ZxyH/DcV1zTWv2llegI5BXZxbDnBxaW8dalYOtSpBi0AWEBxUcgvbTHbLsdPKGWsGqSyJykV6LPIOnHcQHnDtn22EHCLDsfVBMURhmzXf3fP+UnX35tBP3yyvZOQIoiRz7/67evfs+Gruj0yL7BLaevC6EryiVvfnvp9V/7/RXhI54YX6J3zmVCfCXdeLTZUiBlHRmOr6T7CNY6GbZO9gkXJF0kfQRS2Phy1CSQ+EqtRLW2R/8DD+VYvG5EAAA=","debug_symbols":"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"},{"name":"sync_state","hash":"8131136269561630715","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"return_type":null,"error_types":{"361444214588792908":{"error_kind":"string","string":"attempt to multiply with overflow"},"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"1064022259863234536":{"error_kind":"fmtstring","length":101,"item_types":[{"kind":"integer","sign":"unsigned","width":32}]},"1998584279744703196":{"error_kind":"string","string":"attempt to subtract with overflow"},"5421095327929394772":{"error_kind":"string","string":"attempt to bit-shift with overflow"},"5449178635769758673":{"error_kind":"fmtstring","length":61,"item_types":[{"kind":"field"},{"kind":"field"}]},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"9791669845391776238":{"error_kind":"string","string":"0 has a square root; you cannot claim it is not square"},"9885968605480832328":{"error_kind":"string","string":"Attempted to read past the length of a CapsuleArray"},"10791800398362570014":{"error_kind":"string","string":"extend_from_bounded_vec out of bounds"},"10835969307644359280":{"error_kind":"fmtstring","length":40,"item_types":[]},"11021520179822076911":{"error_kind":"string","string":"Attempted to delete past the length of a CapsuleArray"},"12820178569648940736":{"error_kind":"fmtstring","length":48,"item_types":[{"kind":"field"},{"kind":"field"}]},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"},"17110599087403377004":{"error_kind":"fmtstring","length":98,"item_types":[]},"17655676068928457687":{"error_kind":"string","string":"Reader did not read all data"}}},"bytecode":"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","debug_symbols":"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"}],"outputs":{"structs":{"functions":[{"kind":"struct","path":"AuthorizeOnceBeforeExternal::foo_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::foo_parameters","fields":[{"name":"from","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"authwit_nonce","type":{"kind":"field"}}]}}]},{"kind":"struct","path":"AuthorizeOnceBeforeExternal::offchain_receive_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::offchain_receive_parameters","fields":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]},{"kind":"struct","path":"AuthorizeOnceBeforeExternal::sync_state_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::sync_state_parameters","fields":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}]},"globals":{}},"file_map":{"3":{"source":"use crate::cmp::{Eq, Ord};\nuse crate::convert::From;\nuse crate::runtime::is_unconstrained;\n\nmod check_shuffle;\nmod quicksort;\n\nimpl [T; N] {\n /// Returns the length of this array.\n ///\n /// ```noir\n /// fn len(self) -> Field\n /// ```\n ///\n /// example\n ///\n /// ```noir\n /// fn main() {\n /// let array = [42, 42];\n /// assert(array.len() == 2);\n /// }\n /// ```\n #[builtin(array_len)]\n pub fn len(self) -> u32 {}\n\n /// Returns this array as a vector.\n ///\n /// ```noir\n /// let array = [1, 2];\n /// let vector = array.as_vector();\n /// assert_eq(vector, [1, 2].as_vector());\n /// ```\n #[builtin(as_vector)]\n pub fn as_vector(self) -> [T] {}\n\n /// Returns this array as a vector.\n /// This method is deprecated in favor of `as_vector`.\n ///\n /// ```noir\n /// let array = [1, 2];\n /// let vector = array.as_slice();\n /// assert_eq(vector, [1, 2].as_vector());\n /// ```\n #[builtin(as_vector)]\n #[deprecated(\"This method has been renamed to `as_vector`\")]\n pub fn as_slice(self) -> [T] {}\n\n /// Applies a function to each element of this array, returning a new array containing the mapped elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let b = a.map(|a| a * 2);\n /// assert_eq(b, [2, 4, 6]);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> [U; N] {\n let uninitialized = crate::mem::zeroed();\n let mut ret = [uninitialized; N];\n\n for i in 0..self.len() {\n ret[i] = f(self[i]);\n }\n\n ret\n }\n\n /// Applies a function to each element of this array along with its index,\n /// returning a new array containing the mapped elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let b = a.mapi(|i, a| i + a * 2);\n /// assert_eq(b, [2, 5, 8]);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> [U; N] {\n let uninitialized = crate::mem::zeroed();\n let mut ret = [uninitialized; N];\n\n for i in 0..self.len() {\n ret[i] = f(i, self[i]);\n }\n\n ret\n }\n\n /// Applies a function to each element of this array.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let mut b = [0; 3];\n /// let mut i = 0;\n /// a.for_each(|x| {\n /// b[i] = x;\n /// i += 1;\n /// });\n /// assert_eq(a, b);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n for i in 0..self.len() {\n f(self[i]);\n }\n }\n\n /// Applies a function to each element of this array along with its index.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let mut b = [0; 3];\n /// a.for_eachi(|i, x| {\n /// b[i] = x;\n /// });\n /// assert_eq(a, b);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n for i in 0..self.len() {\n f(i, self[i]);\n }\n }\n\n /// Applies a function to each element of the array, returning the final accumulated value. The first\n /// parameter is the initial value.\n ///\n /// This is a left fold, so the given function will be applied to the accumulator and first element of\n /// the array, then the second, and so on. For a given call the expected result would be equivalent to:\n ///\n /// ```rust\n /// let a1 = [1];\n /// let a2 = [1, 2];\n /// let a3 = [1, 2, 3];\n ///\n /// let f = |a, b| a - b;\n /// a1.fold(10, f); //=> f(10, 1)\n /// a2.fold(10, f); //=> f(f(10, 1), 2)\n /// a3.fold(10, f); //=> f(f(f(10, 1), 2), 3)\n ///\n /// assert_eq(a3.fold(10, f), 10 - 1 - 2 - 3);\n /// ```\n pub fn fold(&self, mut accumulator: U, f: fn[Env](U, T) -> U) -> U {\n for elem in self {\n accumulator = f(accumulator, elem);\n }\n accumulator\n }\n\n /// Same as fold, but uses the first element as the starting element.\n ///\n /// Requires the input array to be non-empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [1, 2, 3, 4];\n /// let reduced = arr.reduce(|a, b| a + b);\n /// assert(reduced == 10);\n /// }\n /// ```\n pub fn reduce(&self, f: fn[Env](T, T) -> T) -> T {\n let mut accumulator = self[0];\n for i in 1..self.len() {\n accumulator = f(accumulator, self[i]);\n }\n accumulator\n }\n\n /// Returns true if all the elements in this array satisfy the given predicate.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [2, 2, 2, 2, 2];\n /// let all = arr.all(|a| a == 2);\n /// assert(all);\n /// }\n /// ```\n pub fn all(&self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = true;\n for elem in self {\n ret &= predicate(elem);\n }\n ret\n }\n\n /// Returns true if any of the elements in this array satisfy the given predicate.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [2, 2, 2, 2, 5];\n /// let any = arr.any(|a| a == 5);\n /// assert(any);\n /// }\n /// ```\n pub fn any(&self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n for elem in self {\n ret |= predicate(elem);\n }\n ret\n }\n\n /// Concatenates this array with another array.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr1 = [1, 2, 3, 4];\n /// let arr2 = [6, 7, 8, 9, 10, 11];\n /// let concatenated_arr = arr1.concat(arr2);\n /// assert(concatenated_arr == [1, 2, 3, 4, 6, 7, 8, 9, 10, 11]);\n /// }\n /// ```\n pub fn concat(&self, array2: [T; M]) -> [T; N + M] {\n let mut result = [crate::mem::zeroed(); N + M];\n for i in 0..N {\n result[i] = self[i];\n }\n for i in 0..M {\n result[i + N] = array2[i];\n }\n result\n }\n}\n\nimpl [T; N]\nwhere\n T: Ord + Eq,\n{\n /// Returns a new sorted array. The original array remains untouched. Notice that this function will\n /// only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting\n /// logic it uses internally is optimized specifically for these values. If you need a sort function to\n /// sort any type, you should use the [`Self::sort_via`] function.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let arr = [42, 32];\n /// let sorted = arr.sort();\n /// assert(sorted == [32, 42]);\n /// }\n /// ```\n pub fn sort(&self) -> Self {\n self.sort_via(|a, b| a <= b)\n }\n}\n\nimpl [T; N]\nwhere\n T: Eq,\n{\n /// Returns a new sorted array by sorting it with a custom comparison function.\n /// The original array remains untouched.\n /// The ordering function must return true if the first argument should be sorted to be before the second argument or is equal to the second argument.\n ///\n /// Using this method with an operator like `<` that does not return `true` for equal values will result in an assertion failure for arrays with equal elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let arr = [42, 32]\n /// let sorted_ascending = arr.sort_via(|a, b| a <= b);\n /// assert(sorted_ascending == [32, 42]); // verifies\n ///\n /// let sorted_descending = arr.sort_via(|a, b| a >= b);\n /// assert(sorted_descending == [32, 42]); // does not verify\n /// }\n /// ```\n pub fn sort_via(&self, ordering: fn[Env](T, T) -> bool) -> Self {\n // Safety: `sorted` array is checked to be:\n // a. a permutation of `input`'s elements\n // b. satisfying the predicate `ordering`\n let sorted = unsafe { quicksort::quicksort(self, ordering) };\n\n if !is_unconstrained() {\n for i in 0..N - 1 {\n assert(\n ordering(sorted[i], sorted[i + 1]),\n \"Array has not been sorted correctly according to `ordering`.\",\n );\n }\n check_shuffle::check_shuffle(self, &sorted);\n }\n sorted\n }\n}\n\nimpl [u8; N] {\n /// Converts a byte array of type `[u8; N]` to a string. Note that this performs no UTF-8 validation -\n /// the given array is interpreted as-is as a string.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let hi = [104, 105].as_str_unchecked();\n /// assert_eq(hi, \"hi\");\n /// }\n /// ```\n #[builtin(array_as_str_unchecked)]\n pub fn as_str_unchecked(self) -> str {}\n}\n\nimpl From> for [u8; N] {\n /// Returns an array of the string bytes.\n fn from(s: str) -> Self {\n s.as_bytes()\n }\n}\n\nmod test {\n #[test]\n fn map_empty() {\n assert_eq([].map(|x| x + 1), []);\n }\n\n global arr_with_100_values: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2, 54,\n 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41, 19, 98,\n 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21, 43, 86, 35,\n 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15, 127, 81, 30, 8,\n 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n global expected_with_100_values: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30, 32,\n 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58, 61, 62,\n 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82, 84, 84, 86,\n 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114, 114, 116, 118,\n 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n fn sort_u32(a: u32, b: u32) -> bool {\n a <= b\n }\n\n #[test]\n fn test_sort() {\n let arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = arr.sort();\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_100_values() {\n let arr: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2,\n 54, 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41,\n 19, 98, 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21,\n 43, 86, 35, 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15,\n 127, 81, 30, 8, 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n\n let sorted = arr.sort();\n\n let expected: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30,\n 32, 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58,\n 61, 62, 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82,\n 84, 84, 86, 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114,\n 114, 116, 118, 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_100_values_comptime() {\n let sorted = arr_with_100_values.sort();\n assert(sorted == expected_with_100_values);\n }\n\n #[test]\n fn test_sort_via() {\n let arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = arr.sort_via(sort_u32);\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_via_100_values() {\n let arr: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2,\n 54, 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41,\n 19, 98, 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21,\n 43, 86, 35, 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15,\n 127, 81, 30, 8, 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n\n let sorted = arr.sort_via(sort_u32);\n\n let expected: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30,\n 32, 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58,\n 61, 62, 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82,\n 84, 84, 86, 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114,\n 114, 116, 118, 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n assert(sorted == expected);\n }\n\n #[test]\n fn mapi_empty() {\n assert_eq([].mapi(|i, x| i * x + 1), []);\n }\n\n #[test]\n fn for_each_empty() {\n let empty_array: [Field; 0] = [];\n empty_array.for_each(|_x| assert(false));\n }\n\n #[test]\n fn for_eachi_empty() {\n let empty_array: [Field; 0] = [];\n empty_array.for_eachi(|_i, _x| assert(false));\n }\n\n #[test]\n fn map_example() {\n let a = [1, 2, 3];\n let b = a.map(|a| a * 2);\n assert_eq(b, [2, 4, 6]);\n }\n\n #[test]\n fn mapi_example() {\n let a = [1, 2, 3];\n let b = a.mapi(|i, a| i + a * 2);\n assert_eq(b, [2, 5, 8]);\n }\n\n #[test]\n fn for_each_example() {\n let a = [1, 2, 3];\n let mut b = [0, 0, 0];\n let b_ref = &mut b;\n let mut i = 0;\n let i_ref = &mut i;\n a.for_each(|x| {\n b_ref[*i_ref] = x * 2;\n *i_ref += 1;\n });\n assert_eq(b, [2, 4, 6]);\n assert_eq(i, 3);\n }\n\n #[test]\n fn for_eachi_example() {\n let a = [1, 2, 3];\n let mut b = [0, 0, 0];\n let b_ref = &mut b;\n a.for_eachi(|i, a| { b_ref[i] = i + a * 2; });\n assert_eq(b, [2, 5, 8]);\n }\n\n #[test]\n fn concat() {\n let arr1 = [1, 2, 3, 4];\n let arr2 = [6, 7, 8, 9, 10, 11];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1, 2, 3, 4, 6, 7, 8, 9, 10, 11]);\n }\n\n #[test]\n fn concat_zero_length_with_something() {\n let arr1 = [];\n let arr2 = [1];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1]);\n }\n\n #[test]\n fn concat_something_with_zero_length() {\n let arr1 = [1];\n let arr2 = [];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1]);\n }\n\n #[test]\n fn concat_zero_lengths() {\n let arr1: [Field; 0] = [];\n let arr2: [Field; 0] = [];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, []);\n }\n}\n","path":"std/array/mod.nr","function_locations":[{"start":480,"name":"[T; N]::len"},{"start":735,"name":"[T; N]::as_vector"},{"start":1112,"name":"[T; N]::as_slice"},{"start":1443,"name":"[T; N]::map"},{"start":2004,"name":"[T; N]::mapi"},{"start":2552,"name":"[T; N]::for_each"},{"start":2970,"name":"[T; N]::for_eachi"},{"start":3837,"name":"[T; N]::fold"},{"start":4355,"name":"[T; N]::reduce"},{"start":4865,"name":"[T; N]::all"},{"start":5338,"name":"[T; N]::any"},{"start":5881,"name":"[T; N]::concat"},{"start":6778,"name":"[T; N]::sort"},{"start":7794,"name":"[T; N]::sort_via"},{"start":8823,"name":"[u8; N]::as_str_unchecked"},{"start":8950,"name":"> for [u8; N]>::from"},{"start":9024,"name":"test::map_empty"},{"start":10134,"name":"test::sort_u32"},{"start":10189,"name":"test::test_sort"},{"start":10420,"name":"test::test_sort_100_values"},{"start":11588,"name":"test::test_sort_100_values_comptime"},{"start":11733,"name":"test::test_sort_via"},{"start":11980,"name":"test::test_sort_via_100_values"},{"start":13141,"name":"test::mapi_empty"},{"start":13236,"name":"test::for_each_empty"},{"start":13374,"name":"test::for_eachi_empty"},{"start":13513,"name":"test::map_example"},{"start":13650,"name":"test::mapi_example"},{"start":13799,"name":"test::for_each_example"},{"start":14139,"name":"test::for_eachi_example"},{"start":14350,"name":"test::concat"},{"start":14609,"name":"test::concat_zero_length_with_something"},{"start":14812,"name":"test::concat_something_with_zero_length"},{"start":15001,"name":"test::concat_zero_lengths"}]},"5":{"source":"use crate::meta::ctstring::AsCtString;\nuse crate::meta::derive_via;\n\n/// Compare two values for equality\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n if result {\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\ncomptime fn make_tuple_eq_body(n: u32) -> Quoted {\n let mut body = f\"self.0.eq(other.0)\".as_ctstring();\n for i in 1u32..n {\n body = body.append_fmtstr(f\" & self.{i}.eq(other.{i})\");\n }\n f\"{body}\".quoted_contents()\n}\n\nimpl Eq for (A, B) {\n fn eq(self, other: (A, B)) -> bool {\n make_tuple_eq_body!(2u32)\n }\n}\n\nimpl Eq for (A, B, C) {\n fn eq(self, other: (A, B, C)) -> bool {\n make_tuple_eq_body!(3u32)\n }\n}\n\nimpl Eq for (A, B, C, D) {\n fn eq(self, other: (A, B, C, D)) -> bool {\n make_tuple_eq_body!(4u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E) {\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n make_tuple_eq_body!(5u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F) {\n fn eq(self, other: (A, B, C, D, E, F)) -> bool {\n make_tuple_eq_body!(6u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G) {\n fn eq(self, other: (A, B, C, D, E, F, G)) -> bool {\n make_tuple_eq_body!(7u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H) {\n fn eq(self, other: (A, B, C, D, E, F, G, H)) -> bool {\n make_tuple_eq_body!(8u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I)) -> bool {\n make_tuple_eq_body!(9u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J)) -> bool {\n make_tuple_eq_body!(10u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J, K) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> bool {\n make_tuple_eq_body!(11u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> bool {\n make_tuple_eq_body!(12u32)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\n/// A value with three states: `Ordering::less()`, `Ordering::equal()` or `Ordering::greater()`.\n/// Most often used to encode the result of a comparison operation.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n/// Compare one object to another, returning whether it is less-than, equal-to,\n/// or greater-than the other object.\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let self_len = self.len();\n let other_len = other.len();\n let min_len = if self_len < other_len {\n self_len\n } else {\n other_len\n };\n\n let mut result = Ordering::equal();\n for i in 0..min_len {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n\n if result != Ordering::equal() {\n result\n } else {\n self_len.cmp(other_len)\n }\n }\n}\n\ncomptime fn make_tuple_ord_body(n: u32) -> Quoted {\n let last = n - 1u32;\n let mut body = if last == 1 {\n f\"let result = self.0.cmp(other.0);\".as_ctstring()\n } else {\n f\"let mut result = self.0.cmp(other.0);\".as_ctstring()\n };\n for i in 1u32..last {\n body = body.append_fmtstr(\n f\" if result == Ordering::equal() {{ result = self.{i}.cmp(other.{i}); }}\",\n );\n }\n body = body.append_fmtstr(\n f\" if result != Ordering::equal() {{ result }} else {{ self.{last}.cmp(other.{last}) }}\",\n );\n f\"{body}\".quoted_contents()\n}\n\nimpl Ord for (A, B) {\n fn cmp(self, other: (A, B)) -> Ordering {\n make_tuple_ord_body!(2u32)\n }\n}\n\nimpl Ord for (A, B, C) {\n fn cmp(self, other: (A, B, C)) -> Ordering {\n make_tuple_ord_body!(3u32)\n }\n}\n\nimpl Ord for (A, B, C, D) {\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n make_tuple_ord_body!(4u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E) {\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n make_tuple_ord_body!(5u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F) {\n fn cmp(self, other: (A, B, C, D, E, F)) -> Ordering {\n make_tuple_ord_body!(6u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G) {\n fn cmp(self, other: (A, B, C, D, E, F, G)) -> Ordering {\n make_tuple_ord_body!(7u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H)) -> Ordering {\n make_tuple_ord_body!(8u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I)) -> Ordering {\n make_tuple_ord_body!(9u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J)) -> Ordering {\n make_tuple_ord_body!(10u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J, K) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> Ordering {\n make_tuple_ord_body!(11u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> Ordering {\n make_tuple_ord_body!(12u32)\n }\n}\n\n/// Compares and returns the maximum of two values.\n///\n/// Returns the second argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::max(1, 2), 2);\n/// assert_eq(cmp::max(2, 2), 2);\n/// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n/// Compares and returns the minimum of two values.\n///\n/// Returns the first argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::min(1, 2), 1);\n/// assert_eq(cmp::min(2, 2), 2);\n/// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use super::{Eq, max, min, Ord};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n\n #[test]\n fn correctly_handles_unequal_length_vectors() {\n let vector_1 = [0, 1, 2, 3].as_vector();\n let vector_2 = [0, 1, 2].as_vector();\n assert(!vector_1.eq(vector_2));\n }\n\n #[test]\n fn lexicographic_ordering_for_vectors() {\n assert(\n [2_u32].as_vector().cmp([1_u32, 1_u32, 1_u32].as_vector())\n == super::Ordering::greater(),\n );\n assert(\n [1_u32, 2_u32].as_vector().cmp([1_u32, 2_u32, 3_u32].as_vector())\n == super::Ordering::less(),\n );\n }\n}\n","path":"std/cmp.nr","function_locations":[{"start":305,"name":"derive_eq"},{"start":851,"name":"::eq"},{"start":940,"name":"::eq"},{"start":1026,"name":"::eq"},{"start":1112,"name":"::eq"},{"start":1198,"name":"::eq"},{"start":1282,"name":"::eq"},{"start":1366,"name":"::eq"},{"start":1452,"name":"::eq"},{"start":1538,"name":"::eq"},{"start":1624,"name":"::eq"},{"start":1717,"name":"::eq"},{"start":1796,"name":"::eq"},{"start":1921,"name":"::eq"},{"start":2139,"name":"::eq"},{"start":2418,"name":">::eq"},{"start":2598,"name":"make_tuple_eq_body"},{"start":2859,"name":"::eq"},{"start":2991,"name":"::eq"},{"start":3136,"name":"::eq"},{"start":3294,"name":"::eq"},{"start":3465,"name":"::eq"},{"start":3649,"name":"::eq"},{"start":3846,"name":"::eq"},{"start":4056,"name":"::eq"},{"start":4279,"name":"::eq"},{"start":4516,"name":"::eq"},{"start":4766,"name":"::eq"},{"start":4876,"name":"::eq"},{"start":5477,"name":"Ordering::less"},{"start":5548,"name":"Ordering::equal"},{"start":5621,"name":"Ordering::greater"},{"start":5992,"name":"derive_ord"},{"start":6642,"name":"::cmp"},{"start":6889,"name":"::cmp"},{"start":7137,"name":"::cmp"},{"start":7385,"name":"::cmp"},{"start":7631,"name":"::cmp"},{"start":7877,"name":"::cmp"},{"start":8125,"name":"::cmp"},{"start":8373,"name":"::cmp"},{"start":8621,"name":"::cmp"},{"start":8875,"name":"::cmp"},{"start":8974,"name":"::cmp"},{"start":9444,"name":"::cmp"},{"start":9847,"name":"::cmp"},{"start":10415,"name":"make_tuple_ord_body"},{"start":11037,"name":"::cmp"},{"start":11179,"name":"::cmp"},{"start":11335,"name":"::cmp"},{"start":11505,"name":"::cmp"},{"start":11689,"name":"::cmp"},{"start":11887,"name":"::cmp"},{"start":12099,"name":"::cmp"},{"start":12325,"name":"::cmp"},{"start":12565,"name":"::cmp"},{"start":12820,"name":"::cmp"},{"start":13089,"name":"::cmp"},{"start":13451,"name":"max"},{"start":13828,"name":"min"},{"start":13982,"name":"cmp_tests::sanity_check_min"},{"start":14178,"name":"cmp_tests::sanity_check_max"},{"start":14400,"name":"cmp_tests::correctly_handles_unequal_length_vectors"},{"start":14600,"name":"cmp_tests::lexicographic_ordering_for_vectors"}]},"6":{"source":"use crate::{cmp::Eq, convert::From, runtime::is_unconstrained, static_assert};\n\n/// A `BoundedVec` is a growable storage similar to a built-in vector except that it\n/// is bounded with a maximum possible length. `BoundedVec` is also not\n/// subject to the same restrictions vectors are (notably, nested vectors are disallowed).\n///\n/// Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by\n/// pushing an additional element is also more efficient - the length only needs to be increased\n/// by one.\n///\n/// For these reasons `BoundedVec` should generally be preferred over vectors when there\n/// is a reasonable maximum bound that can be placed on the vector.\n///\n/// Example:\n///\n/// ```noir\n/// let mut vector: BoundedVec = BoundedVec::new();\n/// for i in 0..5 {\n/// vector.push(i);\n/// }\n/// assert(vector.len() == 5);\n/// assert(vector.max_len() == 10);\n/// ```\npub struct BoundedVec {\n storage: [T; MaxLen],\n len: u32,\n}\n\nimpl BoundedVec {\n /// Creates a new, empty vector of length zero.\n ///\n /// Since this container is backed by an array internally, it still needs an initial value\n /// to give each element. To resolve this, each element is zeroed internally. This value\n /// is guaranteed to be inaccessible unless `get_unchecked` is used.\n ///\n /// Example:\n ///\n /// ```noir\n /// let empty_vector: BoundedVec = BoundedVec::new();\n /// assert(empty_vector.len() == 0);\n /// ```\n ///\n /// Note that whenever calling `new` the maximum length of the vector should always be specified\n /// via a type signature:\n ///\n /// ```noir\n /// fn good() -> BoundedVec {\n /// // Ok! MaxLen is specified with a type annotation\n /// let v1: BoundedVec = BoundedVec::new();\n /// let v2 = BoundedVec::new();\n ///\n /// // Ok! MaxLen is known from the type of `good`'s return value\n /// v2\n /// }\n ///\n /// fn bad() {\n /// // Error: Type annotation needed\n /// // The compiler can't infer `MaxLen` from the following code:\n /// let mut v3 = BoundedVec::new();\n /// v3.push(5);\n /// }\n /// ```\n ///\n /// This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions\n /// but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a\n /// constraint failure at runtime when the vec is pushed to.\n pub fn new() -> Self {\n let zeroed = crate::mem::zeroed();\n BoundedVec { storage: [zeroed; MaxLen], len: 0 }\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this\n /// will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// let last = v.get(v.len() - 1);\n /// assert(first != last);\n /// }\n /// ```\n pub fn get(&self, index: u32) -> T {\n assert(index < self.len, \"Attempted to read past end of BoundedVec\");\n self.get_unchecked(index)\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero, without\n /// performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element,\n /// it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn sum_of_first_three(v: BoundedVec) -> u32 {\n /// // Always ensure the length is larger than the largest\n /// // index passed to get_unchecked\n /// assert(v.len() > 2);\n /// let first = v.get_unchecked(0);\n /// let second = v.get_unchecked(1);\n /// let third = v.get_unchecked(2);\n /// first + second + third\n /// }\n /// ```\n pub fn get_unchecked(&self, index: u32) -> T {\n self.storage[index]\n }\n\n /// Writes an element to the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// assert(first != 42);\n /// v.set(0, 42);\n /// let new_first = v.get(0);\n /// assert(new_first == 42);\n /// }\n /// ```\n pub fn set(&mut self, index: u32, value: T) {\n assert(index < self.len, \"Attempted to write past end of BoundedVec\");\n self.set_unchecked(index, value)\n }\n\n /// Writes an element to the vector at the given index, starting from zero, without performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element, it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn set_unchecked_example() {\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([1, 2]);\n ///\n /// // Here we're safely writing within the valid range of `vec`\n /// // `vec` now has the value [42, 2]\n /// vec.set_unchecked(0, 42);\n ///\n /// // We can then safely read this value back out of `vec`.\n /// // Notice that we use the checked version of `get` which would prevent reading unsafe values.\n /// assert_eq(vec.get(0), 42);\n ///\n /// // We've now written past the end of `vec`.\n /// // As this index is still within the maximum potential length of `v`,\n /// // it won't cause a constraint failure.\n /// vec.set_unchecked(2, 42);\n /// println(vec);\n ///\n /// // This will write past the end of the maximum potential length of `vec`,\n /// // it will then trigger a constraint failure.\n /// vec.set_unchecked(5, 42);\n /// println(vec);\n /// }\n /// ```\n pub fn set_unchecked(&mut self, index: u32, value: T) {\n self.storage[index] = value;\n }\n\n /// Pushes an element to the end of the vector. This increases the length\n /// of the vector by one.\n ///\n /// Panics if the new length of the vector will be greater than the max length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// v.push(1);\n /// v.push(2);\n ///\n /// // Panics with failed assertion \"push out of bounds\"\n /// v.push(3);\n /// ```\n pub fn push(&mut self, elem: T) {\n assert(self.len < MaxLen, \"push out of bounds\");\n\n self.storage[self.len] = elem;\n self.len += 1;\n }\n\n /// Returns the current length of this vector\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// assert(v.len() == 0);\n ///\n /// v.push(100);\n /// assert(v.len() == 1);\n ///\n /// v.push(200);\n /// v.push(300);\n /// v.push(400);\n /// assert(v.len() == 4);\n ///\n /// let _ = v.pop();\n /// let _ = v.pop();\n /// assert(v.len() == 2);\n /// ```\n pub fn len(&self) -> u32 {\n self.len\n }\n\n /// Returns the maximum length of this vector. This is always\n /// equal to the `MaxLen` parameter this vector was initialized with.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.max_len() == 5);\n /// v.push(10);\n /// assert(v.max_len() == 5);\n /// ```\n pub fn max_len(_self: &BoundedVec) -> u32 {\n MaxLen\n }\n\n /// Returns the internal array within this vector.\n ///\n /// Since arrays in Noir are immutable, mutating the returned storage array will not mutate\n /// the storage held internally by this vector.\n ///\n /// Note that uninitialized elements may be zeroed out!\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.storage() == [0, 0, 0, 0, 0]);\n ///\n /// v.push(57);\n /// assert(v.storage() == [57, 0, 0, 0, 0]);\n /// ```\n pub fn storage(self) -> [T; MaxLen] {\n self.storage\n }\n\n /// Pushes each element from the given array to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([2, 4]);\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_array(&mut self, array: [T; Len]) {\n let new_len = self.len + array.len();\n assert(new_len <= MaxLen, \"extend_from_array out of bounds\");\n for i in 0..array.len() {\n self.storage[self.len + i] = array[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the given vector to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_vector([2, 4].as_vector());\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_vector(&mut self, vector: [T]) {\n let new_len = self.len + vector.len();\n assert(new_len <= MaxLen, \"extend_from_vector out of bounds\");\n for i in 0..vector.len() {\n self.storage[self.len + i] = vector[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the other vector to this vector. The length of\n /// the other vector is left unchanged.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// ```noir\n /// let mut v1: BoundedVec = BoundedVec::new();\n /// let mut v2: BoundedVec = BoundedVec::new();\n ///\n /// v2.extend_from_array([1, 2, 3]);\n /// v1.extend_from_bounded_vec(v2);\n ///\n /// assert(v1.storage() == [1, 2, 3, 0, 0]);\n /// assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]);\n /// ```\n pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) {\n let append_len = vec.len();\n let new_len = self.len + append_len;\n assert(new_len <= MaxLen, \"extend_from_bounded_vec out of bounds\");\n\n if is_unconstrained() {\n for i in 0..append_len {\n self.storage[self.len + i] = vec.get_unchecked(i);\n }\n } else {\n // The source vector can be longer than the destination, or vice versa;\n // regardless we will only ever be able to read or write whichever is\n // the shorter max length of the two. We asserted that the actual content fits,\n // but the capacity of the source vector could be higher.\n let max = crate::cmp::min(Len, MaxLen);\n\n // Save the last item in case we have to do a fixup on an already full array.\n let last = if MaxLen > 0 {\n self.storage[MaxLen - 1]\n } else {\n crate::mem::zeroed()\n };\n\n for src in 0..max {\n // Since we are iterating to the static capacity of the arrays,\n // the destination could be out of bounds. If that's the case,\n // overwrite the last item, which we'll fixup in the end.\n // NB using cmp::min resulted in more opcodes here.\n let mut dst = self.len + src;\n if dst >= MaxLen { dst = MaxLen - 1; };\n // Assigning the source or zeroed to avoid having to merge arrays in SSA.\n self.storage[dst] = if src < append_len {\n vec.get_unchecked(src)\n } else {\n last\n }\n }\n\n // Fixup the last item if we have to.\n if MaxLen > 0 {\n self.storage[MaxLen - 1] = if (self.len + append_len == MaxLen) & (append_len > 0) {\n vec.get_unchecked(append_len - 1)\n } else {\n last\n }\n }\n }\n self.len = new_len;\n }\n\n /// Creates a new vector, populating it with values derived from an array input.\n /// The maximum length of the vector is determined based on the type signature.\n ///\n /// Example:\n ///\n /// ```noir\n /// let bounded_vec: BoundedVec = BoundedVec::from_array([1, 2, 3])\n /// ```\n pub fn from_array(array: [T; Len]) -> Self {\n static_assert(Len <= MaxLen, \"from array out of bounds\");\n let mut vec: BoundedVec = BoundedVec::new();\n vec.extend_from_array(array);\n vec\n }\n\n /// Pops the element at the end of the vector. This will decrease the length\n /// of the vector by one.\n ///\n /// Panics if the vector is empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.push(1);\n /// v.push(2);\n ///\n /// let two = v.pop();\n /// let one = v.pop();\n ///\n /// assert(two == 2);\n /// assert(one == 1);\n ///\n /// // error: cannot pop from an empty vector\n /// let _ = v.pop();\n /// ```\n pub fn pop(&mut self) -> T {\n assert(self.len > 0, \"cannot pop from an empty vector\");\n self.len -= 1;\n\n let elem = self.storage[self.len];\n self.storage[self.len] = crate::mem::zeroed();\n elem\n }\n\n /// Returns true if the given predicate returns true for any element\n /// in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.extend_from_array([2, 4, 6]);\n ///\n /// let all_even = !v.any(|elem: u32| elem % 2 != 0);\n /// assert(all_even);\n /// ```\n pub fn any(self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n if is_unconstrained() {\n for i in 0..self.len {\n ret |= predicate(self.storage[i]);\n }\n } else {\n let mut exceeded_len = false;\n for i in 0..MaxLen {\n exceeded_len |= i == self.len;\n if !exceeded_len {\n ret |= predicate(self.storage[i]);\n }\n }\n }\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.map(|value| value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element\n /// in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.mapi(|i, value| i + value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(i, self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Calls a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_each(|value| result.push(value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Calls a closure on each element in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_eachi(|i, value| result.push(i + value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(i, self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function will zero out any elements at or past index `len` of `array`.\n /// This incurs an extra runtime cost of O(MaxLen). If you are sure your array is\n /// zeroed after that index, you can use [`from_parts_unchecked`][Self::from_parts_unchecked] to remove the extra loop.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n /// ```\n pub fn from_parts(mut array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n let zeroed = crate::mem::zeroed();\n\n if is_unconstrained() {\n for i in len..MaxLen {\n array[i] = zeroed;\n }\n } else {\n for i in 0..MaxLen {\n if i >= len {\n array[i] = zeroed;\n }\n }\n }\n\n BoundedVec { storage: array, len }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function is unsafe because it expects all elements past the `len` index\n /// of `array` to be zeroed, but does not check for this internally. Use `from_parts`\n /// for a safe version of this function which does zero out any indices past the\n /// given length. Invalidating this assumption can notably cause `BoundedVec::eq`\n /// to give incorrect results since it will check even elements past `len`.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n ///\n /// // invalid use!\n /// let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n /// let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n ///\n /// // both vecs have length 3 so we'd expect them to be equal, but this\n /// // fails because elements past the length are still checked in eq\n /// assert_eq(vec1, vec2); // fails\n /// ```\n pub fn from_parts_unchecked(array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n BoundedVec { storage: array, len }\n }\n}\n\nimpl Eq for BoundedVec\nwhere\n T: Eq,\n{\n fn eq(self, other: BoundedVec) -> bool {\n // TODO: https://github.com/noir-lang/noir/issues/4837\n //\n // We make the assumption that the user has used the proper interface for working with `BoundedVec`s\n // rather than directly manipulating the internal fields as this can result in an inconsistent internal state.\n if self.len == other.len {\n self.storage == other.storage\n } else {\n false\n }\n }\n}\n\nimpl From<[T; Len]> for BoundedVec {\n fn from(array: [T; Len]) -> BoundedVec {\n BoundedVec::from_array(array)\n }\n}\n\nmod bounded_vec_tests {\n\n mod get {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_elements_past_end_of_vec() {\n let vec: BoundedVec = BoundedVec::new();\n\n let _ = vec.get(0);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_beyond_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let _ = vec.get(3);\n }\n\n #[test]\n fn get_works_within_bounds() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(2), 3);\n assert_eq(vec.get(4), 5);\n }\n\n #[test]\n fn get_unchecked_works() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(0), 1);\n assert_eq(vec.get_unchecked(2), 3);\n }\n\n #[test]\n fn get_unchecked_works_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(4), 0);\n }\n }\n\n mod set {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn set_updates_values_properly() {\n let mut vec = BoundedVec::from_array([0, 0, 0, 0, 0]);\n\n vec.set(0, 42);\n assert_eq(vec.storage, [42, 0, 0, 0, 0]);\n\n vec.set(1, 43);\n assert_eq(vec.storage, [42, 43, 0, 0, 0]);\n\n vec.set(2, 44);\n assert_eq(vec.storage, [42, 43, 44, 0, 0]);\n\n vec.set(1, 10);\n assert_eq(vec.storage, [42, 10, 44, 0, 0]);\n\n vec.set(0, 0);\n assert_eq(vec.storage, [0, 10, 44, 0, 0]);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_writing_elements_past_end_of_vec() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.set(0, 42);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_setting_beyond_length() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.set(3, 4);\n }\n\n #[test]\n fn set_unchecked_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(0, 10);\n assert_eq(vec.get(0), 10);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn set_unchecked_operations_past_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(3, 40);\n assert_eq(vec.get(3), 40);\n }\n\n #[test]\n fn set_preserves_other_elements() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n vec.set(2, 30);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 30);\n assert_eq(vec.get(3), 4);\n assert_eq(vec.get(4), 5);\n }\n }\n\n mod any {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn returns_false_if_predicate_not_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, false, false]);\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn returns_true_if_predicate_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, true, true]);\n let result = vec.any(|value| value);\n\n assert(result);\n }\n\n #[test]\n fn returns_false_on_empty_boundedvec() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn any_with_complex_predicates() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n assert(vec.any(|x| x > 3));\n assert(!vec.any(|x| x > 10));\n assert(vec.any(|x| x % 2 == 0)); // has a even number\n assert(vec.any(|x| x == 3)); // has a specific value\n }\n\n #[test]\n fn any_with_partial_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n assert(vec.any(|x| x == 1));\n assert(vec.any(|x| x == 2));\n assert(!vec.any(|x| x == 3));\n }\n }\n\n mod map {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-map-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| value * 2);\n // docs:end:bounded-vec-map-example\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.map(|value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn map_with_conditional_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.map(|x| if x % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([1, 4, 3, 8]);\n assert_eq(result, expected);\n }\n\n #[test]\n fn map_preserves_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|x| x * 2);\n\n assert_eq(result.len(), vec.len());\n assert_eq(result.max_len(), vec.max_len());\n }\n\n #[test]\n fn map_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.map(|x| x * 2);\n assert_eq(result, vec);\n assert_eq(result.len(), 0);\n assert_eq(result.max_len(), 5);\n }\n }\n\n mod mapi {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-mapi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| i + value * 2);\n // docs:end:bounded-vec-mapi-example\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.mapi(|_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn mapi_with_index_branching_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.mapi(|i, x| if i % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([2, 2, 6, 4]);\n assert_eq(result, expected);\n }\n }\n\n mod for_each {\n use crate::collections::bounded_vec::BoundedVec;\n\n // map in terms of for_each\n fn for_each_map(\n input: BoundedVec,\n f: fn[Env](T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_each(|x| output_ref.push(f(x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-each-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_each(|value| { *acc_ref += value; });\n // docs:end:bounded-vec-for-each-example\n assert_eq(acc, 6);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| value * 2);\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_each_map(vec, |value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_each_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_each(|_| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_each_with_side_effects() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let mut seen = BoundedVec::::new();\n let seen_ref = &mut seen;\n vec.for_each(|x| seen_ref.push(x));\n assert_eq(seen, vec);\n }\n }\n\n mod for_eachi {\n use crate::collections::bounded_vec::BoundedVec;\n\n // mapi in terms of for_eachi\n fn for_eachi_mapi(\n input: BoundedVec,\n f: fn[Env](u32, T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_eachi(|i, x| output_ref.push(f(i, x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-eachi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_eachi(|i, value| { *acc_ref += i * value; });\n // docs:end:bounded-vec-for-eachi-example\n\n // 0 * 1 + 1 * 2 + 2 * 3\n assert_eq(acc, 8);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| i + value * 2);\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_eachi_mapi(vec, |_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_eachi_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_eachi(|_, _| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_eachi_with_index_tracking() {\n let vec: BoundedVec = BoundedVec::from_array([10, 20, 30]);\n let mut indices = BoundedVec::::new();\n let indices_ref = &mut indices;\n vec.for_eachi(|i, _| indices_ref.push(i));\n\n let expected = BoundedVec::from_array([0, 1, 2]);\n assert_eq(indices, expected);\n }\n\n }\n\n mod from_array {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty() {\n let empty_array: [Field; 0] = [];\n let bounded_vec = BoundedVec::from_array([]);\n\n assert_eq(bounded_vec.max_len(), 0);\n assert_eq(bounded_vec.len(), 0);\n assert_eq(bounded_vec.storage(), empty_array);\n }\n\n #[test]\n fn equal_len() {\n let array = [1, 2, 3];\n let bounded_vec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 3);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.storage(), array);\n }\n\n #[test]\n fn max_len_greater_then_array_len() {\n let array = [1, 2, 3];\n let bounded_vec: BoundedVec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n assert_eq(bounded_vec.get(2), 3);\n }\n\n #[test(should_fail_with = \"from array out of bounds\")]\n fn max_len_lower_then_array_len() {\n let _: BoundedVec = BoundedVec::from_array([0; 3]);\n }\n\n #[test]\n fn from_array_preserves_order() {\n let array = [5, 3, 1, 4, 2];\n let vec: BoundedVec = BoundedVec::from_array(array);\n for i in 0..array.len() {\n assert_eq(vec.get(i), array[i]);\n }\n }\n\n #[test]\n fn from_array_with_different_types() {\n let bool_array = [true, false, true];\n let bool_vec: BoundedVec = BoundedVec::from_array(bool_array);\n assert_eq(bool_vec.len(), 3);\n assert_eq(bool_vec.get(0), true);\n assert_eq(bool_vec.get(1), false);\n }\n }\n\n mod trait_from {\n use crate::collections::bounded_vec::BoundedVec;\n use crate::convert::From;\n\n #[test]\n fn simple() {\n let array = [1, 2];\n let bounded_vec: BoundedVec = BoundedVec::from(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 2);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n }\n }\n\n mod trait_eq {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty_equality() {\n let bounded_vec1: BoundedVec = BoundedVec::new();\n let bounded_vec2: BoundedVec = BoundedVec::new();\n\n assert_eq(bounded_vec1, bounded_vec2);\n }\n\n #[test]\n fn inequality() {\n let mut bounded_vec1: BoundedVec = BoundedVec::new();\n let mut bounded_vec2: BoundedVec = BoundedVec::new();\n bounded_vec1.push(1);\n bounded_vec2.push(2);\n\n assert(bounded_vec1 != bounded_vec2);\n }\n }\n\n mod from_parts {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn from_parts() {\n // docs:start:from-parts\n let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // Any elements past the given length are zeroed out, so these\n // two BoundedVecs will be completely equal\n let vec1: BoundedVec = BoundedVec::from_parts([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts([1, 2, 3, 2], 3);\n assert_eq(vec1, vec2);\n // docs:end:from-parts\n }\n\n #[test]\n fn from_parts_unchecked() {\n // docs:start:from-parts-unchecked\n let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // invalid use!\n let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n\n // both vecs have length 3 so we'd expect them to be equal, but this\n // fails because elements past the length are still checked in eq\n assert(vec1 != vec2);\n // docs:end:from-parts-unchecked\n }\n }\n\n mod push_pop {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn push_and_pop_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n assert_eq(vec.len(), 0);\n\n vec.push(1);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 1);\n\n vec.push(2);\n assert_eq(vec.len(), 2);\n assert_eq(vec.get(1), 2);\n\n let popped = vec.pop();\n assert_eq(popped, 2);\n assert_eq(vec.len(), 1);\n\n let popped2 = vec.pop();\n assert_eq(popped2, 1);\n assert_eq(vec.len(), 0);\n }\n\n #[test(should_fail_with = \"push out of bounds\")]\n fn push_to_full_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n vec.push(3); // should panic\n }\n\n #[test(should_fail_with = \"cannot pop from an empty vector\")]\n fn pop_from_empty_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n let _ = vec.pop(); // should panic\n }\n\n #[test]\n fn push_pop_cycle() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // push to full\n vec.push(1);\n vec.push(2);\n vec.push(3);\n assert_eq(vec.len(), 3);\n\n // pop all\n assert_eq(vec.pop(), 3);\n assert_eq(vec.pop(), 2);\n assert_eq(vec.pop(), 1);\n assert_eq(vec.len(), 0);\n\n // push again\n vec.push(4);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 4);\n }\n }\n\n mod extend {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn extend_from_array() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3]);\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3].as_vector());\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec() {\n // The source deliberately has a higher capacity,\n // to make sure we are not trying to assign out-of-bounds.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_limit() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_full_and_empty() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_zero_len() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_last_zeroed() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get_unchecked(3), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_empty_self() {\n // self.len == 0 with Len > MaxLen: the loop doesn't reach\n // the last storage slot, so the fixup must write it.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_equal_capacity() {\n // Len == MaxLen, fills to capacity.\n let mut vec1: BoundedVec = BoundedVec::new();\n vec1.push(1);\n let vec2: BoundedVec = BoundedVec::from_array([2, 3, 4]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 4);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n assert_eq(vec1.get(3), 4);\n }\n\n #[test(should_fail_with = \"extend_from_array out of bounds\")]\n fn extend_array_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3, 4]); // should panic\n }\n\n #[test(should_fail_with = \"extend_from_vector out of bounds\")]\n fn extend_vector_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3, 4].as_vector()); // S]should panic\n }\n\n #[test(should_fail_with = \"extend_from_bounded_vec out of bounds\")]\n fn extend_bounded_vec_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n let other: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n vec.extend_from_bounded_vec(other); // should panic\n }\n\n #[test]\n fn extend_with_empty_collections() {\n let mut vec: BoundedVec = BoundedVec::new();\n let original_len = vec.len();\n\n vec.extend_from_array([]);\n assert_eq(vec.len(), original_len);\n\n vec.extend_from_vector([].as_vector());\n assert_eq(vec.len(), original_len);\n\n let empty: BoundedVec = BoundedVec::new();\n vec.extend_from_bounded_vec(empty);\n assert_eq(vec.len(), original_len);\n }\n }\n\n mod storage {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn storage_consistency() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // test initial storage state\n assert_eq(vec.storage(), [0, 0, 0, 0, 0]);\n\n vec.push(1);\n vec.push(2);\n\n // test storage after modifications\n assert_eq(vec.storage(), [1, 2, 0, 0, 0]);\n\n // storage doesn't change length\n assert_eq(vec.len(), 2);\n assert_eq(vec.max_len(), 5);\n }\n\n #[test]\n fn storage_after_pop() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n let _ = vec.pop();\n // after pop, the last element should be zeroed\n assert_eq(vec.storage(), [1, 2, 0]);\n assert_eq(vec.len(), 2);\n }\n\n #[test]\n fn vector_immutable() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let storage = vec.storage();\n\n assert_eq(storage, [1, 2, 3]);\n\n // Verify that the original vector is unchanged\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n }\n}\n","path":"std/collections/bounded_vec.nr","function_locations":[{"start":2599,"name":"BoundedVec::new"},{"start":3202,"name":"BoundedVec::get"},{"start":4110,"name":"BoundedVec::get_unchecked"},{"start":4693,"name":"BoundedVec::set"},{"start":6221,"name":"BoundedVec::set_unchecked"},{"start":6759,"name":"BoundedVec::push"},{"start":7367,"name":"BoundedVec::len"},{"start":7808,"name":"BoundedVec::max_len"},{"start":8406,"name":"BoundedVec::storage"},{"start":8962,"name":"BoundedVec::extend_from_array"},{"start":9733,"name":"BoundedVec::extend_from_vector"},{"start":10678,"name":"BoundedVec::extend_from_bounded_vec"},{"start":13073,"name":"BoundedVec::from_array"},{"start":13816,"name":"BoundedVec::pop"},{"start":14439,"name":"BoundedVec::any"},{"start":15355,"name":"BoundedVec::map"},{"start":16355,"name":"BoundedVec::mapi"},{"start":17313,"name":"BoundedVec::for_each"},{"start":18118,"name":"BoundedVec::for_eachi"},{"start":19117,"name":"BoundedVec::from_parts"},{"start":20766,"name":"BoundedVec::from_parts_unchecked"},{"start":20978,"name":">::eq"},{"start":21549,"name":" for BoundedVec>::from"},{"start":21832,"name":"bounded_vec_tests::get::panics_when_reading_elements_past_end_of_vec"},{"start":22067,"name":"bounded_vec_tests::get::panics_when_reading_beyond_length"},{"start":22242,"name":"bounded_vec_tests::get::get_works_within_bounds"},{"start":22501,"name":"bounded_vec_tests::get::get_unchecked_works"},{"start":22745,"name":"bounded_vec_tests::get::get_unchecked_works_past_len"},{"start":23018,"name":"bounded_vec_tests::set::set_updates_values_properly"},{"start":23656,"name":"bounded_vec_tests::set::panics_when_writing_elements_past_end_of_vec"},{"start":23891,"name":"bounded_vec_tests::set::panics_when_setting_beyond_length"},{"start":24066,"name":"bounded_vec_tests::set::set_unchecked_operations"},{"start":24398,"name":"bounded_vec_tests::set::set_unchecked_operations_past_len"},{"start":24662,"name":"bounded_vec_tests::set::set_preserves_other_elements"},{"start":25130,"name":"bounded_vec_tests::any::returns_false_if_predicate_not_satisfied"},{"start":25384,"name":"bounded_vec_tests::any::returns_true_if_predicate_satisfied"},{"start":25633,"name":"bounded_vec_tests::any::returns_false_on_empty_boundedvec"},{"start":25844,"name":"bounded_vec_tests::any::any_with_complex_predicates"},{"start":26207,"name":"bounded_vec_tests::any::any_with_partial_vector"},{"start":26594,"name":"bounded_vec_tests::map::applies_function_correctly"},{"start":27016,"name":"bounded_vec_tests::map::applies_function_that_changes_return_type"},{"start":27364,"name":"bounded_vec_tests::map::does_not_apply_function_past_len"},{"start":27737,"name":"bounded_vec_tests::map::map_with_conditional_logic"},{"start":28061,"name":"bounded_vec_tests::map::map_preserves_length"},{"start":28353,"name":"bounded_vec_tests::map::map_on_empty_vector"},{"start":28727,"name":"bounded_vec_tests::mapi::applies_function_correctly"},{"start":29160,"name":"bounded_vec_tests::mapi::applies_function_that_changes_return_type"},{"start":29517,"name":"bounded_vec_tests::mapi::does_not_apply_function_past_len"},{"start":29899,"name":"bounded_vec_tests::mapi::mapi_with_index_branching_logic"},{"start":30458,"name":"bounded_vec_tests::for_each::for_each_map"},{"start":30688,"name":"bounded_vec_tests::for_each::smoke_test"},{"start":31096,"name":"bounded_vec_tests::for_each::applies_function_correctly"},{"start":31430,"name":"bounded_vec_tests::for_each::applies_function_that_changes_return_type"},{"start":31788,"name":"bounded_vec_tests::for_each::does_not_apply_function_past_len"},{"start":32169,"name":"bounded_vec_tests::for_each::for_each_on_empty_vector"},{"start":32455,"name":"bounded_vec_tests::for_each::for_each_with_side_effects"},{"start":33012,"name":"bounded_vec_tests::for_eachi::for_eachi_mapi"},{"start":33249,"name":"bounded_vec_tests::for_eachi::smoke_test"},{"start":33705,"name":"bounded_vec_tests::for_eachi::applies_function_correctly"},{"start":34049,"name":"bounded_vec_tests::for_eachi::applies_function_that_changes_return_type"},{"start":34417,"name":"bounded_vec_tests::for_eachi::does_not_apply_function_past_len"},{"start":34804,"name":"bounded_vec_tests::for_eachi::for_eachi_on_empty_vector"},{"start":35097,"name":"bounded_vec_tests::for_eachi::for_eachi_with_index_tracking"},{"start":35574,"name":"bounded_vec_tests::from_array::empty"},{"start":35884,"name":"bounded_vec_tests::from_array::equal_len"},{"start":36201,"name":"bounded_vec_tests::from_array::max_len_greater_then_array_len"},{"start":36672,"name":"bounded_vec_tests::from_array::max_len_lower_then_array_len"},{"start":36815,"name":"bounded_vec_tests::from_array::from_array_preserves_order"},{"start":37104,"name":"bounded_vec_tests::from_array::from_array_with_different_types"},{"start":37541,"name":"bounded_vec_tests::trait_from::simple"},{"start":37979,"name":"bounded_vec_tests::trait_eq::empty_equality"},{"start":38228,"name":"bounded_vec_tests::trait_eq::inequality"},{"start":38637,"name":"bounded_vec_tests::from_parts::from_parts"},{"start":39227,"name":"bounded_vec_tests::from_parts::from_parts_unchecked"},{"start":40009,"name":"bounded_vec_tests::push_pop::push_and_pop_operations"},{"start":40635,"name":"bounded_vec_tests::push_pop::push_to_full_vector"},{"start":40909,"name":"bounded_vec_tests::push_pop::pop_from_empty_vector"},{"start":41078,"name":"bounded_vec_tests::push_pop::push_pop_cycle"},{"start":41724,"name":"bounded_vec_tests::extend::extend_from_array"},{"start":42070,"name":"bounded_vec_tests::extend::extend_from_vector"},{"start":42434,"name":"bounded_vec_tests::extend::extend_from_bounded_vec"},{"start":43055,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_limit"},{"start":43569,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_full_and_empty"},{"start":44073,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_zero_len"},{"start":44367,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_last_zeroed"},{"start":44792,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_empty_self"},{"start":45359,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_equal_capacity"},{"start":45946,"name":"bounded_vec_tests::extend::extend_array_beyond_max_len"},{"start":46224,"name":"bounded_vec_tests::extend::extend_vector_beyond_max_len"},{"start":46527,"name":"bounded_vec_tests::extend::extend_bounded_vec_beyond_max_len"},{"start":46813,"name":"bounded_vec_tests::extend::extend_with_empty_collections"},{"start":47413,"name":"bounded_vec_tests::storage::storage_consistency"},{"start":47915,"name":"bounded_vec_tests::storage::storage_after_pop"},{"start":48233,"name":"bounded_vec_tests::storage::vector_immutable"}]},"16":{"source":"use crate::field::field_less_than;\nuse crate::runtime::is_unconstrained;\n\n// The low and high decomposition of the field modulus\npub(crate) global PLO: Field = 53438638232309528389504892708671455233;\npub(crate) global PHI: Field = 64323764613183177041862057485226039389;\n\npub(crate) global TWO_POW_128: Field = 0x100000000000000000000000000000000;\n\n// Decomposes a single field into two 16 byte fields.\nfn compute_decomposition(x: Field) -> (Field, Field) {\n // Here's we're taking advantage of truncating 128 bit limbs from the input field\n // and then subtracting them from the input such the field division is equivalent to integer division.\n let low = (x as u128) as Field;\n let high = (x - low) / TWO_POW_128;\n\n (low, high)\n}\n\npub(crate) unconstrained fn decompose_hint(x: Field) -> (Field, Field) {\n compute_decomposition(x)\n}\n\nunconstrained fn lte_hint(x: Field, y: Field) -> bool {\n if x == y {\n true\n } else {\n field_less_than(x, y)\n }\n}\n\n// Assert that (alo > blo && ahi >= bhi) || (alo <= blo && ahi > bhi)\nfn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) {\n let (alo, ahi) = a;\n let (blo, bhi) = b;\n // Safety: borrow is enforced to be boolean due to its type.\n // if borrow is 0, it asserts that (alo > blo && ahi >= bhi)\n // if borrow is 1, it asserts that (alo <= blo && ahi > bhi)\n unsafe {\n let borrow = lte_hint(alo, blo);\n\n let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128;\n let rhi = ahi - bhi - (borrow as Field);\n\n rlo.assert_max_bit_size::<128>();\n rhi.assert_max_bit_size::<128>();\n }\n}\n\n/// Decompose a single field into two 16 byte fields.\npub fn decompose(x: Field) -> (Field, Field) {\n if is_unconstrained() {\n compute_decomposition(x)\n } else {\n // Safety: decomposition is properly checked below\n unsafe {\n // Take hints of the decomposition\n let (xlo, xhi) = decompose_hint(x);\n\n // Range check the limbs\n xlo.assert_max_bit_size::<128>();\n xhi.assert_max_bit_size::<128>();\n\n // Check that the decomposition is correct\n assert_eq(x, xlo + TWO_POW_128 * xhi);\n\n // Assert that the decomposition of P is greater than the decomposition of x\n assert_gt_limbs((PLO, PHI), (xlo, xhi));\n (xlo, xhi)\n }\n }\n}\n\npub fn assert_gt(a: Field, b: Field) {\n if is_unconstrained() {\n assert(\n // Safety: already unconstrained\n unsafe { field_less_than(b, a) },\n );\n } else {\n // Decompose a and b\n let a_limbs = decompose(a);\n let b_limbs = decompose(b);\n\n // Assert that a_limbs is greater than b_limbs\n assert_gt_limbs(a_limbs, b_limbs)\n }\n}\n\npub fn assert_lt(a: Field, b: Field) {\n assert_gt(b, a);\n}\n\npub fn gt(a: Field, b: Field) -> bool {\n if is_unconstrained() {\n // Safety: unsafe in unconstrained\n unsafe {\n field_less_than(b, a)\n }\n } else if a == b {\n false\n } else {\n // Safety: Take a hint of the comparison and verify it\n unsafe {\n if field_less_than(a, b) {\n assert_gt(b, a);\n false\n } else {\n assert_gt(a, b);\n true\n }\n }\n }\n}\n\npub fn lt(a: Field, b: Field) -> bool {\n gt(b, a)\n}\n\nmod tests {\n // TODO: Allow imports from \"super\"\n use crate::field::bn254::{assert_gt, decompose, gt, lt, lte_hint, PHI, PLO, TWO_POW_128};\n\n #[test]\n fn check_decompose() {\n assert_eq(decompose(TWO_POW_128), (0, 1));\n assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1));\n assert_eq(decompose(0x1234567890), (0x1234567890, 0));\n }\n\n #[test]\n unconstrained fn check_lte_hint() {\n assert(lte_hint(0, 1));\n assert(lte_hint(0, 0x100));\n assert(lte_hint(0x100, TWO_POW_128 - 1));\n assert(!lte_hint(0 - 1, 0));\n\n assert(lte_hint(0, 0));\n assert(lte_hint(0x100, 0x100));\n assert(lte_hint(0 - 1, 0 - 1));\n }\n\n #[test]\n fn check_gt() {\n assert(gt(1, 0));\n assert(gt(0x100, 0));\n assert(gt((0 - 1), (0 - 2)));\n assert(gt(TWO_POW_128, 0));\n assert(!gt(0, 0));\n assert(!gt(0, 0x100));\n assert(gt(0 - 1, 0 - 2));\n assert(!gt(0 - 2, 0 - 1));\n assert_gt(0 - 1, 0);\n }\n\n #[test]\n fn check_plo_phi() {\n assert_eq(PLO + PHI * TWO_POW_128, 0);\n let p_bytes = crate::field::modulus_le_bytes();\n let mut p_low: Field = 0;\n let mut p_high: Field = 0;\n\n let mut offset = 1;\n for i in 0..16 {\n p_low += (p_bytes[i] as Field) * offset;\n p_high += (p_bytes[i + 16] as Field) * offset;\n offset *= 256;\n }\n assert_eq(p_low, PLO);\n assert_eq(p_high, PHI);\n }\n\n #[test]\n fn check_decompose_edge_cases() {\n assert_eq(decompose(0), (0, 0));\n assert_eq(decompose(TWO_POW_128 - 1), (TWO_POW_128 - 1, 0));\n assert_eq(decompose(TWO_POW_128 + 1), (1, 1));\n assert_eq(decompose(TWO_POW_128 * 2), (0, 2));\n assert_eq(decompose(TWO_POW_128 * 2 + 0x1234567890), (0x1234567890, 2));\n }\n\n #[test]\n fn check_decompose_large_values() {\n let large_field = 0xffffffffffffffff;\n let (lo, hi) = decompose(large_field);\n assert_eq(large_field, lo + TWO_POW_128 * hi);\n\n let large_value = large_field - TWO_POW_128;\n let (lo2, hi2) = decompose(large_value);\n assert_eq(large_value, lo2 + TWO_POW_128 * hi2);\n }\n\n #[test]\n fn check_lt_comprehensive() {\n assert(lt(0, 1));\n assert(!lt(1, 0));\n assert(!lt(0, 0));\n assert(!lt(42, 42));\n\n assert(lt(TWO_POW_128 - 1, TWO_POW_128));\n assert(!lt(TWO_POW_128, TWO_POW_128 - 1));\n }\n}\n","path":"std/field/bn254.nr","function_locations":[{"start":456,"name":"compute_decomposition"},{"start":818,"name":"decompose_hint"},{"start":906,"name":"lte_hint"},{"start":1116,"name":"assert_gt_limbs"},{"start":1725,"name":"decompose"},{"start":2431,"name":"assert_gt"},{"start":2837,"name":"assert_lt"},{"start":2901,"name":"gt"},{"start":3405,"name":"lt"},{"start":3607,"name":"tests::check_decompose"},{"start":3857,"name":"tests::check_lte_hint"},{"start":4164,"name":"tests::check_gt"},{"start":4494,"name":"tests::check_plo_phi"},{"start":4989,"name":"tests::check_decompose_edge_cases"},{"start":5349,"name":"tests::check_decompose_large_values"},{"start":5710,"name":"tests::check_lt_comprehensive"}]},"17":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [bool; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [bool; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [bool; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = false if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = true.\n pub fn sgn0(self) -> bool {\n (self as u8) % 2 == 1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [bool; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [bool; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [bool] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [bool] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_be_bits();\n assert_eq(bits, [false, false, false, false, false, false, true, false]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_le_bits();\n assert_eq(bits, [false, true, false, false, false, false, false, false]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_field.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_val.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [bool; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [false; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [bool; 8] = 1.to_le_bits();\n let expected: [bool; 8] = [true, false, false, false, false, false, false, false];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [bool; 8] = 4.to_le_bits();\n let expected: [bool; 8] = [false, false, true, false, false, false, false, false];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), false);\n assert_eq(2.sgn0(), false);\n assert_eq(4.sgn0(), false);\n assert_eq(100.sgn0(), false);\n\n assert_eq(1.sgn0(), true);\n assert_eq(3.sgn0(), true);\n assert_eq(5.sgn0(), true);\n assert_eq(101.sgn0(), true);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [bool; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits(bits: [bool; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits(bits: [bool; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1]);\n p_minus_1_bits[254 - 1] = false;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(!p_plus_4_bits[254 - 3]);\n p_plus_4_bits[254 - 3] = true;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_be_bits();\n assert(p_plus_4_converted_bits[254 - 3]);\n p_plus_4_converted_bits[254 - 3] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_be_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0]);\n p_minus_1_bits[0] = false;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(!p_plus_4_bits[2]);\n p_plus_4_bits[2] = true;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_le_bits();\n assert(p_plus_4_converted_bits[2]);\n p_plus_4_converted_bits[2] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_le_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n}\n","path":"std/field/mod.nr","function_locations":[{"start":380,"name":"Field::assert_max_bit_size"},{"start":1196,"name":"Field::to_le_bits"},{"start":2387,"name":"Field::to_be_bits"},{"start":3562,"name":"Field::to_le_bytes"},{"start":5033,"name":"Field::to_be_bytes"},{"start":5904,"name":"Field::to_le_radix"},{"start":6362,"name":"Field::to_be_radix"},{"start":7053,"name":"Field::pow_32"},{"start":7455,"name":"Field::sgn0"},{"start":7538,"name":"Field::lt"},{"start":7918,"name":"Field::from_le_bytes"},{"start":8476,"name":"Field::from_be_bytes"},{"start":8757,"name":"__assert_max_bit_size"},{"start":8885,"name":"__to_le_radix"},{"start":9013,"name":"__to_be_radix"},{"start":9734,"name":"__to_le_bits"},{"start":10452,"name":"__to_be_bits"},{"start":10527,"name":"modulus_num_bits"},{"start":10603,"name":"modulus_be_bits"},{"start":10679,"name":"modulus_le_bits"},{"start":10755,"name":"modulus_be_bytes"},{"start":10831,"name":"modulus_le_bytes"},{"start":10992,"name":"__field_less_than"},{"start":11068,"name":"field_less_than"},{"start":11210,"name":"bytes32_to_field"},{"start":11617,"name":"lt_fallback"},{"start":12579,"name":"tests::test_to_be_bits"},{"start":12852,"name":"tests::test_to_le_bits"},{"start":13127,"name":"tests::test_to_be_bytes"},{"start":13433,"name":"tests::test_to_le_bytes"},{"start":13739,"name":"tests::test_to_be_radix"},{"start":14321,"name":"tests::test_to_le_radix"},{"start":14921,"name":"tests::test_to_le_radix_1"},{"start":15374,"name":"tests::test_to_le_radix_brillig_1"},{"start":15728,"name":"tests::test_to_le_radix_3"},{"start":16039,"name":"tests::test_to_le_radix_brillig_3"},{"start":16467,"name":"tests::test_to_le_radix_512"},{"start":16876,"name":"tests::not_enough_limbs_brillig"},{"start":17072,"name":"tests::not_enough_limbs"},{"start":17214,"name":"tests::test_field_less_than"},{"start":17469,"name":"tests::test_large_field_values_unconstrained"},{"start":17922,"name":"tests::test_large_field_values"},{"start":18369,"name":"tests::test_decomposition_edge_cases"},{"start":18959,"name":"tests::test_pow_32"},{"start":19288,"name":"tests::test_sgn0"},{"start":19710,"name":"tests::test_bit_decomposition_overflow"},{"start":19992,"name":"tests::test_byte_decomposition_overflow"},{"start":20209,"name":"tests::test_to_from_be_bytes_bn254_edge_cases"},{"start":22160,"name":"tests::test_to_from_le_bytes_bn254_edge_cases"},{"start":24245,"name":"tests::from_le_bits"},{"start":24792,"name":"tests::from_be_bits"},{"start":25038,"name":"tests::test_to_from_be_bits_bn254_edge_cases"},{"start":26971,"name":"tests::test_to_from_le_bits_bn254_edge_cases"}]},"18":{"source":"// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\nuse crate::static_assert;\n\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated(\"This function has been moved to std::hash::keccakf1600\")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you're working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n \"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\n }\n let generators = derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n crate::assert_constant(separator);\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators(\"pedersen_hash_length\".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n crate::assert_constant(starting_index);\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\npub fn poseidon2_permutation(input: [Field; N]) -> [Field; N] {\n static_assert(\n N == POSEIDON2_CONFIG_STATE_SIZE,\n f\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\",\n );\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal(input: [Field; N]) -> [Field; N] {}\n\n#[foreign(poseidon2_config_state_size)]\ncomptime fn poseidon2_config_state_size() -> u32 {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n /// Returns the hash value without consuming the hasher.\n /// Override this for more efficient implementations that avoid copying.\n /// TODO: deprecate finish() and replace it\n fn finish_ref(&self) -> Field {\n (*self).finish()\n }\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault;\n\nimpl BuildHasher for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl Default for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for [T]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n },\n );\n}\n","path":"std/hash/mod.nr","function_locations":[{"start":572,"name":"sha256_compression"},{"start":707,"name":"keccakf1600"},{"start":882,"name":"keccak::keccakf1600"},{"start":1044,"name":"blake2s"},{"start":1142,"name":"blake3"},{"start":1629,"name":"__blake3"},{"start":1747,"name":"pedersen_commitment"},{"start":1976,"name":"pedersen_commitment_with_separator"},{"start":2380,"name":"pedersen_hash"},{"start":2537,"name":"pedersen_hash_with_separator"},{"start":3531,"name":"derive_generators"},{"start":3890,"name":"__derive_generators"},{"start":3968,"name":"poseidon2_permutation"},{"start":4324,"name":"poseidon2_permutation_internal"},{"start":4417,"name":"poseidon2_config_state_size"},{"start":4728,"name":"derive_hash"},{"start":5953,"name":">::build_hasher"},{"start":6085,"name":">::default"},{"start":6217,"name":"::hash"},{"start":6347,"name":"::hash"},{"start":6487,"name":"::hash"},{"start":6627,"name":"::hash"},{"start":6767,"name":"::hash"},{"start":6908,"name":"::hash"},{"start":7047,"name":"::hash"},{"start":7193,"name":"::hash"},{"start":7340,"name":"::hash"},{"start":7487,"name":"::hash"},{"start":7635,"name":"::hash"},{"start":7782,"name":"::hash"},{"start":7914,"name":"::hash"},{"start":8103,"name":"::hash"},{"start":8343,"name":"::hash"},{"start":8559,"name":"::hash"},{"start":8822,"name":"::hash"},{"start":9132,"name":"::hash"},{"start":9528,"name":"assert_pedersen"}]},"41":{"source":"use crate::cmp::{Eq, Ord, Ordering};\nuse crate::default::Default;\nuse crate::hash::{Hash, Hasher};\n\n/// Represents a value of type T or its absence.\n/// Use `Option::some(value)` to construct a value or `Option::none()` to record the absence of one.\npub struct Option {\n _is_some: bool,\n _value: T,\n}\n\nimpl Option {\n /// Constructs a None value\n pub fn none() -> Self {\n Self { _is_some: false, _value: crate::mem::zeroed() }\n }\n\n /// Constructs a Some wrapper around the given value\n pub fn some(_value: T) -> Self {\n Self { _is_some: true, _value }\n }\n\n /// True if this Option is None\n pub fn is_none(&self) -> bool {\n !self._is_some\n }\n\n /// True if this Option is Some\n pub fn is_some(&self) -> bool {\n self._is_some\n }\n\n /// Asserts `self.is_some()` and returns the wrapped value.\n pub fn unwrap(self) -> T {\n assert(self._is_some);\n self._value\n }\n\n /// Returns the inner value without asserting `self.is_some()`\n /// Note that if `self` is `None`, there is no guarantee what value will be returned,\n /// only that it will be of type `T`.\n pub fn unwrap_unchecked(self) -> T {\n self._value\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.\n pub fn unwrap_or(self, default: T) -> T {\n if self._is_some {\n self._value\n } else {\n default\n }\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return\n /// a default value.\n pub fn unwrap_or_else(self, default: fn[Env]() -> T) -> T {\n if self._is_some {\n self._value\n } else {\n default()\n }\n }\n\n /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value\n pub fn expect(self, message: fmtstr) -> T {\n assert(self.is_some(), message);\n self._value\n }\n\n /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.\n pub fn map(self, f: fn[Env](T) -> U) -> Option {\n if self._is_some {\n Option::some(f(self._value))\n } else {\n Option::none()\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.\n pub fn map_or(self, default: U, f: fn[Env](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.\n pub fn map_or_else(self, default: fn[Env1]() -> U, f: fn[Env2](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default()\n }\n }\n\n /// Returns None if self is None. Otherwise, this returns `other`.\n pub fn and(self, other: Self) -> Self {\n if self.is_none() {\n Option::none()\n } else {\n other\n }\n }\n\n /// If self is None, this returns None. Otherwise, this calls the given function\n /// with the Some value contained within self, and returns the result of that call.\n ///\n /// In some languages this function is called `flat_map` or `bind`.\n pub fn and_then(self, f: fn[Env](T) -> Option) -> Option {\n if self._is_some {\n f(self._value)\n } else {\n Option::none()\n }\n }\n\n /// If self is Some, return self. Otherwise, return `other`.\n pub fn or(self, other: Self) -> Self {\n if self._is_some {\n self\n } else {\n other\n }\n }\n\n /// If self is Some, return self. Otherwise, return `default()`.\n pub fn or_else(self, default: fn[Env]() -> Self) -> Self {\n if self._is_some {\n self\n } else {\n default()\n }\n }\n\n // If only one of the two Options is Some, return that option.\n // Otherwise, if both options are Some or both are None, None is returned.\n pub fn xor(self, other: Self) -> Self {\n if self._is_some {\n if other._is_some {\n Option::none()\n } else {\n self\n }\n } else if other._is_some {\n other\n } else {\n Option::none()\n }\n }\n\n /// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.\n /// Otherwise, this returns `None`\n pub fn filter(self, predicate: fn[Env](T) -> bool) -> Self {\n if self._is_some {\n if predicate(self._value) {\n self\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n }\n\n /// Flattens an Option> into a Option.\n /// This returns None if the outer Option is None. Otherwise, this returns the inner Option.\n pub fn flatten(option: Option>) -> Option {\n if option._is_some {\n option._value\n } else {\n Option::none()\n }\n }\n}\n\nimpl Default for Option {\n fn default() -> Self {\n Option::none()\n }\n}\n\nimpl Eq for Option\nwhere\n T: Eq,\n{\n fn eq(self, other: Self) -> bool {\n if self._is_some == other._is_some {\n if self._is_some {\n self._value == other._value\n } else {\n true\n }\n } else {\n false\n }\n }\n}\n\nimpl Hash for Option\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self._is_some.hash(state);\n if self._is_some {\n self._value.hash(state);\n }\n }\n}\n\n// For this impl we're declaring Option::none < Option::some\nimpl Ord for Option\nwhere\n T: Ord,\n{\n fn cmp(self, other: Self) -> Ordering {\n if self._is_some {\n if other._is_some {\n self._value.cmp(other._value)\n } else {\n Ordering::greater()\n }\n } else if other._is_some {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n","path":"std/option.nr","function_locations":[{"start":389,"name":"Option::none"},{"start":553,"name":"Option::some"},{"start":672,"name":"Option::is_none"},{"start":774,"name":"Option::is_some"},{"start":898,"name":"Option::unwrap"},{"start":1196,"name":"Option::unwrap_unchecked"},{"start":1368,"name":"Option::unwrap_or"},{"start":1668,"name":"Option::unwrap_or_else"},{"start":1969,"name":"Option::expect"},{"start":2190,"name":"Option::map"},{"start":2490,"name":"Option::map_or"},{"start":2784,"name":"Option::map_or_else"},{"start":3009,"name":"Option::and"},{"start":3446,"name":"Option::and_then"},{"start":3669,"name":"Option::or"},{"start":3902,"name":"Option::or_else"},{"start":4192,"name":"Option::xor"},{"start":4636,"name":"Option::filter"},{"start":5065,"name":"Option::flatten"},{"start":5242,"name":">::default"},{"start":5357,"name":">::eq"},{"start":5706,"name":">::hash"},{"start":5975,"name":">::cmp"}]},"42":{"source":"/// Halt the program at runtime with the given error message.\n///\n/// The provided error message must be either a `str` or a `fmtstr`.\npub fn panic(message: T) -> U\nwhere\n T: StringLike,\n{\n assert(false, message);\n crate::mem::zeroed()\n}\n\ntrait StringLike {}\n\nimpl StringLike for str {}\nimpl StringLike for fmtstr {}\n","path":"std/panic.nr","function_locations":[{"start":196,"name":"panic"}]},"52":{"source":"use crate::{\n authwit::{authorization_interface::AuthorizationInterface, AuthorizationSelector},\n context::{gas::GasOpts, PrivateContext, PublicContext},\n hash::hash_args,\n macros::authorization::authorization,\n oracle::{execution_cache::load, offchain_effect::emit_offchain_effect},\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::AztecAddress,\n constants::{\n CANONICAL_AUTH_REGISTRY_ADDRESS, DOM_SEP__AUTHWIT_INNER, DOM_SEP__AUTHWIT_NULLIFIER, DOM_SEP__AUTHWIT_OUTER,\n },\n hash::poseidon2_hash_with_separator,\n traits::{Serialize, ToField},\n};\n\n/// Authentication witness helper library\n///\n/// Authentication Witness is a scheme for authenticating actions on Aztec, so users can allow third-parties (e.g.\n/// protocols or other users) to execute an action on their behalf.\n///\n/// This library provides helper functions to manage such witnesses. The authentication witness, is some \"witness\"\n/// (data) that authenticates a `message_hash`. The simplest example of an authentication witness, is a signature. The\n/// signature is the \"evidence\", that the signer has seen the message, agrees with it, and has allowed it. It does not\n/// need to be a signature. It could be any kind of \"proof\" that the message is allowed. Another proof could be knowing\n/// some kind of secret, or having some kind of \"token\" that allows the message.\n///\n/// The `message_hash` is a hash of the following structure: hash(consumer, chain_id, version, inner_hash)\n/// - consumer: the address of the contract that is \"consuming\" the message,\n/// - chain_id: the chain id of the chain that the message is being consumed on,\n/// - version: the version of the chain that the message is being consumed on,\n/// - inner_hash: the hash of the \"inner\" message that is being consumed, this is the \"actual\" message or action.\n///\n/// While the `inner_hash` could be anything, such as showing you signed a specific message, it will often be a hash of\n/// the \"action\" to approve, along with who made the call. As part of this library, we provide a few helper functions\n/// to deal with such messages.\n///\n/// For example, we provide helper function that is used for checking that the message is an encoding of the current\n/// call. This can be used to let some contract \"allow\" another contract to act on its behalf, as long as it can show\n/// that it is acting on behalf of the contract.\n///\n/// If we take a case of allowing a contract to transfer tokens on behalf of an account, the `inner_hash` can be\n/// derived as: inner_hash = hash(caller, \"transfer\", hash(to, amount))\n///\n/// Where the `caller` would be the address of the contract that is trying to transfer the tokens, and `to` and\n/// `amount` the arguments for the transfer.\n///\n/// Note that we have both a `caller` and a `consumer`, the `consumer` will be the contract that is consuming the\n/// message, in the case of the transfer, it would be the `Token` contract itself, while the caller, will be the actor\n/// that is allowed to transfer the tokens.\n///\n///\n/// The authentication mechanism works differently in public and private contexts. In private, we recall that\n/// everything is executed on the user's device, so we can use `oracles` to \"ask\" the user (not contract) for\n/// information. In public we cannot do this, since it is executed by the sequencer (someone else). Therefore we can\n/// instead use a \"registry\" to store the messages that we have approved.\n///\n/// A simple example would be a \"token\" that is being \"pulled\" from one account into another. We will first outline how\n/// this would look in private, and then in public later.\n///\n/// Say that a user `Alice` wants to deposit some tokens into a DeFi protocol (say a DEX). `Alice` would make a\n/// `deposit` transaction, that she is executing using her account contract. The account would call the `DeFi` contract\n/// to execute `deposit`, which would try to pull funds from the `Token` contract. Since the `DeFi` contract is trying\n/// to pull funds from an account that is not its own, it needs to convince the `Token` contract that it is allowed to\n/// do so.\n///\n/// This is where the authentication witness comes in The `Token` contract computes a `message_hash` from the\n/// `transfer` call, and then asks `Alice Account` contract to verify that the `DeFi` contract is allowed to execute\n/// that call.\n///\n/// `Alice Account` contract can then ask `Alice` if she wants to allow the `DeFi` contract to pull funds from her\n/// account. If she does, she will sign the `message_hash` and return the signature to the `Alice Account` which will\n/// validate it and return success to the `Token` contract which will then allow the `DeFi` contract to pull funds from\n/// `Alice`.\n///\n/// To ensure that the same \"approval\" cannot be used multiple times, we also compute a `nullifier` for the\n/// authentication witness, and emit it from the `Token` contract (consumer).\n///\n/// Note that we can do this flow as we are in private were we can do oracle calls out from contracts.\n///\n///\n/// Person Contract Contract Contract\n/// Alice Alice Account Token DeFi\n/// | | | |\n/// | Defi.deposit(Token, 1000) | |\n/// |----------------->| | |\n/// | | deposit(Token, 1000) |\n/// | |---------------------------------------->|\n/// | | | |\n/// | | | transfer(Alice, Defi, 1000)\n/// | | |<---------------------|\n/// | | | |\n/// | | Check if Defi may call transfer(Alice, Defi, 1000)\n/// | |<-----------------| |\n/// | | | |\n/// | Please give me AuthWit for DeFi | |\n/// | calling transfer(Alice, Defi, 1000) | |\n/// |<-----------------| | |\n/// | | | |\n/// | | | |\n/// | AuthWit for transfer(Alice, Defi, 1000) |\n/// |----------------->| | |\n/// | | AuthWit validity | |\n/// | |----------------->| |\n/// | | | |\n/// | | throw if invalid AuthWit |\n/// | | | |\n/// | | emit AuthWit nullifier |\n/// | | | |\n/// | | transfer(Alice, Defi, 1000) |\n/// | | | |\n/// | | | |\n/// | | | success |\n/// | | |--------------------->|\n/// | | | |\n/// | | | |\n/// | | | deposit(Token, 1000)\n/// | | | |\n/// | | | |\n///\n///\n/// If we instead were in public, we cannot do the same flow. Instead we would use an authentication registry to store\n/// the messages that we have approved.\n///\n/// To approve a message, `Alice Account` can make a `set_authorized` call to the registry, to set a `message_hash` as\n/// authorized. This is essentially a mapping from `message_hash` to `true` for `Alice Contract`. Every account has its\n/// own map in the registry, so `Alice` cannot approve a message for `Bob`.\n///\n/// The `Token` contract can then try to \"spend\" the approval by calling `consume` on the registry. If the message was\n/// approved, the value is updated to `false`, and we return the success flag. For more information on the registry,\n/// see `main.nr` in `auth_registry_contract`.\n///\n/// Person Contract Contract Contract Contract\n/// Alice Alice Account Registry Token DeFi\n/// | | | | |\n/// | Registry.set_authorized(..., true) | | |\n/// |----------------->| | | |\n/// | | set_authorized(..., true) | |\n/// | |------------------->| | |\n/// | | | | |\n/// | | set authorized to true | |\n/// | | | | |\n/// | | | | |\n/// | Defi.deposit(Token, 1000) | | |\n/// |----------------->| | | |\n/// | | deposit(Token, 1000) | |\n/// | |-------------------------------------------------------------->|\n/// | | | | |\n/// | | | transfer(Alice, Defi, 1000) |\n/// | | | |<---------------------|\n/// | | | | |\n/// | | | Check if Defi may call transfer(Alice, Defi, 1000)\n/// | | |<------------------| |\n/// | | | | |\n/// | | throw if invalid AuthWit | |\n/// | | | | |\n/// | | | | |\n/// | | set authorized to false | |\n/// | | | | |\n/// | | | | |\n/// | | | AuthWit validity | |\n/// | | |------------------>| |\n/// | | | | |\n/// | | | | transfer(Alice, Defi, 1000)\n/// | | | |<-------------------->|\n/// | | | | |\n/// | | | | success |\n/// | | | |--------------------->|\n/// | | | | |\n/// | | | | deposit(Token, 1000)\n/// | | | | |\n///\n///\n/// --- FAQ ---\n/// Q: Why are we using a success flag of `poseidon2_hash_bytes(\"IS_VALID()\")` instead of just returning a boolean?\n/// A: We want to make sure that we don't accidentally return `true` if there is a collision in the function\n/// selector. By returning a hash of `IS_VALID()`, it becomes very unlikely that there is both a collision and we\n/// return a success flag.\n///\n/// Q: Why are we using static calls?\n/// A: We are using static calls to ensure that the account contract cannot re-enter. If it was a normal call, it\n/// could make a new call and do a re-entry attack. Using a static ensures that it cannot update any state.\n///\n/// Q: Would it not be cheaper to use a nullifier instead of updating state in public?\n/// A: At a quick glance, a public state update + nullifier is 96 bytes, but two state updates are 128, so it would\n/// be cheaper to use a nullifier, if this is the way it would always be done. However, if both the approval and the\n/// consumption is done in the same transaction, then we will be able to squash the updates (only final tx state diff\n/// is posted to DA), and now it is cheaper.\n///\n/// Q: Why is the chain id and the version part of the message hash?\n/// A: The chain id and the version is part of the message hash to ensure that the message is only valid on a\n/// specific chain to avoid a case where the same message could be used across multiple chains.\n\npub global IS_VALID_SELECTOR: Field = 0x47dacd73; // 4 last bytes of\n// poseidon2_hash_bytes(\"IS_VALID()\")\n\n/// A struct that represents a contract call the user can authorize. It's associated identifier is generated by\n/// serializing and hashing it. The user is expected to sign this hash to signal the contract call can be performed on\n/// their behalf\n#[authorization]\nstruct CallAuthorization {\n msg_sender: AztecAddress,\n selector: FunctionSelector,\n args_hash: Field,\n}\n\n/// A struct that represents a request to authorize a call, which is used to emit an offchain effect so the user/wallet\n/// can understand what they are being asked to sign. It is generated from a CallAuthorization by adding metadata to\n/// it, such as the selector for the authorization, the inner hash, and the actual arguments that are being passed to\n/// the function call.\n#[derive(Serialize)]\nstruct CallAuthorizationRequest {\n selector: AuthorizationSelector,\n inner_hash: Field,\n on_behalf_of: AztecAddress,\n msg_sender: AztecAddress,\n fn_selector: FunctionSelector,\n args_hash: Field,\n}\n\nunconstrained fn emit_authorization_as_offchain_effect(\n authorization: CallAuthorization,\n inner_hash: Field,\n on_behalf_of: AztecAddress,\n) {\n let args: [Field; N] = load(authorization.args_hash);\n let authorization_request = CallAuthorizationRequest {\n selector: authorization.get_authorization_selector(),\n inner_hash: inner_hash,\n on_behalf_of: on_behalf_of,\n msg_sender: authorization.msg_sender,\n fn_selector: authorization.selector,\n args_hash: authorization.args_hash,\n };\n emit_offchain_effect(authorization_request.serialize().concat(args))\n}\n\n/// Assert that `on_behalf_of` has authorized the current call with a valid authentication witness\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Additionally, this function emits the identifying information of the call as an offchain effect so PXE can rely the\n/// information to the user/wallet in a readable way. To that effect, it is generic over N, where N is the number of\n/// arguments the authorized functions takes. This is used to load the arguments from the execution cache. This\n/// function is intended to be called via a macro, which will use the turbofish operator to specify the number of\n/// arguments.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call\npub fn assert_current_call_valid_authwit(context: &mut PrivateContext, on_behalf_of: AztecAddress) {\n let args_hash: Field = context.get_args_hash();\n\n let authorization =\n CallAuthorization { msg_sender: context.maybe_msg_sender().unwrap(), selector: context.selector(), args_hash };\n let inner_hash = compute_inner_authwit_hash(authorization.serialize());\n // Safety: Offchain effects are by definition unconstrained. They are emitted via an oracle which we don't use for\n // anything besides its side effects, therefore this is safe to call.\n unsafe { emit_authorization_as_offchain_effect::(authorization, inner_hash, on_behalf_of) };\n\n assert_inner_hash_valid_authwit(context, on_behalf_of, inner_hash);\n}\n\n/// Assert that a specific `inner_hash` is valid for the `on_behalf_of` address\n///\n/// Used as an internal function for `assert_current_call_valid_authwit` and can be used as a standalone function when\n/// the `inner_hash` is from a different source, e.g., say a block of text etc.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call @param inner_hash The hash of the\n/// message to authorize\npub fn assert_inner_hash_valid_authwit(context: &mut PrivateContext, on_behalf_of: AztecAddress, inner_hash: Field) {\n // We perform a static call here and not a standard one to ensure that the account contract cannot re-enter.\n let result: Field = context\n .static_call_private_function(\n on_behalf_of,\n comptime { FunctionSelector::from_signature(\"verify_private_authwit(Field)\") },\n [inner_hash],\n )\n .get_preimage();\n assert(result == IS_VALID_SELECTOR, \"Message not authorized by account\");\n // Compute the nullifier, similar computation to the outer hash, but without the chain_id and version. Those should\n // already be handled in the verification, so we just need something to nullify, that allows the same inner_hash\n // for multiple actors.\n let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash);\n context.push_nullifier(nullifier);\n}\n\n/// Assert that `on_behalf_of` has authorized the current call in the authentication registry\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Note that the authentication registry will take the `msg_sender` into account as the consumer, so this will only\n/// work if the `msg_sender` is the same as the `consumer` when the `message_hash` was inserted into the registry.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call\npub unconstrained fn assert_current_call_valid_authwit_public(context: PublicContext, on_behalf_of: AztecAddress) {\n let inner_hash = compute_inner_authwit_hash([\n context.maybe_msg_sender().unwrap().to_field(),\n context.selector().to_field(),\n context.get_args_hash(),\n ]);\n assert_inner_hash_valid_authwit_public(context, on_behalf_of, inner_hash);\n}\n\n/// Assert that `on_behalf_of` has authorized a specific `inner_hash` in the authentication registry\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Note that the authentication registry will take the `msg_sender` into account as the consumer, so this will only\n/// work if the `msg_sender` is the same as the `consumer` when the `message_hash` was inserted into the registry.\n///\n/// @param on_behalf_of The address that has allegedly authorized the `inner_hash`\npub unconstrained fn assert_inner_hash_valid_authwit_public(\n context: PublicContext,\n on_behalf_of: AztecAddress,\n inner_hash: Field,\n) {\n let results: [Field] = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"consume((Field),Field)\") },\n [on_behalf_of.to_field(), inner_hash],\n GasOpts::default(),\n );\n assert(results.len() == 1, \"Invalid response from registry\");\n assert(results[0] == IS_VALID_SELECTOR, \"Message not authorized by account\");\n}\n\n/// Compute the `message_hash` from a function call to be used by an authentication witness\n///\n/// Useful for when you need a non-account contract to approve during execution. For example if you need a contract to\n/// make a call to nested contract, e.g., contract A wants to exit token T to L1 using bridge B, so it needs to allow B\n/// to transfer T on its behalf.\n///\n/// @param caller The address of the contract that is calling the function, in the example above, this would be B\n/// @param consumer The address of the contract that is consuming the message, in the example above, this would be T\n/// @param chain_id The chain id of the chain that the message is being consumed on @param version The version of the\n/// chain that the message is being consumed on @param selector The function selector of the function that is being\n/// called @param args The arguments of the function that is being called\npub fn compute_authwit_message_hash_from_call(\n caller: AztecAddress,\n consumer: AztecAddress,\n chain_id: Field,\n version: Field,\n selector: FunctionSelector,\n args: [Field; N],\n) -> Field {\n let args_hash = hash_args(args);\n let inner_hash = compute_inner_authwit_hash([caller.to_field(), selector.to_field(), args_hash]);\n compute_authwit_message_hash(consumer, chain_id, version, inner_hash)\n}\n\n/// Computes the `inner_hash` of the authentication witness\n///\n/// This is used internally, but also useful in cases where you want to compute the `inner_hash` for a specific message\n/// that is not necessarily a call, but just some \"bytes\" or text.\n///\n/// @param args The arguments to hash\npub fn compute_inner_authwit_hash(args: [Field; N]) -> Field {\n poseidon2_hash_with_separator(args, DOM_SEP__AUTHWIT_INNER)\n}\n\n/// Computes the `authwit_nullifier` for a specific `on_behalf_of` and `inner_hash`\n///\n/// Using the `on_behalf_of` and the `inner_hash` to ensure that the nullifier is siloed for a specific `on_behalf_of`.\n///\n/// @param on_behalf_of The address that has authorized the `inner_hash` @param inner_hash The hash of the message to\n/// authorize\npub fn compute_authwit_nullifier(on_behalf_of: AztecAddress, inner_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [on_behalf_of.to_field(), inner_hash],\n DOM_SEP__AUTHWIT_NULLIFIER,\n )\n}\n\n/// Computes the `message_hash` for the authentication witness\n///\n/// @param consumer The address of the contract that is consuming the message @param chain_id The chain id of the chain\n/// that the message is being consumed on @param version The version of the chain that the message is being consumed on\n/// @param inner_hash The hash of the \"inner\" message that is being consumed\npub fn compute_authwit_message_hash(\n consumer: AztecAddress,\n chain_id: Field,\n version: Field,\n inner_hash: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [consumer.to_field(), chain_id, version, inner_hash],\n DOM_SEP__AUTHWIT_OUTER,\n )\n}\n\n/// Helper function to set the authorization status of a message hash\n///\n/// Wraps a public call to the authentication registry to set the authorization status of a `message_hash`\n///\n/// @param message_hash The hash of the message to authorize @param authorize True if the message should be authorized,\n/// false if it should be revoked\npub unconstrained fn set_authorized(context: PublicContext, message_hash: Field, authorize: bool) {\n let res = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"set_authorized(Field,bool)\") },\n [message_hash, authorize as Field],\n GasOpts::default(),\n );\n assert(res.len() == 0);\n}\n\n/// Helper function to reject all authwits\n///\n/// Wraps a public call to the authentication registry to set the `reject_all` flag\n///\n/// @param reject True if all authwits should be rejected, false otherwise\npub unconstrained fn set_reject_all(context: PublicContext, reject: bool) {\n let res = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"set_reject_all(bool)\") },\n [reject as Field],\n GasOpts::default(),\n );\n assert(res.len() == 0);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/authwit/auth.nr","function_locations":[{"start":14768,"name":"emit_authorization_as_offchain_effect"},{"start":16200,"name":"assert_current_call_valid_authwit"},{"start":17389,"name":"assert_inner_hash_valid_authwit"},{"start":18929,"name":"assert_current_call_valid_authwit_public"},{"start":19955,"name":"assert_inner_hash_valid_authwit_public"},{"start":21499,"name":"compute_authwit_message_hash_from_call"},{"start":22083,"name":"compute_inner_authwit_hash"},{"start":22585,"name":"compute_authwit_nullifier"},{"start":23238,"name":"compute_authwit_message_hash"},{"start":23815,"name":"set_authorized"},{"start":24381,"name":"set_reject_all"}]},"59":{"source":"use crate::oracle::capsules;\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// A dynamically sized array backed by PXE's non-volatile database (called capsules). Values are persisted until\n/// deleted, so they can be e.g. stored during simulation of a transaction and later retrieved during witness\n/// generation. All values are scoped per contract address, so external contracts cannot access them.\npub struct CapsuleArray {\n contract_address: AztecAddress,\n /// The base slot is where the array length is stored in capsules. Array elements are stored in consecutive slots\n /// after the base slot. For example, with base slot 5: the length is at slot 5, the first element (index 0) is at\n /// slot 6, the second element (index 1) is at slot 7, and so on.\n base_slot: Field,\n /// Scope for capsule isolation. Capsule operations are scoped to the given address, allowing multiple independent\n /// namespaces within the same contract.\n scope: AztecAddress,\n}\n\nimpl CapsuleArray {\n /// Returns a CapsuleArray scoped to a specific address.\n ///\n /// Array elements are stored in contiguous slots\n /// following the base slot, so there should be sufficient space between array base slots to accommodate elements.\n /// A reasonable strategy is to make the base slot a hash of a unique value.\n pub unconstrained fn at(contract_address: AztecAddress, base_slot: Field, scope: AztecAddress) -> Self {\n Self { contract_address, base_slot, scope }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n // An uninitialized array defaults to a length of 0.\n capsules::load(self.contract_address, self.base_slot, self.scope).unwrap_or(0) as u32\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let current_length = self.len();\n\n // The slot corresponding to the index `current_length` is the first slot immediately after the end of the\n // array, which is where we want to place the new value.\n capsules::store(\n self.contract_address,\n self.slot_at(current_length),\n value,\n self.scope,\n );\n\n // Then we simply update the length.\n let new_length = current_length + 1;\n capsules::store(\n self.contract_address,\n self.base_slot,\n new_length,\n self.scope,\n );\n }\n\n /// Retrieves the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n assert(index < self.len(), \"Attempted to read past the length of a CapsuleArray\");\n\n capsules::load(self.contract_address, self.slot_at(index), self.scope).unwrap()\n }\n\n /// Deletes the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n let current_length = self.len();\n assert(index < current_length, \"Attempted to delete past the length of a CapsuleArray\");\n\n // In order to be able to remove elements at arbitrary indices, we need to shift the entire contents of the\n // array past the removed element one slot backward so that we don't end up with a gap and preserve the\n // contiguous slots. We can skip this when deleting the last element however.\n if index != current_length - 1 {\n // The source and destination regions overlap, but `copy` supports this.\n capsules::copy(\n self.contract_address,\n self.slot_at(index + 1),\n self.slot_at(index),\n current_length - index - 1,\n self.scope,\n );\n }\n\n // We can now delete the last element (which has either been copied to the slot immediately before it, or was\n // the element we meant to delete in the first place) and update the length.\n capsules::delete(\n self.contract_address,\n self.slot_at(current_length - 1),\n self.scope,\n );\n capsules::store(\n self.contract_address,\n self.base_slot,\n current_length - 1,\n self.scope,\n );\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. The order in which values\n /// are processed is arbitrary.\n ///\n /// ## Array Mutation\n ///\n /// It is safe to delete the current element (and only the current element) from inside the callback via `remove`:\n /// ```noir\n /// array.for_each(|index, value| {\n /// if some_condition(value) {\n /// array.remove(index); // safe only for this index\n /// }\n /// }\n /// ```\n ///\n /// If all elements in the array need to iterated over and then removed, then using `for_each` results in optimal\n /// efficiency.\n ///\n /// It is **not** safe to push new elements into the array from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n // Iterating over all elements is simple, but we want to do it in such a way that a) deleting the current\n // element is safe to do, and b) deleting *all* elements is optimally efficient. This is because CapsuleArrays\n // are typically used to hold pending tasks, so iterating them while clearing completed tasks (sometimes\n // unconditionally, resulting in a full clear) is a very common access pattern.\n //\n // The way we achieve this is by iterating backwards: each element can always be deleted since it won't change\n // any preceding (lower) indices, and if every element is deleted then every element will (in turn) be the last\n // element. This results in an optimal full clear since `remove` will be able to skip the `capsules::copy` call\n // to shift any elements past the deleted one (because there will be none).\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n\n unconstrained fn slot_at(self, index: u32) -> Field {\n // Elements are stored immediately after the base slot, so we add 1 to it to compute the slot for the first\n // element.\n self.base_slot + 1 + index as Field\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::CapsuleArray;\n\n global SLOT: Field = 1230;\n\n #[test]\n unconstrained fn empty_array() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array: CapsuleArray = CapsuleArray::at(contract_address, SLOT, scope);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn empty_array_read() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n let _: Field = array.get(0);\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn read_past_len() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(5);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 8);\n assert_eq(array.get(2), 9);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We store all values that we were called with and check that all (value, index) tuples are present. Note\n // that we do not care about the order in which each tuple was passed to the closure.\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all_no_copy() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We test that the aztec_utl_copyCapsule was never called, which is the expensive operation we want to\n // avoid.\n let mock = std::test::OracleMock::mock(\"aztec_utl_copyCapsule\");\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(mock.times_called(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_scopes_are_isolated() {\n let mut env = TestEnvironment::new();\n let scope_a = env.create_light_account();\n let scope_b = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array_a = CapsuleArray::at(contract_address, SLOT, scope_a);\n let array_b = CapsuleArray::at(contract_address, SLOT, scope_b);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/capsules/mod.nr","function_locations":[{"start":1478,"name":"CapsuleArray::at"},{"start":1641,"name":"CapsuleArray::len"},{"start":1935,"name":"CapsuleArray::push"},{"start":2748,"name":"CapsuleArray::get"},{"start":3083,"name":"CapsuleArray::remove"},{"start":5345,"name":"CapsuleArray::for_each"},{"start":6413,"name":"CapsuleArray::slot_at"},{"start":6789,"name":"test::empty_array"},{"start":7263,"name":"test::empty_array_read"},{"start":7638,"name":"test::array_push"},{"start":8156,"name":"test::read_past_len"},{"start":8559,"name":"test::array_remove_last"},{"start":8997,"name":"test::array_remove_some"},{"start":9729,"name":"test::array_remove_all"},{"start":10296,"name":"test::for_each_called_with_all_elements"},{"start":11389,"name":"test::for_each_remove_some"},{"start":12081,"name":"test::for_each_remove_all"},{"start":12619,"name":"test::for_each_remove_all_no_copy"},{"start":13383,"name":"test::different_scopes_are_isolated"}]},"68":{"source":"use crate::{\n context::gas::GasOpts,\n hash::{\n compute_l1_to_l2_message_hash, compute_l1_to_l2_message_nullifier, compute_secret_hash,\n compute_siloed_nullifier,\n },\n oracle::avm,\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::{AztecAddress, EthAddress},\n constants::{MAX_U32_VALUE, NULL_MSG_SENDER_CONTRACT_ADDRESS},\n traits::{Empty, FromField, Packable, Serialize, ToField},\n utils::writer::Writer,\n};\n\n/// # PublicContext\n///\n/// The **main interface** between an #[external(\"public\")] function and the Aztec blockchain.\n///\n/// An instance of the PublicContext is initialized automatically at the outset of every public function, within the\n/// #[external(\"public\")] macro, so you'll never need to consciously instantiate this yourself.\n///\n/// The instance is always named `context`, and it will always be available within the body of every\n/// #[external(\"public\")] function in your smart contract.\n///\n/// Typical usage for a smart contract developer will be to call getter methods of the PublicContext.\n///\n/// _Pushing_ data and requests to the context is mostly handled within aztec-nr's own functions, so typically a smart\n/// contract developer won't need to call any setter methods directly.\n///\n/// ## Responsibilities\n/// - Exposes contextual data to a public function:\n/// - Data relating to how this public function was called:\n/// - msg_sender, this_address\n/// - Data relating to the current blockchain state:\n/// - timestamp, block_number, chain_id, version\n/// - Gas and fee information\n/// - Provides state access:\n/// - Read/write public storage (key-value mapping)\n/// - Check existence of notes and nullifiers (Some patterns use notes & nullifiers to store public (not private)\n/// information)\n/// - Enables consumption of L1->L2 messages.\n/// - Enables calls to other public smart contract functions:\n/// - Writes data to the blockchain:\n/// - Updates to public state variables\n/// - New public logs (for events)\n/// - New L2->L1 messages\n/// - New notes & nullifiers (E.g. pushing public info to notes/nullifiers, or for completing \"partial notes\")\n///\n/// ## Key Differences from Private Execution\n///\n/// Unlike private functions -- which are executed on the user's device and which can only reference historic state --\n/// public functions are executed by a block proposer and are executed \"live\" on the _current_ tip of the chain. This\n/// means public functions can:\n/// - Read and write _current_ public state\n/// - Immediately see the effects of earlier transactions in the same block\n///\n/// Also, public functions are executed within a zkVM (the \"AVM\"), so that they can _revert_ whilst still ensuring\n/// payment to the proposer and prover. (Private functions cannot revert: they either succeed, or they cannot be\n/// included).\n///\n/// ## Optimising Public Functions\n///\n/// Using the AVM to execute public functions means they compile down to \"AVM bytecode\" instead of the ACIR that\n/// private functions (standalone circuits) compile to. Therefore the approach to optimising a public function is\n/// fundamentally different from optimising a public function.\n///\npub struct PublicContext {\n pub args_hash: Option,\n pub compute_args_hash: fn() -> Field,\n}\n\nimpl Eq for PublicContext {\n fn eq(self, other: Self) -> bool {\n (self.args_hash == other.args_hash)\n // Can't compare the function compute_args_hash\n }\n}\n\nimpl PublicContext {\n /// Creates a new PublicContext instance.\n ///\n /// Low-level function: This is called automatically by the #[external(\"public\")] macro, so you shouldn't need to\n /// be called directly by smart contract developers.\n ///\n /// # Arguments\n /// * `compute_args_hash` - Function to compute the args_hash\n ///\n /// # Returns\n /// * A new PublicContext instance\n ///\n pub fn new(compute_args_hash: fn() -> Field) -> Self {\n PublicContext { args_hash: Option::none(), compute_args_hash }\n }\n\n /// Emits a _public_ log that will be visible onchain to everyone.\n ///\n /// # Arguments\n /// * `tag` - A tag placed at `fields[0]` of the emitted log. Nodes index logs by this value, allowing\n /// clients to efficiently query for matching logs without scanning all of them.\n /// * `log` - The data to log, must implement Serialize trait.\n ///\n /// ## Safety\n ///\n /// The `tag` should be domain-separated (e.g. via [`crate::protocol::hash::compute_log_tag`]) to prevent\n /// collisions between logs from different sources. Without domain separation, two unrelated log types that\n /// happen to share a raw tag value become indistinguishable. Prefer `self.emit(event)` for events, which\n /// handles tagging automatically.\n pub fn emit_public_log_unsafe(_self: Self, tag: Field, log: T)\n where\n T: Serialize,\n {\n // We use a Writer to serialize the log directly after the tag, avoiding an extra O(n) copy that would\n // result from serializing first and then prepending the tag.\n let mut writer: Writer<1 + ::N> = Writer::new();\n writer.write(tag);\n Serialize::stream_serialize(log, &mut writer);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_public_log(writer.finish().as_vector()) };\n }\n\n /// Checks if a given note hash exists in the note hash tree at a particular leaf_index.\n ///\n /// # Arguments\n /// * `note_hash` - The note hash to check for existence\n /// * `leaf_index` - The index where the note hash should be located\n ///\n /// # Returns\n /// * `bool` - True if the note hash exists at the specified index\n ///\n pub fn note_hash_exists(_self: Self, note_hash: Field, leaf_index: u64) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::note_hash_exists(note_hash, leaf_index)\n }\n }\n\n /// Checks if a specific L1-to-L2 message exists in the L1-to-L2 message tree at a particular leaf index.\n ///\n /// Common use cases include token bridging, cross-chain governance, and triggering L2 actions based on L1 events.\n ///\n /// This function should be called before attempting to consume an L1-to-L2 message.\n ///\n /// # Arguments\n /// * `msg_hash` - Hash of the L1-to-L2 message to check\n /// * `msg_leaf_index` - The index where the message should be located\n ///\n /// # Returns\n /// * `bool` - True if the message exists at the specified index\n ///\n /// # Advanced\n /// * Uses the AVM l1_to_l2_msg_exists opcode for tree lookup\n /// * Messages are copied from L1 Inbox to L2 by block proposers\n ///\n pub fn l1_to_l2_msg_exists(_self: Self, msg_hash: Field, msg_leaf_index: Field) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself TODO(alvaro): Make l1l2msg leaf index a u64 upstream\n unsafe {\n avm::l1_to_l2_msg_exists(msg_hash, msg_leaf_index as u64)\n }\n }\n\n /// Returns `true` if an `unsiloed_nullifier` has been emitted by `contract_address`.\n ///\n /// Note that unsiloed nullifiers are not the actual values stored in the nullifier tree: they are first siloed via\n /// [`crate::hash::compute_siloed_nullifier`] with the emitting contract's address.\n ///\n /// ## Use Cases\n ///\n /// Nullifiers are typically used as a _privacy-preserving_ record of a one-time action, but they can also be used\n /// to efficiently record _public_ one-time actions as well. This is cheaper than using public storage, and has the\n /// added benefit of the nullifier being emittable from a private function.\n ///\n /// An example is to check whether a contract has been published: we emit a nullifier that is deterministic and\n /// which has a _public_ preimage.\n ///\n /// ## Public vs Private\n ///\n /// In general, one should not attempt to prove nullifier non-existence in private, as that will not consider the\n /// possibility of the nullifier having been emitted in any transaction between the anchor block and the inclusion\n /// block. Private functions instead prove existence via\n /// [`crate::context::PrivateContext::assert_nullifier_exists`]\n /// and 'prove' non-existence by _emitting_ the nullifer, which would cause the transaction to fail if the\n /// nullifier existed.\n ///\n /// This is not the case in public functions, which **do** have access to the tip of the blockchain and so can\n /// reliably prove whether a nullifier exists or not.\n ///\n /// ## Safety\n ///\n /// While it is safe to rely on this function's return value to determine if a nullifier exists or not, it is often\n /// **not** safe to infer additional information from that. In particular, it is **unsafe** to infer that the\n /// existence of a nullifier emitted from a private function implies that all other side-effects of said private\n /// execution have been completed, more concretely that any enqueued public calls have been executed.\n ///\n /// For example, if a function in contract `A` privately emits nullifier `X` and then enqueues public function `Y`,\n /// then it is **unsafe** for a contract `B` to infer that `Y` has alredy executed simply because `X` exists.\n ///\n /// This is because **all** private transaction effects are committed _before_ enqueued public functions are run\n /// (in\n /// order to not reveal detailed timing information about the transaction), so it is possible to observe a\n /// nullifier that was emitted alongside the enqueuing of a public call **before** said call has been completed.\n ///\n /// ## Cost\n ///\n /// This emits the `CHECKNULLIFIEREXISTS` opcode, which conceptually performs a merkle inclusion proof on the\n /// nullifier tree (both when the nullifier exists and when it doesn't).\n pub fn nullifier_exists_unsafe(_self: Self, unsiloed_nullifier: Field, contract_address: AztecAddress) -> bool {\n let siloed_nullifier = compute_siloed_nullifier(contract_address, unsiloed_nullifier);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::nullifier_exists(siloed_nullifier)\n }\n }\n\n /// Consumes a message sent from Ethereum (L1) to Aztec (L2) -- effectively marking it as \"read\".\n ///\n /// Use this function if you only want the message to ever be \"referred to\" once. Once consumed using this method,\n /// the message cannot be consumed again, because a nullifier is emitted. If your use case wants for the message to\n /// be read unlimited times, then you can always read any historic message from the L1-to-L2 messages tree, using\n /// the `l1_to_l2_msg_exists` method. Messages never technically get deleted from that tree.\n ///\n /// The message will first be inserted into an Aztec \"Inbox\" smart contract on L1. It will not be available for\n /// consumption immediately. Messages get copied-over from the L1 Inbox to L2 by the next Proposer in batches. So\n /// you will need to wait until the messages are copied before you can consume them.\n ///\n /// # Arguments\n /// * `content` - The message content that was sent from L1\n /// * `secret` - Secret value used for message privacy (if needed)\n /// * `sender` - Ethereum address that sent the message\n /// * `leaf_index` - Index of the message in the L1-to-L2 message tree\n ///\n /// # Advanced\n /// * Validates message existence in the L1-to-L2 message tree\n /// * Prevents double-consumption by emitting a nullifier\n /// * Message hash is computed from all parameters + chain context\n /// * Will revert if message doesn't exist or was already consumed\n ///\n pub fn consume_l1_to_l2_message(self: Self, content: Field, secret: Field, sender: EthAddress, leaf_index: Field) {\n let secret_hash = compute_secret_hash(secret);\n let message_hash = compute_l1_to_l2_message_hash(\n sender,\n self.chain_id(),\n /*recipient=*/\n self.this_address(),\n self.version(),\n content,\n secret_hash,\n leaf_index,\n );\n let nullifier = compute_l1_to_l2_message_nullifier(message_hash, secret);\n\n assert(!self.nullifier_exists_unsafe(nullifier, self.this_address()), \"L1-to-L2 message is already nullified\");\n assert(self.l1_to_l2_msg_exists(message_hash, leaf_index), \"Tried to consume nonexistent L1-to-L2 message\");\n\n self.push_nullifier(nullifier);\n }\n\n /// Sends an \"L2 -> L1 message\" from this function (Aztec, L2) to a smart contract on Ethereum (L1). L1 contracts\n /// which are designed to send/receive messages to/from Aztec are called \"Portal Contracts\".\n ///\n /// Common use cases include withdrawals, cross-chain asset transfers, and triggering L1 actions based on L2 state\n /// changes.\n ///\n /// The message will be inserted into an Aztec \"Outbox\" contract on L1, when this transaction's block is proposed\n /// to L1. Sending the message will not result in any immediate state changes in the target portal contract. The\n /// message will need to be manually consumed from the Outbox through a separate Ethereum transaction: a user will\n /// need to call a function of the portal contract -- a function specifically designed to make a call to the Outbox\n /// to consume the message. The message will only be available for consumption once the _epoch_ proof has been\n /// submitted. Given that there are multiple Aztec blocks within an epoch, it might take some time for this epoch\n /// proof to be submitted -- especially if the block was near the start of an epoch.\n ///\n /// # Arguments\n /// * `recipient` - Ethereum address that will receive the message\n /// * `content` - Message content (32 bytes as a Field element)\n ///\n pub fn message_portal(_self: Self, recipient: EthAddress, content: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::send_l2_to_l1_msg(recipient, content) };\n }\n\n /// Calls a public function on another contract.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Arguments to pass to the function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn call_public_function(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Makes a read-only call to a public function on another contract.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be staticcalls.\n ///\n /// Useful for querying data from other contracts safely.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Array of arguments to pass to the called function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn static_call_public_function(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call_static(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Adds a new note hash to the Aztec blockchain's global Note Hash Tree.\n ///\n /// Notes are ordinarily constructed and emitted by _private_ functions, to ensure that both the content of the\n /// note, and the contract that emitted the note, stay private.\n ///\n /// There are however some useful patterns whereby a note needs to contain _public_ data. The ability to push a new\n /// note_hash from a _public_ function means that notes can be injected with public data immediately -- as soon as\n /// the public value is known. The slower alternative would be to submit a follow-up transaction so that a private\n /// function can inject the data. Both are possible on Aztec.\n ///\n /// Search \"Partial Note\" for a very common pattern which enables a note to be \"partially\" populated with some data\n /// in a _private_ function, and then later \"completed\" with some data in a public function.\n ///\n /// # Arguments\n /// * `note_hash` - The hash of the note to add to the tree\n ///\n /// # Advanced\n /// * The note hash will be siloed with the contract address by the protocol\n ///\n pub fn push_note_hash(_self: Self, note_hash: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_note_hash(note_hash) };\n }\n\n /// Creates a new [nullifier](crate::nullifier).\n ///\n /// While nullifiers are primarily intended as a _privacy-preserving_ record of a one-time action, they can also\n /// be used to efficiently record _public_ one-time actions. This function allows creating nullifiers from public\n /// contract functions, which behave just like those created from private functions.\n ///\n /// ## Safety\n ///\n /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state.\n ///\n /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that\n /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a\n /// variable as initialized). Note nullifiers should only be created via\n /// [`crate::context::PrivateContext::push_nullifier_for_note_hash`].\n ///\n /// ## Advanced\n ///\n /// The raw `nullifier` is not what is inserted into the Aztec state tree: it will be first siloed by contract\n /// address via [`crate::protocol::hash::compute_siloed_nullifier`] in order to prevent accidental or malicious\n /// interference of nullifiers from different contracts.\n pub fn push_nullifier(_self: Self, nullifier: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_nullifier(nullifier) };\n }\n\n /// Returns the address of the current contract being executed.\n ///\n /// This is equivalent to `address(this)` in Solidity (hence the name). Use this to identify the current contract's\n /// address, commonly needed for access control or when interacting with other contracts.\n ///\n /// # Returns\n /// * `AztecAddress` - The contract address of the current function being executed.\n ///\n pub fn this_address(_self: Self) -> AztecAddress {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::address()\n }\n }\n\n /// Returns the contract address that initiated this function call.\n ///\n /// This is similar to `msg.sender` in Solidity (hence the name).\n ///\n /// Important Note: If the calling function is a _private_ function, then it had the option of hiding its address\n /// when enqueuing this public function call. In such cases, this method will return `Option::none`.\n /// If the calling function is a _public_ function, it will always return an `Option::some` (i.e. a\n /// non-null value).\n ///\n /// # Returns\n /// * `Option` - The address of the smart contract that called this function (be it an app contract\n /// or a user's account contract).\n ///\n /// # Advanced\n /// * Value is provided by the AVM sender opcode\n /// * In nested calls, this is the immediate caller, not the original transaction sender\n ///\n pub fn maybe_msg_sender(_self: Self) -> Option {\n // Safety: AVM opcodes are constrained by the AVM itself\n let maybe_msg_sender = unsafe { avm::sender() };\n if maybe_msg_sender == NULL_MSG_SENDER_CONTRACT_ADDRESS {\n Option::none()\n } else {\n Option::some(maybe_msg_sender)\n }\n }\n\n /// Returns the function selector of the currently-executing function.\n ///\n /// This is similar to `msg.sig` in Solidity, returning the first 4 bytes of the function signature.\n ///\n /// # Returns\n /// * `FunctionSelector` - The 4-byte function identifier\n ///\n /// # Advanced\n /// * Extracted from the first element of calldata\n /// * Used internally for function dispatch in the AVM\n ///\n pub fn selector(_self: Self) -> FunctionSelector {\n // The selector is the first element of the calldata when calling a public function through dispatch.\n // Safety: AVM opcodes are constrained by the AVM itself.\n let raw_selector: [Field; 1] = unsafe { avm::calldata_copy(0, 1) };\n FunctionSelector::from_field(raw_selector[0])\n }\n\n /// Returns the hash of the arguments passed to the current function.\n ///\n /// Very low-level function: The #[external(\"public\")] macro uses this internally. Smart contract developers\n /// typically won't need to access this directly as arguments are automatically made available.\n ///\n /// # Returns\n /// * `Field` - Hash of the function arguments\n ///\n pub fn get_args_hash(mut self) -> Field {\n if !self.args_hash.is_some() {\n self.args_hash = Option::some((self.compute_args_hash)());\n }\n\n self.args_hash.unwrap_unchecked()\n }\n\n /// Returns the \"transaction fee\" for the current transaction. This is the final tx fee that will be deducted from\n /// the fee_payer's \"fee-juice\" balance (in the protocol's Base Rollup circuit).\n ///\n /// # Returns\n /// * `Field` - The actual, final cost of the transaction, taking into account: the actual gas used during the\n /// setup and app-logic phases, and the fixed amount of gas that's been allocated by the user for the teardown\n /// phase. I.e. effectiveL2FeePerGas * l2GasUsed + effectiveDAFeePerGas * daGasUsed\n ///\n /// This will return `0` during the \"setup\" and \"app-logic\" phases of tx execution (because the final tx fee is not\n /// known at that time). This will only return a nonzero value during the \"teardown\" phase of execution, where the\n /// final tx fee can actually be computed.\n ///\n /// Regardless of _when_ this function is called during the teardown phase, it will always return the same final tx\n /// fee value. The teardown phase does not consume a variable amount of gas: it always consumes a pre-allocated\n /// amount of gas, as specified by the user when they generate their tx.\n ///\n pub fn transaction_fee(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::transaction_fee()\n }\n }\n\n /// Returns the chain ID of the current network.\n ///\n /// This is similar to `block.chainid` in Solidity. Returns the unique identifier for the blockchain network this\n /// transaction is executing on.\n ///\n /// Helps prevent cross-chain replay attacks. Useful if implementing multi-chain contract logic.\n ///\n /// # Returns\n /// * `Field` - The chain ID as a field element\n ///\n pub fn chain_id(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::chain_id()\n }\n }\n\n /// Returns the Aztec protocol version that this transaction is executing under. Different versions may have\n /// different rules, opcodes, or cryptographic primitives.\n ///\n /// This is similar to how Ethereum has different EVM versions.\n ///\n /// Useful for forward/backward compatibility checks\n ///\n /// Not to be confused with contract versions; this is the protocol version.\n ///\n /// # Returns\n /// * `Field` - The protocol version as a field element\n ///\n pub fn version(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::version()\n }\n }\n /// Returns the current block number.\n ///\n /// This is similar to `block.number` in Solidity.\n ///\n /// Note: the current block number is only available within a public function (as opposed to a private function).\n ///\n /// Note: the time intervals between blocks should not be relied upon as being consistent:\n /// - Timestamps of blocks fall within a range, rather than at exact regular intervals.\n /// - Slots can be missed.\n /// - Protocol upgrades can completely change the intervals between blocks (and indeed the current roadmap plans to\n /// reduce the time between blocks, eventually). Use `context.timestamp()` for more-reliable time-based logic.\n ///\n /// # Returns\n /// * `u32` - The current block number\n ///\n pub fn block_number(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::block_number()\n }\n }\n\n /// Returns the timestamp of the current block.\n ///\n /// This is similar to `block.timestamp` in Solidity.\n ///\n /// All functions of all transactions in a block share the exact same timestamp (even though technically each\n /// transaction is executed one-after-the-other).\n ///\n /// Important note: Timestamps of Aztec blocks are not at reliably-fixed intervals. The proposer of the block has\n /// some flexibility to choose a timestamp which is in a valid _range_: Obviously the timestamp of this block must\n /// be strictly greater than that of the previous block, and must must be less than the timestamp of whichever\n /// ethereum block the aztec block is proposed to. Furthermore, if the timestamp is not deemed close enough to the\n /// actual current time, the committee of validators will not attest to the block.\n ///\n /// # Returns\n /// * `u64` - Unix timestamp in seconds\n ///\n pub fn timestamp(_self: Self) -> u64 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::timestamp()\n }\n }\n\n /// Returns the fee per unit of L2 gas for this transaction (aka the \"L2 gas price\"), as chosen by the user.\n ///\n /// L2 gas covers the cost of executing public functions and handling side-effects within the AVM.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of L2 gas\n ///\n /// Wallet developers should be mindful that the choice of gas price (which is publicly visible) can leak\n /// information about the user, e.g.:\n /// - which wallet software the user is using;\n /// - the amount of time which has elapsed from the time the user's wallet chose a gas price (at the going rate),\n /// to the time of tx submission. This can give clues about the proving time, and hence the nature of the tx.\n /// - the urgency of the transaction (which is kind of unavoidable, if the tx is indeed urgent).\n /// - the wealth of the user.\n /// - the exact user (if the gas price is explicitly chosen by the user to be some unique number like 0.123456789,\n /// or their favorite number). Wallet devs might wish to consider fuzzing the choice of gas price.\n ///\n pub fn min_fee_per_l2_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_l2_gas()\n }\n }\n\n /// Returns the fee per unit of DA (Data Availability) gas (aka the \"DA gas price\").\n ///\n /// DA gas covers the cost of making transaction data available on L1.\n ///\n /// See the warning in `min_fee_per_l2_gas` for how gas prices can be leaky.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of DA gas\n ///\n pub fn min_fee_per_da_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_da_gas()\n }\n }\n\n /// Returns the remaining L2 gas available for this transaction.\n ///\n /// Different AVM opcodes consume different amounts of gas.\n ///\n /// # Returns\n /// * `u32` - Remaining L2 gas units\n ///\n pub fn l2_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::l2_gas_left()\n }\n }\n\n /// Returns the remaining DA (Data Availability) gas available for this transaction.\n ///\n /// DA gas is consumed when emitting data that needs to be made available on L1, such as public logs or state\n /// updates. All of the side-effects from the private part of the tx also consume DA gas before execution of any\n /// public functions even begins.\n ///\n /// # Returns\n /// * `u32` - Remaining DA gas units\n ///\n pub fn da_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::da_gas_left()\n }\n }\n\n /// Checks if the current execution is within a staticcall context, where no state changes or logs are allowed to\n /// be emitted (by this function or any nested function calls).\n ///\n /// # Returns\n /// * `bool` - True if in staticcall context, false otherwise\n ///\n pub fn is_static_call(_self: Self) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::is_static_call()\n }\n }\n\n /// Reads raw field values from public storage. Reads N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to read from\n ///\n /// # Returns\n /// * `[Field; N]` - Array of N field values from consecutive storage slots\n ///\n /// # Generic Parameters\n /// * `N` - the number of consecutive slots to return, starting from the `storage_slot`.\n ///\n pub fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n let mut out = [0; N];\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n out[i] = unsafe { avm::storage_read(storage_slot + i as Field, self.this_address().to_field()) };\n }\n out\n }\n\n /// Reads a typed value from public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to read from\n ///\n /// # Returns\n /// * `T` - The deserialized value from storage\n ///\n /// # Generic Parameters\n /// * `T` - The type that the caller expects to read from the `storage_slot`.\n ///\n pub fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n\n /// Writes raw field values to public storage. Writes to N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// Public storage writes take effect immediately.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to write to\n /// * `values` - Array of N Fields to write to storage\n ///\n pub fn raw_storage_write(_self: Self, storage_slot: Field, values: [Field; N]) {\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::storage_write(storage_slot + i as Field, values[i]) };\n }\n }\n\n /// Writes a typed value to public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to write to\n /// * `value` - The typed value to write to storage\n ///\n /// # Generic Parameters\n /// * `T` - The type to write to storage.\n ///\n pub fn storage_write(self, storage_slot: Field, value: T)\n where\n T: Packable,\n {\n self.raw_storage_write(storage_slot, value.pack());\n }\n}\n\nimpl Empty for PublicContext {\n fn empty() -> Self {\n PublicContext::new(|| 0)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/public_context.nr","function_locations":[{"start":3353,"name":"::eq"},{"start":3938,"name":"PublicContext::new"},{"start":4887,"name":"PublicContext::emit_public_log_unsafe"},{"start":5811,"name":"PublicContext::note_hash_exists"},{"start":6824,"name":"PublicContext::l1_to_l2_msg_exists"},{"start":10039,"name":"PublicContext::nullifier_exists_unsafe"},{"start":11904,"name":"PublicContext::consume_l1_to_l2_message"},{"start":14021,"name":"PublicContext::message_portal"},{"start":14911,"name":"PublicContext::call_public_function"},{"start":16543,"name":"PublicContext::static_call_public_function"},{"start":18327,"name":"PublicContext::push_note_hash"},{"start":19766,"name":"PublicContext::push_nullifier"},{"start":20356,"name":"PublicContext::this_address"},{"start":21451,"name":"PublicContext::maybe_msg_sender"},{"start":22223,"name":"PublicContext::selector"},{"start":22962,"name":"PublicContext::get_args_hash"},{"start":24354,"name":"PublicContext::transaction_fee"},{"start":24943,"name":"PublicContext::chain_id"},{"start":25613,"name":"PublicContext::version"},{"start":26553,"name":"PublicContext::block_number"},{"start":27665,"name":"PublicContext::timestamp"},{"start":28946,"name":"PublicContext::min_fee_per_l2_gas"},{"start":29473,"name":"PublicContext::min_fee_per_da_gas"},{"start":29871,"name":"PublicContext::l2_gas_left"},{"start":30487,"name":"PublicContext::da_gas_left"},{"start":30952,"name":"PublicContext::is_static_call"},{"start":31794,"name":"PublicContext::raw_storage_read"},{"start":32652,"name":"PublicContext::storage_read"},{"start":33320,"name":"PublicContext::raw_storage_write"},{"start":34054,"name":"PublicContext::storage_write"},{"start":34179,"name":"::empty"}]},"70":{"source":"use crate::oracle::{execution::get_utility_context, storage::storage_read};\nuse crate::protocol::{abis::block_header::BlockHeader, address::AztecAddress, traits::Packable};\n\n// If you'll modify this struct don't forget to update utility_context.ts as well.\npub struct UtilityContext {\n block_header: BlockHeader,\n contract_address: AztecAddress,\n}\n\nimpl UtilityContext {\n pub unconstrained fn new() -> Self {\n get_utility_context()\n }\n\n pub unconstrained fn at(contract_address: AztecAddress) -> Self {\n // We get a context with default contract address, and then we construct the final context with the provided\n // contract address.\n let default_context = get_utility_context();\n\n Self { block_header: default_context.block_header, contract_address }\n }\n\n pub fn block_header(self) -> BlockHeader {\n self.block_header\n }\n\n pub fn block_number(self) -> u32 {\n self.block_header.block_number()\n }\n\n pub fn timestamp(self) -> u64 {\n self.block_header.timestamp()\n }\n\n pub fn this_address(self) -> AztecAddress {\n self.contract_address\n }\n\n pub fn version(self) -> Field {\n self.block_header.version()\n }\n\n pub fn chain_id(self) -> Field {\n self.block_header.chain_id()\n }\n\n pub unconstrained fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n storage_read(self.block_header, self.this_address(), storage_slot)\n }\n\n pub unconstrained fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/utility_context.nr","function_locations":[{"start":416,"name":"UtilityContext::new"},{"start":523,"name":"UtilityContext::at"},{"start":855,"name":"UtilityContext::block_header"},{"start":927,"name":"UtilityContext::block_number"},{"start":1011,"name":"UtilityContext::timestamp"},{"start":1104,"name":"UtilityContext::this_address"},{"start":1177,"name":"UtilityContext::version"},{"start":1257,"name":"UtilityContext::chain_id"},{"start":1404,"name":"UtilityContext::raw_storage_read"},{"start":1596,"name":"UtilityContext::storage_read"}]},"72":{"source":"//! The `self` contract value for public execution contexts.\n\nuse crate::{\n context::{calls::{PublicCall, PublicStaticCall}, PublicContext},\n event::{event_emission::emit_event_in_public, event_interface::EventInterface},\n};\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Core interface for interacting with aztec-nr contract features in public execution contexts.\n///\n/// This struct is automatically injected into every [`external`](crate::macros::functions::external) and\n/// [`internal`](crate::macros::functions::internal) contract function marked with `\"public\"` by the Aztec macro\n/// system and is accessible through the `self` variable.\n///\n/// ## Type Parameters\n///\n/// - `Storage`: The contract's storage struct (defined with [`storage`](crate::macros::storage::storage), or `()` if\n/// the contract has no storage\n/// - `CallSelf`: Macro-generated type for calling contract's own non-view functions\n/// - `CallSelfStatic`: Macro-generated type for calling contract's own view functions\n/// - `CallInternal`: Macro-generated type for calling internal functions\npub struct ContractSelfPublic {\n /// The address of this contract\n pub address: AztecAddress,\n\n /// The contract's storage instance, representing the struct to which the\n /// [`storage`](crate::macros::storage::storage) macro was applied in your contract. If the contract has no\n /// storage, the type of this will be `()`.\n ///\n /// This storage instance is specialized for the current execution context (public) and\n /// provides access to the contract's state variables.\n ///\n /// ## Developer Note\n ///\n /// If you've arrived here while trying to access your contract's storage while the `Storage` generic type is set\n /// to unit type `()`, it means you haven't yet defined a Storage struct using the\n /// [`storage`](crate::macros::storage::storage) macro in your contract. For guidance on setting this up, please\n /// refer to our docs: https://docs.aztec.network/developers/docs/guides/smart_contracts/storage\n pub storage: Storage,\n\n /// The public execution context.\n pub context: PublicContext,\n\n /// Provides type-safe methods for calling this contract's own non-view functions.\n ///\n /// Example API:\n /// ```noir\n /// self.call_self.some_public_function(args)\n /// ```\n pub call_self: CallSelf,\n\n /// Provides type-safe methods for calling this contract's own view functions.\n ///\n /// Example API:\n /// ```noir\n /// self.call_self_static.some_view_function(args)\n /// ```\n pub call_self_static: CallSelfStatic,\n\n /// Provides type-safe methods for calling internal functions.\n ///\n /// Example API:\n /// ```noir\n /// self.internal.some_internal_function(args)\n /// ```\n pub internal: CallInternal,\n}\n\nimpl ContractSelfPublic {\n /// Creates a new `ContractSelfPublic` instance for a public function.\n ///\n /// This constructor is called automatically by the macro system and should not be called directly.\n pub fn new(\n context: PublicContext,\n storage: Storage,\n call_self: CallSelf,\n call_self_static: CallSelfStatic,\n internal: CallInternal,\n ) -> Self {\n Self { context, storage, address: context.this_address(), call_self, call_self_static, internal }\n }\n\n /// The address of the contract address that made this function call.\n ///\n /// This is similar to Solidity's `msg.sender` value.\n ///\n /// ## Incognito Calls\n ///\n /// Contracts can call public functions from private ones hiding their identity (see\n ///\n /// [`ContractSelfPrivate::enqueue_incognito`](crate::contract_self::ContractSelfPrivate::enqueue_incognito)).\n /// This function reverts when executed in such a context.\n ///\n /// If you need to handle these cases, use [`PublicContext::maybe_msg_sender`].\n pub fn msg_sender(self: Self) -> AztecAddress {\n self.context.maybe_msg_sender().unwrap()\n }\n\n /// Emits an event publicly.\n ///\n /// Public events are emitted as plaintext and are therefore visible to everyone. This is is the same as Solidity\n /// events on EVM chains.\n ///\n /// Unlike private events, they don't require delivery of an event message.\n ///\n /// # Example\n /// ```noir\n /// #[event]\n /// struct Update { value: Field }\n ///\n /// #[external(\"public\")]\n /// fn publish_update(value: Field) {\n /// self.emit(Update { value });\n /// }\n /// ```\n ///\n /// # Cost\n ///\n /// Public event emission is achieved by emitting public transaction logs. A total of `N+1` fields are emitted,\n /// where `N` is the serialization length of the event.\n pub fn emit(&mut self, event: Event)\n where\n Event: EventInterface + Serialize,\n {\n emit_event_in_public(self.context, event);\n }\n\n /// Makes a public contract call.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `call` - The object representing the public function to invoke.\n ///\n /// # Returns\n /// * `T` - Whatever data the called function has returned.\n ///\n /// # Example\n /// ```noir\n /// self.call(Token::at(address).transfer_in_public(recipient, amount));\n /// ```\n ///\n pub unconstrained fn call(self, call: PublicCall) -> T\n where\n T: Deserialize,\n {\n call.call(self.context)\n }\n\n /// Makes a public read-only contract call.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be static calls.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `call` - The object representing the read-only public function to invoke.\n ///\n /// # Returns\n /// * `T` - Whatever data the called function has returned.\n ///\n /// # Example\n /// ```noir\n /// self.view(Token::at(address).balance_of_public(recipient));\n /// ```\n ///\n pub unconstrained fn view(self, call: PublicStaticCall) -> T\n where\n T: Deserialize,\n {\n call.view(self.context)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/contract_self/contract_self_public.nr","function_locations":[{"start":3401,"name":"ContractSelfPublic::new"},{"start":4116,"name":"ContractSelfPublic::msg_sender"},{"start":5004,"name":"ContractSelfPublic::emit"},{"start":5645,"name":"ContractSelfPublic::call"},{"start":6466,"name":"ContractSelfPublic::view"}]},"75":{"source":"use crate::oracle::ephemeral;\nuse crate::protocol::traits::{Deserialize, Serialize};\n\n/// A dynamically sized array that exists only during a single contract call frame.\n///\n/// Ephemeral arrays are backed by in-memory storage on the PXE side rather than a persistent database. Each contract\n/// call frame gets its own isolated slot space of ephemeral arrays. Child simulations cannot see the parent's\n/// ephemeral arrays, and vice versa.\n///\n/// Each logical array operation (push, pop, get, etc.) is a single oracle call, making ephemeral arrays significantly\n/// cheaper than capsule arrays.\n///\n/// ## Use Cases\n///\n/// Ephemeral arrays are designed for passing data between PXE (TypeScript) and contracts (Noir) during simulation,\n/// for example, note validation requests or event validation responses. This data type is appropriate for data that\n/// is not supposed to be persisted.\n///\n/// For data that needs to persist across simulations, contract calls, etc, use\n/// [`CapsuleArray`](crate::capsules::CapsuleArray) instead.\npub struct EphemeralArray {\n pub slot: Field,\n}\n\nimpl EphemeralArray {\n /// Returns a handle to an ephemeral array at the given slot, which may already contain data (e.g. populated\n /// by an oracle).\n pub unconstrained fn at(slot: Field) -> Self {\n Self { slot }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n ephemeral::len_oracle(self.slot)\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n let _ = ephemeral::push_oracle(self.slot, serialized);\n }\n\n /// Removes and returns the last element. Panics if the array is empty.\n pub unconstrained fn pop(self) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::pop_oracle(self.slot);\n Deserialize::deserialize(serialized)\n }\n\n /// Retrieves the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::get_oracle(self.slot, index);\n Deserialize::deserialize(serialized)\n }\n\n /// Overwrites the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn set(self, index: u32, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n ephemeral::set_oracle(self.slot, index, serialized);\n }\n\n /// Removes the element at `index`, shifting subsequent elements backward. Panics if out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n ephemeral::remove_oracle(self.slot, index);\n }\n\n /// Removes all elements from the array and returns self for chaining (e.g. `EphemeralArray::at(slot).clear()`\n /// to get a guaranteed-empty array at a given slot).\n pub unconstrained fn clear(self) -> Self {\n ephemeral::clear_oracle(self.slot);\n self\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. Iteration proceeds\n /// backwards so that it is safe to remove the current element (and only the current element) inside the\n /// callback.\n ///\n /// It is **not** safe to push new elements from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use crate::test::mocks::MockStruct;\n use super::EphemeralArray;\n\n global SLOT: Field = 1230;\n global OTHER_SLOT: Field = 5670;\n\n #[test]\n unconstrained fn empty_array() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn empty_array_read() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.get(0);\n });\n }\n\n #[test(should_fail_with = \"is empty\")]\n unconstrained fn empty_array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.pop();\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn read_past_len() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.push(10);\n\n let popped: Field = array.pop();\n assert_eq(popped, 10);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test]\n unconstrained fn array_set() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.set(0, 99);\n assert_eq(array.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.remove(0);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_slots_are_isolated() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array_a = EphemeralArray::at(SLOT);\n let array_b = EphemeralArray::at(OTHER_SLOT);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn works_with_multi_field_type() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n\n let a = MockStruct::new(5, 6);\n let b = MockStruct::new(7, 8);\n array.push(a);\n array.push(b);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), a);\n assert_eq(array.get(1), b);\n\n let popped: MockStruct = array.pop();\n assert_eq(popped, b);\n assert_eq(array.len(), 1);\n });\n }\n\n #[test]\n unconstrained fn clear_returns_self() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(array.len(), 0);\n\n array.push(42);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 42);\n });\n }\n\n #[test]\n unconstrained fn clear_wipes_previous_data() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n array.push(1);\n array.push(2);\n array.push(3);\n assert_eq(array.len(), 3);\n\n // Clear the same slot, previous data should be gone.\n let fresh: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(fresh.len(), 0);\n fresh.push(4);\n assert_eq(fresh.get(0), 4);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/ephemeral/mod.nr","function_locations":[{"start":1305,"name":"EphemeralArray::at"},{"start":1438,"name":"EphemeralArray::len"},{"start":1618,"name":"EphemeralArray::push"},{"start":1888,"name":"EphemeralArray::pop"},{"start":2176,"name":"EphemeralArray::get"},{"start":2475,"name":"EphemeralArray::set"},{"start":2743,"name":"EphemeralArray::remove"},{"start":3022,"name":"EphemeralArray::clear"},{"start":3593,"name":"EphemeralArray::for_each"},{"start":3983,"name":"test::empty_array"},{"start":4280,"name":"test::empty_array_read"},{"start":4550,"name":"test::empty_array_pop"},{"start":4783,"name":"test::array_push"},{"start":5122,"name":"test::read_past_len"},{"start":5376,"name":"test::array_pop"},{"start":5783,"name":"test::array_set"},{"start":6081,"name":"test::array_remove_last"},{"start":6376,"name":"test::array_remove_some"},{"start":6847,"name":"test::array_remove_all"},{"start":7273,"name":"test::for_each_called_with_all_elements"},{"start":8009,"name":"test::for_each_remove_some"},{"start":8561,"name":"test::for_each_remove_all"},{"start":8960,"name":"test::different_slots_are_isolated"},{"start":9534,"name":"test::works_with_multi_field_type"},{"start":10148,"name":"test::clear_returns_self"},{"start":10535,"name":"test::clear_wipes_previous_data"}]},"77":{"source":"use crate::{event::EventSelector, messages::logs::event::MAX_EVENT_SERIALIZED_LEN};\nuse crate::protocol::{\n constants::DOM_SEP__EVENT_COMMITMENT,\n hash::{poseidon2_hash_with_separator, poseidon2_hash_with_separator_bounded_vec},\n traits::{Serialize, ToField},\n};\n\npub trait EventInterface {\n fn get_event_type_id() -> EventSelector;\n}\n\n/// A private event's commitment is a value stored on-chain which is used to verify that the event was indeed emitted.\n///\n/// It requires a `randomness` value that must be produced alongside the event in order to perform said validation.\n/// This random value prevents attacks in which someone guesses plausible events (e.g. 'Alice transfers to Bob an\n/// amount of 10'), since they will not be able to test for existence of their guessed events without brute-forcing the\n/// entire `Field` space by guessing `randomness` values.\npub fn compute_private_event_commitment(event: Event, randomness: Field) -> Field\nwhere\n Event: EventInterface + Serialize,\n{\n poseidon2_hash_with_separator(\n [randomness, Event::get_event_type_id().to_field()].concat(event.serialize()),\n DOM_SEP__EVENT_COMMITMENT,\n )\n}\n\n/// Unconstrained variant of [`compute_private_event_commitment`] which takes the event in serialized form.\n///\n/// This function is unconstrained as the mechanism it uses to compute the commitment would be very inefficient in a\n/// constrained environment (due to the hashing of a dynamically sized array). This is not an issue as it is typically\n/// invoked when processing event messages, which is an unconstrained operation.\npub unconstrained fn compute_private_serialized_event_commitment(\n serialized_event: BoundedVec,\n randomness: Field,\n event_type_id: Field,\n) -> Field {\n let mut commitment_preimage =\n BoundedVec::<_, 2 + MAX_EVENT_SERIALIZED_LEN>::from_array([randomness, event_type_id]);\n commitment_preimage.extend_from_bounded_vec(serialized_event);\n\n poseidon2_hash_with_separator_bounded_vec(commitment_preimage, DOM_SEP__EVENT_COMMITMENT)\n}\n\nmod test {\n use crate::event::event_interface::{\n compute_private_event_commitment, compute_private_serialized_event_commitment, EventInterface,\n };\n use crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN;\n use crate::protocol::traits::{Serialize, ToField};\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn max_size_serialized_event_commitment() {\n let serialized_event = BoundedVec::from_array([0; MAX_EVENT_SERIALIZED_LEN]);\n let _ = compute_private_serialized_event_commitment(serialized_event, 0, 0);\n }\n\n #[test]\n unconstrained fn event_commitment_equivalence() {\n let event = MockEvent::new(VALUE).build_event();\n\n assert_eq(\n compute_private_event_commitment(event, RANDOMNESS),\n compute_private_serialized_event_commitment(\n BoundedVec::from_array(event.serialize()),\n RANDOMNESS,\n MockEvent::get_event_type_id().to_field(),\n ),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_interface.nr","function_locations":[{"start":1013,"name":"compute_private_event_commitment"},{"start":1803,"name":"compute_private_serialized_event_commitment"},{"start":2570,"name":"test::max_size_serialized_event_commitment"},{"start":2814,"name":"test::event_commitment_equivalence"}]},"79":{"source":"use crate::protocol::{hash::poseidon2_hash_bytes, traits::{Deserialize, Empty, FromField, Serialize, ToField}};\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct EventSelector {\n // Low 32 bits of the poseidon2 hash of the event signature.\n inner: u32,\n}\n\nimpl FromField for EventSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for EventSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for EventSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl EventSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n EventSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_selector.nr","function_locations":[{"start":337,"name":"::from_field"},{"start":449,"name":"::to_field"},{"start":542,"name":"::empty"},{"start":647,"name":"EventSelector::from_u32"},{"start":751,"name":"EventSelector::from_signature"},{"start":985,"name":"EventSelector::zero"}]},"81":{"source":"//! Aztec hash functions.\n\nuse crate::protocol::{\n address::{AztecAddress, EthAddress},\n constants::{\n DOM_SEP__FUNCTION_ARGS, DOM_SEP__MESSAGE_NULLIFIER, DOM_SEP__PUBLIC_BYTECODE, DOM_SEP__PUBLIC_CALLDATA,\n DOM_SEP__SECRET_HASH, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS,\n },\n hash::{poseidon2_hash_subarray, poseidon2_hash_with_separator, sha256_to_field},\n traits::ToField,\n};\n\npub use crate::protocol::hash::compute_siloed_nullifier;\n\npub fn compute_secret_hash(secret: Field) -> Field {\n poseidon2_hash_with_separator([secret], DOM_SEP__SECRET_HASH)\n}\n\npub fn compute_l1_to_l2_message_hash(\n sender: EthAddress,\n chain_id: Field,\n recipient: AztecAddress,\n version: Field,\n content: Field,\n secret_hash: Field,\n leaf_index: Field,\n) -> Field {\n let mut hash_bytes = [0 as u8; 224];\n let sender_bytes: [u8; 32] = sender.to_field().to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n let recipient_bytes: [u8; 32] = recipient.to_field().to_be_bytes();\n let version_bytes: [u8; 32] = version.to_be_bytes();\n let content_bytes: [u8; 32] = content.to_be_bytes();\n let secret_hash_bytes: [u8; 32] = secret_hash.to_be_bytes();\n let leaf_index_bytes: [u8; 32] = leaf_index.to_be_bytes();\n\n for i in 0..32 {\n hash_bytes[i] = sender_bytes[i];\n hash_bytes[i + 32] = chain_id_bytes[i];\n hash_bytes[i + 64] = recipient_bytes[i];\n hash_bytes[i + 96] = version_bytes[i];\n hash_bytes[i + 128] = content_bytes[i];\n hash_bytes[i + 160] = secret_hash_bytes[i];\n hash_bytes[i + 192] = leaf_index_bytes[i];\n }\n\n sha256_to_field(hash_bytes)\n}\n\n// The nullifier of a l1 to l2 message is the hash of the message salted with the secret\npub fn compute_l1_to_l2_message_nullifier(message_hash: Field, secret: Field) -> Field {\n poseidon2_hash_with_separator([message_hash, secret], DOM_SEP__MESSAGE_NULLIFIER)\n}\n\n// Computes the hash of input arguments or return values for private functions, or for authwit creation.\npub fn hash_args(args: [Field; N]) -> Field {\n if args.len() == 0 {\n 0\n } else {\n poseidon2_hash_with_separator(args, DOM_SEP__FUNCTION_ARGS)\n }\n}\n\n// Computes the hash of calldata for public functions.\npub fn hash_calldata_array(calldata: [Field; N]) -> Field {\n poseidon2_hash_with_separator(calldata, DOM_SEP__PUBLIC_CALLDATA)\n}\n\n/// Computes the public bytecode commitment for a contract class. The commitment is `hash([(length | separator),\n/// ...bytecode])`.\n///\n/// @param packed_bytecode - The packed bytecode of the contract class. 0th word is the length in bytes.\n/// packed_bytecode is mutable so that we can avoid copying the array to construct one starting with first_field\n/// instead of length. @returns The public bytecode commitment.\npub fn compute_public_bytecode_commitment(\n mut packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],\n) -> Field {\n // First field element contains the length of the bytecode\n let bytecode_length_in_bytes: u32 = packed_public_bytecode[0] as u32;\n let bytecode_length_in_fields: u32 = (bytecode_length_in_bytes / 31) + (bytecode_length_in_bytes % 31 != 0) as u32;\n // Don't allow empty public bytecode. AVM doesn't handle execution of contracts that exist with empty bytecode.\n assert(bytecode_length_in_fields != 0);\n assert(bytecode_length_in_fields < MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS);\n\n // Packed_bytecode's 0th entry is the length. Append it to the separator before hashing.\n let first_field = DOM_SEP__PUBLIC_BYTECODE.to_field() + (packed_public_bytecode[0] as u64 << 32) as Field;\n packed_public_bytecode[0] = first_field;\n\n // `fields_to_hash` is the number of fields from the start of `packed_public_bytecode` that should be included in\n // the hash. Fields after this length are ignored. +1 to account for the prepended field.\n let num_fields_to_hash = bytecode_length_in_fields + 1;\n\n poseidon2_hash_subarray(packed_public_bytecode, num_fields_to_hash)\n}\n\n#[test]\nunconstrained fn secret_hash_matches_typescript() {\n let secret = 8;\n let hash = compute_secret_hash(secret);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let secret_hash_from_ts = 0x1848b066724ab0ffb50ecb0ee3398eb839f162823d262bad959721a9c13d1e96;\n\n assert_eq(hash, secret_hash_from_ts);\n}\n\n#[test]\nunconstrained fn var_args_hash_matches_typescript() {\n let mut input = [0; 100];\n for i in 0..100 {\n input[i] = i as Field;\n }\n let hash = hash_args(input);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let var_args_hash_from_ts = 0x262e5e121a8efc0382566ab42f0ae2a78bd85db88484f83018fe07fc2552ba0c;\n\n assert_eq(hash, var_args_hash_from_ts);\n}\n\n#[test]\nunconstrained fn compute_calldata_hash() {\n let mut input = [0; 100];\n for i in 0..input.len() {\n input[i] = i as Field;\n }\n let hash = hash_calldata_array(input);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let calldata_hash_from_ts = 0x14a1539bdb1d26e03097cf4d40c87e02ca03f0bb50a3e617ace5a7bfd3943944;\n\n // Used in cpp vm2 tests:\n assert_eq(hash, calldata_hash_from_ts);\n}\n\n#[test]\nunconstrained fn public_bytecode_commitment() {\n let mut input = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS];\n let len = 99;\n for i in 1..len + 1 {\n input[i] = i as Field;\n }\n input[0] = (len as Field) * 31;\n let hash = compute_public_bytecode_commitment(input);\n // Used in cpp vm2 tests:\n assert_eq(hash, 0x09348974e76c3602893d7a4b4bb52c2ec746f1ade5004ac471d0fbb4587a81a6);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/hash.nr","function_locations":[{"start":519,"name":"compute_secret_hash"},{"start":800,"name":"compute_l1_to_l2_message_hash"},{"start":1858,"name":"compute_l1_to_l2_message_nullifier"},{"start":2110,"name":"hash_args"},{"start":2362,"name":"hash_calldata_array"},{"start":2994,"name":"compute_public_bytecode_commitment"},{"start":4153,"name":"secret_hash_matches_typescript"},{"start":4512,"name":"var_args_hash_matches_typescript"},{"start":4922,"name":"compute_calldata_hash"},{"start":5385,"name":"public_bytecode_commitment"}]},"92":{"source":"use crate::protocol::{\n address::aztec_address::AztecAddress,\n constants::{DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, DOM_SEP__ECDH_FIELD_MASK, DOM_SEP__ECDH_SUBKEY},\n hash::poseidon2_hash_with_separator,\n point::Point,\n scalar::Scalar,\n traits::{FromField, ToField},\n};\nuse std::{embedded_curve_ops::multi_scalar_mul, ops::Neg};\n\n/// Computes a standard ECDH shared secret: secret * public_key = shared_secret.\n///\n/// The input secret is known only to one party. The output shared secret can be derived given knowledge of\n/// `public_key`'s key-pair and the public ephemeral secret, using this same function (with reversed inputs).\n///\n/// E.g.: Epk = esk * G // ephemeral key-pair\n/// Pk = sk * G // recipient key-pair\n/// Shared secret S = esk * Pk = sk * Epk\n///\n/// See also: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman\npub fn derive_ecdh_shared_secret(secret: Scalar, public_key: Point) -> Point {\n // TODO(F-553): Drop the `.to_embedded()` / `.into()` round-trip once the custom `Point` wrapper is removed and we\n // use `EmbeddedCurvePoint` directly.\n multi_scalar_mul([public_key.to_embedded()], [secret]).into()\n}\n\n/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.\n///\n/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`\npub(crate) fn compute_app_siloed_shared_secret(shared_secret: Point, contract_address: AztecAddress) -> Field {\n poseidon2_hash_with_separator(\n [shared_secret.x, shared_secret.y, contract_address.to_field()],\n DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET,\n )\n}\n\n/// Derives an indexed subkey from an app-siloed shared secret, used for AES key/IV derivation.\n///\n/// `s_i = h(DOM_SEP__ECDH_SUBKEY + i, s_app)`\npub(crate) fn derive_shared_secret_subkey(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_SUBKEY + index)\n}\n\n/// Derives an indexed field mask from an app-siloed shared secret, used for masking ciphertext fields.\n///\n/// `m_i = h(DOM_SEP__ECDH_FIELD_MASK + i, s_app)`\npub(crate) fn derive_shared_secret_field_mask(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_FIELD_MASK + index)\n}\n\n#[test]\nunconstrained fn test_consistency_with_typescript() {\n let secret = Scalar {\n lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,\n hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,\n };\n let point = Point {\n x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,\n y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,\n is_infinite: false,\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret, point);\n\n // This is just pasted from a test run. The original typescript code from which this could be generated seems to\n // have been deleted by someone, and soon the typescript code for encryption and decryption won't be needed, so\n // this will have to do.\n let hard_coded_shared_secret = Point {\n x: 0x15d55a5b3b2caa6a6207f313f05c5113deba5da9927d6421bcaa164822b911bc,\n y: 0x0974c3d0825031ae933243d653ebb1a0b08b90ee7f228f94c5c74739ea3c871e,\n is_infinite: false,\n };\n assert_eq(shared_secret, hard_coded_shared_secret);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_from_address_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let mut pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let mut pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let address_b = AztecAddress::from_field(pk_b.x);\n\n // We were lazy in deriving the secret keys, and didn't check the resulting y-coordinates of the pk_a or pk_b to be\n // less than half the field modulus. If needed, we negate the pk's so that they yield valid address points. (We\n // could also have negated the secrets, but there's no negate method for EmbeddedCurvesScalar).\n pk_a = if (AztecAddress::from_field(pk_a.x).to_address_point().unwrap().inner == pk_a) {\n pk_a\n } else {\n pk_a.neg()\n };\n pk_b = if (address_b.to_address_point().unwrap().inner == pk_b) {\n pk_b\n } else {\n pk_b.neg()\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, address_b.to_address_point().unwrap().inner);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_app_siloed_shared_secret_differs_per_contract() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(Scalar { lo: 0x3456, hi: 0x4567 }).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n\n let contract_a = AztecAddress::from_field(0xAAAA);\n let contract_b = AztecAddress::from_field(0xBBBB);\n\n let s_app_a = compute_app_siloed_shared_secret(shared_secret, contract_a);\n let s_app_b = compute_app_siloed_shared_secret(shared_secret, contract_b);\n\n assert(s_app_a != s_app_b, \"app-siloed secrets must differ for different contracts\");\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/keys/ecdh_shared_secret.nr","function_locations":[{"start":954,"name":"derive_ecdh_shared_secret"},{"start":1485,"name":"compute_app_siloed_shared_secret"},{"start":1876,"name":"derive_shared_secret_subkey"},{"start":2194,"name":"derive_shared_secret_field_mask"},{"start":2336,"name":"test_consistency_with_typescript"},{"start":3450,"name":"test_shared_secret_computation_in_both_directions"},{"start":4017,"name":"test_shared_secret_computation_from_address_in_both_directions"},{"start":5278,"name":"test_app_siloed_shared_secret_differs_per_contract"}]},"97":{"source":"// Not all log levels are currently used, but we provide the full set so that new call sites can use any level. Because\n// of that we tag all with `#[allow(dead_code)]` to prevent warnings.\n//\n// All wrappers resolve function paths at comptime via `resolve_fn` so that the emitted `Quoted` code works both inside\n// aztec-nr (where `crate::` = aztec) and inside macro-generated contract code (where `crate::` = the contract).\n\nuse std::meta::ctstring::AsCtString;\n\ncomptime fn log_prefix(msg: str) -> CtString {\n \"[aztec-nr] \".as_ctstring().append_str(msg)\n}\n\n// --- No-args variants (direct call) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log });\n quote { $f($msg) }\n}\n\n// --- Format variants (return lambda for runtime args) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n// See module-level comment for why this is needed.\ncomptime fn resolve_fn(path: Quoted) -> TypedExpr {\n path.as_expr().unwrap().resolve(Option::none())\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/logging.nr","function_locations":[{"start":525,"name":"log_prefix"},{"start":717,"name":"aztecnr_fatal_log"},{"start":943,"name":"aztecnr_error_log"},{"start":1168,"name":"aztecnr_warn_log"},{"start":1392,"name":"aztecnr_info_log"},{"start":1619,"name":"aztecnr_verbose_log"},{"start":1847,"name":"aztecnr_debug_log"},{"start":2073,"name":"aztecnr_trace_log"},{"start":2367,"name":"aztecnr_fatal_log_format"},{"start":2622,"name":"aztecnr_error_log_format"},{"start":2876,"name":"aztecnr_warn_log_format"},{"start":3129,"name":"aztecnr_info_log_format"},{"start":3385,"name":"aztecnr_verbose_log_format"},{"start":3642,"name":"aztecnr_debug_log_format"},{"start":3897,"name":"aztecnr_trace_log_format"},{"start":4151,"name":"resolve_fn"}]},"99":{"source":"use crate::logging;\nuse crate::macros::{notes::NOTES, utils::get_trait_impl_method};\n\n/// Generates two contract library methods called `_compute_note_hash` and `_compute_note_nullifier`, plus a\n/// (deprecated) wrapper called `_compute_note_hash_and_nullifier`, which are used for note discovery (i.e. these are\n/// of the `aztec::messages::discovery::ComputeNoteHash` and `aztec::messages::discovery::ComputeNoteNullifier` types).\npub(crate) comptime fn generate_contract_library_methods_compute_note_hash_and_nullifier() -> Quoted {\n let compute_note_hash = generate_contract_library_method_compute_note_hash();\n let compute_note_nullifier = generate_contract_library_method_compute_note_nullifier();\n\n quote {\n $compute_note_hash\n $compute_note_nullifier\n\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n #[allow(dead_code)]\n unconstrained fn _compute_note_hash_and_nullifier(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n note_nonce: Field,\n ) -> Option {\n _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash| {\n\n let siloed_note_hash = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash);\n let unique_note_hash = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash);\n \n let inner_nullifier = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness);\n\n aztec::messages::discovery::NoteHashAndNullifier {\n note_hash,\n inner_nullifier,\n }\n })\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_hash() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the note hash (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_note_hash = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_note_hash },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n Option::some($compute_note_hash(note, owner, storage_slot, randomness))\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed).\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_nullifier() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the inner nullifier (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_nullifier_unconstrained = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_nullifier_unconstrained },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n // The message discovery process finds settled notes, that is, notes that were created in\n // prior transactions and are therefore already part of the note hash tree. The note hash\n // for nullification is hence the unique note hash.\n $compute_nullifier_unconstrained(note, owner, unique_note_hash)\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data.\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec/compute_note_hash_and_nullifier.nr","function_locations":[{"start":534,"name":"generate_contract_library_methods_compute_note_hash_and_nullifier"},{"start":2449,"name":"generate_contract_library_method_compute_note_hash"},{"start":7674,"name":"generate_contract_library_method_compute_note_nullifier"}]},"100":{"source":"mod compute_note_hash_and_nullifier;\n\nuse crate::{\n macros::{\n calls_generation::{\n external_functions::{generate_external_function_calls, generate_external_function_self_calls_structs},\n internal_functions::generate_call_internal_struct,\n },\n dispatch::generate_public_dispatch,\n emit_public_init_nullifier::generate_emit_public_init_nullifier,\n internals_functions_generation::{create_fn_abi_exports, process_functions},\n offchain_receive::{\n OFFCHAIN_RECEIVE_FN_NAME, OFFCHAIN_RECEIVE_PARAM_NAME, offchain_receive_param_type,\n OFFCHAIN_RECEIVE_RETURN_TYPE,\n },\n storage::STORAGE_LAYOUT_NAME,\n utils::{is_fn_contract_library_method, is_fn_external, is_fn_internal, is_fn_test, module_has_storage},\n },\n messages::discovery::CustomMessageHandler,\n};\n\nuse compute_note_hash_and_nullifier::generate_contract_library_methods_compute_note_hash_and_nullifier;\n\n/// Configuration for the [`aztec`] macro.\n///\n/// This type lets users override different parts of the default aztec-nr contract behavior, such\n/// as message handling. These are advanced features that require careful understanding of\n/// the behavior of these systems.\n///\n/// ## Examples\n///\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyContract { ... }\n/// ```\npub struct AztecConfig {\n custom_message_handler: Option>,\n}\n\nimpl AztecConfig {\n /// Creates a new `AztecConfig` with default values.\n ///\n /// Calling `new` is equivalent to invoking the [`aztec`] macro with no parameters. The different methods\n /// (e.g. [`AztecConfig::custom_message_handler`]) can then be used to change the default behavior.\n pub comptime fn new() -> Self {\n Self { custom_message_handler: Option::none() }\n }\n\n /// Sets a handler for custom messages.\n ///\n /// This enables contracts to process non-standard messages (i.e. any with a message type that is not in\n /// [`crate::messages::msg_type`]).\n ///\n /// `handler` must be a function that conforms to the\n /// [`crate::messages::discovery::CustomMessageHandler`] type signature.\n pub comptime fn custom_message_handler(_self: Self, handler: CustomMessageHandler<()>) -> Self {\n Self { custom_message_handler: Option::some(handler) }\n }\n}\n\n/// Enables aztec-nr features on a `contract`.\n///\n/// All aztec-nr contracts should have this macro invoked on them, as it is the one that processes all contract\n/// functions, notes, storage, generates interfaces for external calls, and creates the message processing\n/// boilerplate.\n///\n/// ## Examples\n///\n/// Most contracts can simply invoke the macro with no parameters, resulting in default aztec-nr behavior:\n/// ```noir\n/// #[aztec]\n/// contract MyContract { ... }\n/// ```\n///\n/// Advanced contracts can use [`AztecConfig`] to customize parts of its behavior, such as message\n/// processing.\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyAdvancedContract { ... }\n/// ```\n#[varargs]\npub comptime fn aztec(m: Module, args: [AztecConfig]) -> Quoted {\n let num_args = args.len();\n let config = if num_args == 0 {\n AztecConfig::new()\n } else if num_args == 1 {\n args[0]\n } else {\n panic(f\"#[aztec] expects 0 or 1 arguments, got {num_args}\")\n };\n\n // Functions that don't have #[external(...)], #[contract_library_method], or #[test] are not allowed in contracts.\n check_each_fn_macroified(m);\n\n // We generate new functions prefixed with `__aztec_nr_internals__` and we replace the original functions' bodies\n // with `static_assert(false, ...)` to prevent them from being called directly from within the contract.\n let functions = process_functions(m);\n\n // We generate structs and their implementations necessary for convenient functions calls.\n let interface = generate_contract_interface(m);\n let self_call_structs = generate_external_function_self_calls_structs(m);\n let call_internal_struct = generate_call_internal_struct(m);\n\n // We generate ABI exports for all the external functions in the contract.\n let fn_abi_exports = create_fn_abi_exports(m);\n\n // We generate `_compute_note_hash`, `_compute_note_nullifier` (and the deprecated\n // `_compute_note_hash_and_nullifier` wrapper) and `sync_state` functions only if they are not already implemented.\n // If they are implemented we just insert empty quotes.\n let contract_library_method_compute_note_hash_and_nullifier = if !m.functions().any(|f| {\n // Note that we don't test for `_compute_note_hash` or `_compute_note_nullifier` in order to make this simpler\n // - users must either implement all three or none.\n // Down the line we'll remove this check and use `AztecConfig`.\n f.name() == quote { _compute_note_hash_and_nullifier }\n }) {\n generate_contract_library_methods_compute_note_hash_and_nullifier()\n } else {\n quote {}\n };\n let process_custom_message_option = if config.custom_message_handler.is_some() {\n let handler = config.custom_message_handler.unwrap();\n quote { Option::some($handler) }\n } else {\n quote { Option::>::none() }\n };\n\n let offchain_inbox_sync_option = quote {\n Option::some(aztec::messages::processing::offchain::sync_inbox)\n };\n\n let sync_state_fn_and_abi_export = if !m.functions().any(|f| f.name() == quote { sync_state }) {\n generate_sync_state(process_custom_message_option, offchain_inbox_sync_option)\n } else {\n quote {}\n };\n\n if m.functions().any(|f| f.name() == quote { offchain_receive }) {\n panic(\n \"User-defined 'offchain_receive' is not allowed. The function is auto-injected by the #[aztec] macro. See https://docs.aztec.network/errors/7\",\n );\n }\n let offchain_receive_fn_and_abi_export = generate_offchain_receive();\n\n let (has_public_init_nullifier_fn, emit_public_init_nullifier_fn_body) = generate_emit_public_init_nullifier(m);\n let public_dispatch = generate_public_dispatch(m, has_public_init_nullifier_fn);\n\n quote {\n $interface\n $self_call_structs\n $call_internal_struct\n $functions\n $fn_abi_exports\n $contract_library_method_compute_note_hash_and_nullifier\n $public_dispatch\n $sync_state_fn_and_abi_export\n $emit_public_init_nullifier_fn_body\n $offchain_receive_fn_and_abi_export\n }\n}\n\ncomptime fn generate_contract_interface(m: Module) -> Quoted {\n let calls = generate_external_function_calls(m);\n\n let module_name = m.name();\n\n let has_storage_layout = module_has_storage(m) & STORAGE_LAYOUT_NAME.get(m).is_some();\n let storage_layout_getter = if has_storage_layout {\n let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap();\n quote {\n pub fn storage_layout() -> StorageLayoutFields {\n $storage_layout_name.fields\n }\n }\n } else {\n quote {}\n };\n\n let library_storage_layout_getter = if has_storage_layout {\n quote {\n #[contract_library_method]\n $storage_layout_getter\n }\n } else {\n quote {}\n };\n\n quote {\n pub struct $module_name {\n pub target_contract: aztec::protocol::address::AztecAddress\n }\n\n impl $module_name {\n $calls\n\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> Self {\n Self { target_contract: addr }\n }\n\n pub fn interface() -> Self {\n Self { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $storage_layout_getter\n }\n\n #[contract_library_method]\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> $module_name {\n $module_name { target_contract: addr }\n }\n\n #[contract_library_method]\n pub fn interface() -> $module_name {\n $module_name { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $library_storage_layout_getter\n\n }\n}\n\n/// Generates the `sync_state` utility function that performs message discovery.\ncomptime fn generate_sync_state(process_custom_message_option: Quoted, offchain_inbox_sync_option: Quoted) -> Quoted {\n quote {\n pub struct sync_state_parameters {\n pub scope: aztec::protocol::address::AztecAddress,\n }\n\n #[abi(functions)]\n pub struct sync_state_abi {\n parameters: sync_state_parameters,\n }\n\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn sync_state(scope: aztec::protocol::address::AztecAddress) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::discovery::do_sync_state(\n address,\n _compute_note_hash,\n _compute_note_nullifier,\n $process_custom_message_option,\n $offchain_inbox_sync_option,\n scope,\n );\n }\n }\n}\n\n/// Generates an `offchain_receive` utility function that lets callers add messages to the offchain message inbox.\n///\n/// For more details, see `aztec::messages::processing::offchain::receive`.\ncomptime fn generate_offchain_receive() -> Quoted {\n let param_type = offchain_receive_param_type(quote { aztec });\n let parameters_struct_name = f\"{OFFCHAIN_RECEIVE_FN_NAME}_parameters\".quoted_contents();\n let abi_struct_name = f\"{OFFCHAIN_RECEIVE_FN_NAME}_abi\".quoted_contents();\n\n quote {\n pub struct $parameters_struct_name {\n pub $OFFCHAIN_RECEIVE_PARAM_NAME: $param_type,\n }\n\n #[abi(functions)]\n pub struct $abi_struct_name {\n parameters: $parameters_struct_name,\n }\n\n /// Receives offchain messages into this contract's offchain inbox for subsequent processing.\n ///\n /// Each message is routed to the inbox scoped to its `recipient` field.\n ///\n /// For more details, see `aztec::messages::processing::offchain::receive`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn $OFFCHAIN_RECEIVE_FN_NAME($OFFCHAIN_RECEIVE_PARAM_NAME: $param_type) -> $OFFCHAIN_RECEIVE_RETURN_TYPE {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::processing::offchain::receive(address, $OFFCHAIN_RECEIVE_PARAM_NAME);\n }\n }\n}\n\n/// Checks that all functions in the module have a context macro applied.\n///\n/// Non-macroified functions are not allowed in contracts. They must all be one of\n/// [`crate::macros::functions::external`], [`crate::macros::functions::internal`] or `test`.\ncomptime fn check_each_fn_macroified(m: Module) {\n for f in m.functions() {\n let name = f.name();\n if !is_fn_external(f) & !is_fn_contract_library_method(f) & !is_fn_internal(f) & !is_fn_test(f) {\n // We don't suggest that #[contract_library_method] is allowed because we don't want to introduce another\n // concept\n panic(\n f\"Function {name} must be marked as either #[external(...)], #[internal(...)], or #[test]\",\n );\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec.nr","function_locations":[{"start":1825,"name":"AztecConfig::new"},{"start":2333,"name":"AztecConfig::custom_message_handler"},{"start":3227,"name":"aztec"},{"start":6704,"name":"generate_contract_interface"},{"start":8566,"name":"generate_sync_state"},{"start":9620,"name":"generate_offchain_receive"},{"start":11209,"name":"check_each_fn_macroified"}]},"105":{"source":"use crate::macros::internals_functions_generation::external_functions_registry::get_public_functions;\nuse crate::protocol::meta::utils::get_params_len_quote;\nuse crate::utils::cmap::CHashMap;\nuse super::functions::initialization_utils::EMIT_PUBLIC_INIT_NULLIFIER_FN_NAME;\nuse super::utils::compute_fn_selector;\nuse std::panic;\n\n/// Generates a `public_dispatch` function for an Aztec contract module `m`.\n///\n/// The generated function dispatches public calls based on selector to the appropriate contract function. If\n/// `generate_emit_public_init_nullifier` is true, it also handles dispatch to the macro-generated\n/// `__emit_public_init_nullifier` function.\npub comptime fn generate_public_dispatch(m: Module, generate_emit_public_init_nullifier: bool) -> Quoted {\n let functions = get_public_functions(m);\n\n let unit = get_type::<()>();\n\n let seen_selectors = &mut CHashMap::::new();\n\n let mut ifs = functions.map(|function: FunctionDefinition| {\n let parameters = function.parameters();\n let return_type = function.return_type();\n\n let fn_name = function.name();\n let selector: Field = compute_fn_selector(fn_name, parameters);\n\n // Since function selectors are computed as the first 4 bytes of the hash of the function signature, it's\n // possible to have collisions. With the following check, we ensure it doesn't happen within the same contract.\n let existing_fn = seen_selectors.get(selector);\n if existing_fn.is_some() {\n let existing_fn = existing_fn.unwrap();\n panic(\n f\"Public function selector collision detected between functions '{fn_name}' and '{existing_fn}'\",\n );\n }\n seen_selectors.insert(selector, fn_name);\n\n let params_len_quote = get_params_len_quote(parameters);\n\n let initial_read = if parameters.len() == 0 {\n quote {}\n } else {\n // The initial calldata_copy offset is 1 to skip the Field selector The expected calldata is the\n // serialization of\n // - FunctionSelector: the selector of the function intended to dispatch\n // - Parameters: the parameters of the function intended to dispatch That is, exactly what is expected for\n // a call to the target function, but with a selector added at the beginning.\n quote {\n let input_calldata: [Field; $params_len_quote] = aztec::oracle::avm::calldata_copy(1, $params_len_quote);\n let mut reader = aztec::protocol::utils::reader::Reader::new(input_calldata);\n }\n };\n\n let parameter_index: &mut u32 = &mut 0;\n let reads = parameters.map(|param: (Quoted, Type)| {\n let parameter_index_value = *parameter_index;\n let param_name = f\"arg{parameter_index_value}\".quoted_contents();\n let param_type = param.1;\n let read = quote {\n let $param_name: $param_type = aztec::protocol::traits::Deserialize::stream_deserialize(&mut reader);\n };\n *parameter_index += 1;\n quote { $read }\n });\n let read = reads.join(quote { });\n\n let mut args = @[];\n for parameter_index in 0..parameters.len() {\n let param_name = f\"arg{parameter_index}\".quoted_contents();\n args = args.push_back(quote { $param_name });\n }\n\n // We call a function whose name is prefixed with `__aztec_nr_internals__`. This is necessary because the\n // original function is intentionally made uncallable, preventing direct invocation within the contract.\n // Instead, a new function with the same name, but prefixed by `__aztec_nr_internals__`, has been generated to\n // be called here. For more details see the `process_functions` function.\n let name = f\"__aztec_nr_internals__{fn_name}\".quoted_contents();\n let args = args.join(quote { , });\n let call = quote { $name($args) };\n\n let return_code = if return_type == unit {\n quote {\n $call;\n // Force early return.\n aztec::oracle::avm::avm_return([]);\n }\n } else {\n quote {\n let return_value = aztec::protocol::traits::Serialize::serialize($call);\n aztec::oracle::avm::avm_return(return_value.as_vector());\n }\n };\n\n let if_ = quote {\n if selector == $selector {\n $initial_read\n $read\n $return_code\n }\n };\n if_\n });\n\n // If we injected the auto-generated public function to emit the public initialization nullifier, then\n // we'll also need to handle its dispatch.\n if generate_emit_public_init_nullifier {\n let name = EMIT_PUBLIC_INIT_NULLIFIER_FN_NAME;\n let init_nullifier_selector: Field = compute_fn_selector(name, @[]);\n\n ifs = ifs.push_back(\n quote {\n if selector == $init_nullifier_selector {\n $name();\n aztec::oracle::avm::avm_return([]);\n }\n },\n );\n }\n\n if ifs.len() == 0 {\n // No dispatch function if there are no public functions\n quote {}\n } else {\n let ifs = ifs.push_back(quote { panic(f\"Unknown selector {selector}\") });\n let dispatch = ifs.join(quote { });\n\n let body = quote {\n // We mark this as public because our whole system depends on public functions having this attribute.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]\n pub unconstrained fn public_dispatch(selector: Field) {\n $dispatch\n }\n };\n\n body\n }\n}\n\ncomptime fn get_type() -> Type {\n let t: T = std::mem::zeroed();\n std::meta::type_of(t)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/dispatch.nr","function_locations":[{"start":768,"name":"generate_public_dispatch"},{"start":5832,"name":"get_type"}]},"113":{"source":"use crate::macros::{\n functions::auth_registry::AUTHORIZE_ONCE_REGISTRY,\n utils::{is_fn_initializer, is_fn_only_self, is_fn_view},\n};\n\n/// Gathers all attributes relevant to the function's ABI and returns a quote that can be applied to the newly\n/// generated function. We apply the abi marker attributes instead of the original ones (e.g. abi_view instead of view)\n/// to avoid the relevant attribute's functionality from getting triggered.\npub(crate) comptime fn get_abi_relevant_attributes(f: FunctionDefinition) -> Quoted {\n let mut attributes = quote {};\n\n if is_fn_view(f) {\n attributes = quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_view] };\n }\n\n if is_fn_only_self(f) {\n attributes =\n quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_only_self] };\n }\n\n if is_fn_initializer(f) {\n attributes =\n quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_initializer] };\n }\n\n attributes\n}\n\n/// Injects an authwit verification check of the form:\n/// ```\n/// if (!from.eq(context.maybe_msg_sender().unwrap())) {\n/// assert_current_call_valid_authwit::(&mut context, from);\n/// } else {\n/// assert(authwit_nonce, \"Invalid authwit nonce. When 'from' and 'msg_sender' are the\n/// same, authwit_nonce must be zero\");\n/// }\n/// ```\n/// where `from` and `authwit_nonce` are the names of the parameters that are expected to be present in the function\n/// definition. This check is injected by the `#[authorize_once(\"from_arg_name\", \"nonce_arg_name\")]`, which allows the\n/// user to define which parameters to use.\n///\n/// # Arguments\n/// * `f` - The function definition to inject the authwit verification check into. The function must have parameters\n/// matching the names specified in the `#[authorize_once]` attribute.\n/// * `is_private` - Whether the function is a private function (`true`) or a public function (`false`). This\n/// determines which authwit verification method to use: `assert_current_call_valid_authwit` for private functions or\n/// `assert_current_call_valid_authwit_public` for public functions.\npub(crate) comptime fn create_authorize_once_check(f: FunctionDefinition, is_private: bool) -> Quoted {\n let maybe_authorize_once_args = AUTHORIZE_ONCE_REGISTRY.get(f);\n let authorize_once_args = if maybe_authorize_once_args.is_some() {\n maybe_authorize_once_args.unwrap()\n } else {\n // We need to for authorize_once to have already executed so that we can retrieve its params - this depends on\n // the order in which the attributes are applied.\n panic(\n f\"Functions marked with #[authorize_once] must have the #[external(\\\"private\\\")] or #[external(\\\"public\\\")] attribute placed last\",\n )\n };\n\n let (from_arg_name, nonce_arg_name) = authorize_once_args;\n let name: Quoted = f.name();\n\n let from_arg_candidates = f.parameters().filter(|(name, _)| name == f\"{from_arg_name}\".quoted_contents());\n let (from_arg_name_quoted, from_arg_type) = if from_arg_candidates.len() == 1 {\n from_arg_candidates[0]\n } else {\n panic(\n f\"Function {name} does not have a {from_arg_name} parameter. Please specify which one to use in #[authorize_once(\\\"...\\\", \\\"authwit_nonce\\\")]\",\n )\n };\n if from_arg_type != quote { crate::protocol::address::aztec_address::AztecAddress }.as_type() {\n panic(\n f\"Argument {from_arg_name_quoted} in function {name} must be of type AztecAddress, but is of type {from_arg_type}\",\n )\n }\n\n let nonce_arg_candidates = f.parameters().filter(|(name, _)| name == f\"{nonce_arg_name}\".quoted_contents());\n let (nonce_arg_name_quoted, nonce_arg_type) = if nonce_arg_candidates.len() == 1 {\n nonce_arg_candidates[0]\n } else {\n panic(\n f\"Function {name} does not have a {nonce_arg_name}. Please specify which one to use in #[authorize_once(\\\"from\\\", \\\"...\\\")]\",\n )\n };\n if nonce_arg_type != quote { Field }.as_type() {\n panic(\n f\"Argument {nonce_arg_name_quoted} in function {name} must be of type Field, but is of type {nonce_arg_type}\",\n );\n }\n\n let nonce_check_quote = f\"{nonce_arg_name_quoted} == 0\".quoted_contents();\n\n let fn_call = if is_private {\n let params = f.parameters();\n let serialized_len_quote = if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as aztec::protocol::traits::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n };\n quote { aztec::authwit::auth::assert_current_call_valid_authwit::<($serialized_len_quote)> }\n } else {\n quote { aztec::authwit::auth::assert_current_call_valid_authwit_public }\n };\n let invalid_nonce_message = f\"Invalid authwit nonce. When '{from_arg_name}' and 'msg_sender' are the same, '{nonce_arg_name}' must be zero\"\n .as_quoted_str();\n quote { \n if (!$from_arg_name_quoted.eq(self.msg_sender())) {\n $fn_call(self.context, $from_arg_name_quoted);\n } else {\n assert($nonce_check_quote, $invalid_nonce_message);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr","function_locations":[{"start":532,"name":"get_abi_relevant_attributes"},{"start":2334,"name":"create_authorize_once_check"}]},"116":{"source":"use crate::macros::{\n internals_functions_generation::external::helpers::{create_authorize_once_check, get_abi_relevant_attributes},\n utils::{\n fn_has_authorize_once, fn_has_noinitcheck, is_fn_initializer, is_fn_only_self, is_fn_view,\n module_has_initializer, module_has_storage,\n },\n};\n\npub(crate) comptime fn generate_public_external(f: FunctionDefinition) -> Quoted {\n let module_has_initializer = module_has_initializer(f.module());\n let module_has_storage = module_has_storage(f.module());\n\n // Public functions undergo a lot of transformations from their Aztec.nr form.\n let original_params = f.parameters();\n\n let args_len_quote = if original_params.len() == 0 {\n // If the function has no parameters, we set the args_len to 0.\n quote { 0 }\n } else {\n // The following will give us ::N + ::N + ...\n original_params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::protocol::traits::Serialize>::N\n }\n })\n .join(quote {+})\n };\n\n let storage_init = if module_has_storage {\n quote {\n let storage = Storage::init(context);\n }\n } else {\n // Contract does not have Storage defined, so we set storage to the unit type `()`. ContractSelfPublic requires\n // a storage struct in its constructor. Using an Option type would lead to worse developer experience and\n // higher constraint counts so we use the unit type `()` instead.\n quote {\n let storage = ();\n }\n };\n\n // Unlike in the private case, in public the `context` does not need to receive the hash of the original params.\n let contract_self_creation = quote {\n #[allow(unused_variables)]\n let mut self = {\n let context = aztec::context::PublicContext::new(|| {\n // We start from 1 because we skip the selector for the dispatch function.\n let serialized_args : [Field; $args_len_quote] = aztec::oracle::avm::calldata_copy(1, $args_len_quote);\n aztec::hash::hash_args(serialized_args)\n });\n $storage_init\n let self_address = context.this_address();\n let call_self: CallSelf = CallSelf { address: self_address, context };\n let call_self_static: CallSelfStatic = CallSelfStatic { address: self_address, context };\n let internal: CallInternal = CallInternal { context };\n aztec::contract_self::ContractSelfPublic::new(context, storage, call_self, call_self_static, internal)\n };\n };\n\n let original_function_name = f.name();\n\n // Modifications introduced by the different marker attributes.\n let internal_check = if is_fn_only_self(f) {\n let assertion_message = f\"Function {original_function_name} can only be called by the same contract\";\n quote { assert(self.msg_sender() == self.address, $assertion_message); }\n } else {\n quote {}\n };\n\n let view_check = if is_fn_view(f) {\n let assertion_message = f\"Function {original_function_name} can only be called statically\".as_quoted_str();\n quote { assert(self.context.is_static_call(), $assertion_message); }\n } else {\n quote {}\n };\n\n let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) {\n (\n quote { aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_public(self.context); },\n quote { aztec::macros::functions::initialization_utils::mark_as_initialized_from_public_initializer(self.context); },\n )\n } else {\n (quote {}, quote {})\n };\n\n // Initialization checks are not included in contracts that don't have initializers.\n let init_check = if module_has_initializer & !fn_has_noinitcheck(f) & !is_fn_initializer(f) {\n quote { aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); }\n } else {\n quote {}\n };\n\n // Inject the authwit check if the function is marked with #[authorize_once].\n let authorize_once_check = if fn_has_authorize_once(f) {\n create_authorize_once_check(f, false)\n } else {\n quote {}\n };\n\n let to_prepend = quote {\n $contract_self_creation\n $assert_initializer\n $init_check\n $internal_check\n $view_check\n $authorize_once_check\n };\n\n // `mark_as_initialized` is placed after the user's function body. If it ran at the beginning, the contract\n // would appear initialized while the initializer is still running, allowing contracts called by the initializer\n // to re-enter into a half-initialized contract.\n let to_append = quote {\n $mark_as_initialized\n };\n\n let fn_name = f\"__aztec_nr_internals__{original_function_name}\".quoted_contents();\n let body = f.body();\n let return_type = f.return_type();\n\n // New function parameters are the same as the original function's ones.\n let params = original_params.map(|(param_name, param_type)| quote { $param_name: $param_type }).join(quote {, });\n\n // Preserve all attributes that are relevant to the function's ABI.\n let abi_relevant_attributes = get_abi_relevant_attributes(f);\n\n // All public functions are automatically made unconstrained, even if they were not marked as such. This is because\n // instead of compiling into a circuit, they will compile to bytecode that will be later transpiled into AVM\n // bytecode.\n quote {\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]\n $abi_relevant_attributes\n unconstrained fn $fn_name($params) -> pub $return_type {\n $to_prepend\n $body\n $to_append\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr","function_locations":[{"start":392,"name":"generate_public_external"}]},"127":{"source":"use crate::logging::{aztecnr_debug_log, aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\npub(crate) mod nonce_discovery;\npub(crate) mod partial_notes;\npub(crate) mod private_events;\npub mod private_notes;\npub mod process_message;\n\nuse crate::{\n messages::{\n discovery::process_message::process_message_ciphertext,\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{\n MessageContext, offchain::OffchainInboxSync, OffchainMessageWithContext,\n pending_tagged_log::PendingTaggedLog, validate_and_store_enqueued_notes_and_events,\n },\n },\n oracle::message_processing,\n utils::array,\n};\n\npub struct NoteHashAndNullifier {\n /// The result of [`crate::note::note_interface::NoteHash::compute_note_hash`].\n pub note_hash: Field,\n /// The result of [`crate::note::note_interface::NoteHash::compute_nullifier_unconstrained`].\n ///\n /// This value is unconstrained, as all of message discovery is unconstrained. It is `None` if the nullifier\n /// cannot be computed (e.g. because the nullifier hiding key is not available).\n pub inner_nullifier: Option,\n}\n\n/// A contract's way of computing note hashes.\n///\n/// Each contract in the network is free to compute their note's hash as they see fit - the hash function itself is not\n/// enshrined or standardized. Some aztec-nr functions however do need to know the details of this computation (e.g.\n/// when finding new notes), which is what this type represents.\n///\n/// This function takes a note's packed content, storage slot, note type ID, address of the emitting contract and\n/// randomness, and attempts to compute its inner note hash (not siloed by address nor uniqued by nonce).\n///\n/// ## Transient Notes\n///\n/// This function is meant to always be used on **settled** notes, i.e. those that have been inserted into the trees\n/// and for which the nonce is known. It is never invoked in the context of a transient note, as those are not involved\n/// in message processing.\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract by inspecting all note types in use and the storage layout. This injected function is a\n/// `#[contract_library_method]` called `_compute_note_hash`, and it looks something like this:\n///\n/// ```noir\n/// |packed_note, owner, storage_slot, note_type_id, _contract_address, randomness| {\n/// if note_type_id == MyNoteType::get_id() {\n/// if packed_note.len() != MY_NOTE_TYPE_SERIALIZATION_LENGTH {\n/// Option::none()\n/// } else {\n/// let note = MyNoteType::unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n/// Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n/// }\n/// } else if note_type_id == MyOtherNoteType::get_id() {\n/// ... // Similar to above but calling MyOtherNoteType::unpack\n/// } else {\n/// Option::none() // Unknown note type ID\n/// };\n/// }\n/// ```\npub type ComputeNoteHash = unconstrained fn(/* packed_note */BoundedVec, /*\n owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress, /*\nrandomness */ Field) -> Option;\n\n/// A contract's way of computing note nullifiers.\n///\n/// Like [`ComputeNoteHash`], each contract is free to derive nullifiers as they see fit. This function takes the\n/// unique note hash (used as the note hash for nullification for settled notes), plus the note's packed content and\n/// metadata, and attempts to compute the inner nullifier (not siloed by address).\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract called `_compute_note_nullifier`. It dispatches on `note_type_id` similarly to\n/// [`ComputeNoteHash`], then calls the note's\n/// [`compute_nullifier_unconstrained`](crate::note::note_interface::NoteHash::compute_nullifier_unconstrained) method.\npub type ComputeNoteNullifier = unconstrained fn(/* unique_note_hash */Field, /* packed_note */ BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/* randomness */ Field) -> Option;\n\n/// Deprecated: use [`ComputeNoteHash`] and [`ComputeNoteNullifier`] instead.\npub type ComputeNoteHashAndNullifier = unconstrained fn[Env](/* packed_note */BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/*randomness */ Field, /* note nonce */ Field) -> Option;\n\n/// A handler for custom messages.\n///\n/// Contracts that emit custom messages (i.e. any with a message type that is not in [`crate::messages::msg_type`])\n/// need to use [`crate::macros::AztecConfig::custom_message_handler`] with a function of this type in order to\n/// process them. They will otherwise be **silently ignored**.\npub type CustomMessageHandler = unconstrained fn[Env](\n/* contract_address */AztecAddress,\n/* msg_type_id */ u64,\n/* msg_metadata */ u64,\n/* msg_content */ BoundedVec,\n/* message_context */ MessageContext,\n/* scope */ AztecAddress);\n\n/// Synchronizes the contract's private state with the network.\n///\n/// As blocks are mined, it is possible for a contract's private state to change (e.g. with new notes being created),\n/// but because these changes are private they will be invisible to most actors. This is the function that processes\n/// new transactions in order to discover new notes, events, and other kinds of private state changes.\n///\n/// The private state will be synchronized up to the block that will be used for private transactions (i.e. the anchor\n/// block. This will typically be close to the tip of the chain.\npub unconstrained fn do_sync_state(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n offchain_inbox_sync: Option>,\n scope: AztecAddress,\n) {\n aztecnr_debug_log!(\"Performing state synchronization\");\n\n // First we process all private logs, which can contain different kinds of messages e.g. private notes, partial\n // notes, private events, etc.\n let logs = message_processing::get_pending_tagged_logs(scope);\n logs.for_each(|_i, pending_tagged_log: PendingTaggedLog| {\n if pending_tagged_log.log.len() == 0 {\n aztecnr_warn_log_format!(\"Skipping empty log from tx {0}\")([pending_tagged_log.context.tx_hash]);\n } else {\n aztecnr_debug_log_format!(\"Processing log with tag {0}\")([pending_tagged_log.log.get(0)]);\n\n // We remove the tag from the pending tagged log and process the message ciphertext contained in it.\n let message_ciphertext = array::subbvec(pending_tagged_log.log, 1);\n\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_ciphertext,\n pending_tagged_log.context,\n scope,\n );\n }\n });\n\n if offchain_inbox_sync.is_some() {\n let msgs = offchain_inbox_sync.unwrap()(contract_address, scope);\n msgs.for_each(|_i, msg: OffchainMessageWithContext| {\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n msg.message_ciphertext,\n msg.message_context,\n scope,\n );\n });\n }\n\n // Then we process all pending partial notes, regardless of whether they were found in the current or previous\n // executions.\n partial_notes::fetch_and_process_partial_note_completion_logs(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n scope,\n );\n\n // Finally we validate all notes and events that were found as part of the previous processes, resulting in them\n // being added to PXE's database and retrievable via oracles (get_notes) and our TS API (PXE::getPrivateEvents).\n validate_and_store_enqueued_notes_and_events(scope);\n}\n\nmod test {\n use crate::ephemeral::EphemeralArray;\n use crate::messages::{\n discovery::{CustomMessageHandler, do_sync_state},\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{offchain::OffchainInboxSync, pending_tagged_log::PendingTaggedLog},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n\n #[test]\n unconstrained fn do_sync_state_does_not_panic_on_empty_logs() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n\n let contract_address = AztecAddress { inner: 0xdeadbeef };\n\n env.utility_context_at(contract_address, |_| {\n // Mock the oracle call to return a known base slot, then populate an ephemeral\n // array at that slot so do_sync_state processes a non-empty log list.\n let base_slot = 42;\n let mock = std::test::OracleMock::mock(\"aztec_utl_getPendingTaggedLogs_v2\");\n let _ = mock.returns(base_slot);\n\n let logs: EphemeralArray = EphemeralArray::at(base_slot);\n logs.push(PendingTaggedLog { log: BoundedVec::new(), context: std::mem::zeroed() });\n assert_eq(logs.len(), 1);\n\n let no_handler: Option> = Option::none();\n let no_inbox_sync: Option> = Option::none();\n do_sync_state(\n contract_address,\n dummy_compute_note_hash,\n dummy_compute_note_nullifier,\n no_handler,\n no_inbox_sync,\n scope,\n );\n });\n }\n\n unconstrained fn dummy_compute_note_hash(\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n\n unconstrained fn dummy_compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr","function_locations":[{"start":6465,"name":"do_sync_state"},{"start":9175,"name":"test::do_sync_state_does_not_panic_on_empty_logs"},{"start":10673,"name":"test::dummy_compute_note_hash"},{"start":11034,"name":"test::dummy_compute_note_nullifier"}]},"128":{"source":"use crate::messages::{discovery::{ComputeNoteHash, ComputeNoteNullifier}, logs::note::MAX_NOTE_PACKED_LEN};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{\n address::AztecAddress,\n constants::MAX_NOTE_HASHES_PER_TX,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::ToField,\n};\n\n/// A struct with the discovered information of a complete note, required for delivery to PXE. Note that this is *not*\n/// the complete note information, since it does not include content, storage slot, etc.\npub(crate) struct DiscoveredNoteInfo {\n pub(crate) note_nonce: Field,\n pub(crate) note_hash: Field,\n pub(crate) inner_nullifier: Field,\n}\n\n/// Searches for note nonces that will result in a note that was emitted in a transaction. While rare, it is possible\n/// for multiple notes to have the exact same packed content and storage slot but different nonces, resulting in\n/// different unique note hashes. Because of this this function returns a *vector* of discovered notes, though in most\n/// cases it will contain a single element.\n///\n/// Due to how nonces are computed, this function requires knowledge of the transaction in which the note was created,\n/// more specifically the list of all unique note hashes in it plus the value of its first nullifier.\npub(crate) unconstrained fn attempt_note_nonce_discovery(\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) -> BoundedVec {\n let discovered_notes = &mut BoundedVec::new();\n\n aztecnr_debug_log_format!(\n \"Attempting nonce discovery on {0} potential notes on contract {1} for storage slot {2}\",\n )(\n [unique_note_hashes_in_tx.len() as Field, contract_address.to_field(), storage_slot],\n );\n\n let maybe_note_hash = compute_note_hash(\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_note_hash.is_none() {\n aztecnr_warn_log_format!(\n \"Unable to compute note hash for note of id {0} with packed length {1}, skipping nonce discovery\",\n )(\n [note_type_id, packed_note.len() as Field],\n );\n } else {\n let note_hash = maybe_note_hash.unwrap();\n let siloed_note_hash = compute_siloed_note_hash(contract_address, note_hash);\n\n // We need to find nonces (typically just one) that result in the siloed note hash that being uniqued into one\n // of the transaction's effects.\n // The nonce is meant to be derived from the index of the note hash in the transaction effects array. However,\n // due to an issue in the kernels the nonce might actually use any of the possible note hash indices - not\n // necessarily the one that corresponds to the note hash. Hence, we need to try them all.\n for i in 0..MAX_NOTE_HASHES_PER_TX {\n let nonce_for_i = compute_note_hash_nonce(first_nullifier_in_tx, i);\n let unique_note_hash_for_i = compute_unique_note_hash(nonce_for_i, siloed_note_hash);\n\n let matching_notes = bvec_filter(\n unique_note_hashes_in_tx,\n |unique_note_hash_in_tx| unique_note_hash_in_tx == unique_note_hash_for_i,\n );\n if matching_notes.len() > 1 {\n let identical_note_hashes = matching_notes.len();\n // Note that we don't actually check that the note hashes array contains unique values, only that the\n // note we found is unique. We don't expect for this to ever happen (it'd indicate a malicious node or\n // PXE, which are both assumed to be cooperative) so testing for it just in case is unnecessary, but we\n // _do_ need to handle it if we find a duplicate.\n panic(\n f\"Received {identical_note_hashes} identical note hashes for a transaction - these should all be unique\",\n )\n } else if matching_notes.len() == 1 {\n let maybe_inner_nullifier_for_i = compute_note_nullifier(\n unique_note_hash_for_i,\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_inner_nullifier_for_i.is_none() {\n // TODO: down the line we want to be able to store notes for which we don't know their nullifier,\n // e.g. notes that belong to someone that is not us (and for which we therefore don't know their\n // associated app-siloed nullifer hiding secret key).\n // https://linear.app/aztec-labs/issue/F-265/store-external-notes\n aztecnr_warn_log_format!(\n \"Unable to compute nullifier of unique note {0} with note type id {1} and owner {2}, skipping PXE insertion\",\n )(\n [unique_note_hash_for_i, note_type_id, owner.to_field()],\n );\n } else {\n // Note that while we did check that the note hash is the preimage of a unique note hash, we\n // perform no validations on the nullifier - we fundamentally cannot, since only the application\n // knows how to compute nullifiers. We simply trust it to have provided the correct one: if it\n // hasn't, then PXE may fail to realize that a given note has been nullified already, and calls to\n // the application could result in invalid transactions (with duplicate nullifiers). This is not a\n // concern because an application already has more direct means of making a call to it fail the\n // transaction.\n discovered_notes.push(\n DiscoveredNoteInfo {\n note_nonce: nonce_for_i,\n note_hash,\n inner_nullifier: maybe_inner_nullifier_for_i.unwrap(),\n },\n );\n }\n // We don't exit the loop - it is possible (though rare) for the exact same note content to be present\n // multiple times in the same transaction with different nonces. This typically doesn't happen due to\n // notes containing random values in order to hide their contents.\n }\n }\n }\n\n *discovered_notes\n}\n\n// There is no BoundedVec::filter in the stdlib, so we use this until that is implemented.\nunconstrained fn bvec_filter(\n bvec: BoundedVec,\n filter: fn[Env](T) -> bool,\n) -> BoundedVec {\n let filtered = &mut BoundedVec::new();\n\n bvec.for_each(|value| {\n if filter(value) {\n filtered.push(value);\n }\n });\n\n *filtered\n}\n\nmod test {\n use crate::{\n messages::logs::note::MAX_NOTE_PACKED_LEN,\n note::{\n note_interface::{NoteHash, NoteType},\n note_metadata::SettledNoteMetadata,\n utils::compute_note_hash_for_nullification,\n },\n oracle::random::random,\n test::mocks::mock_note::MockNote,\n utils::array,\n };\n\n use crate::protocol::{\n address::AztecAddress,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::{FromField, Packable},\n };\n\n use super::attempt_note_nonce_discovery;\n\n // This implementation could be simpler, but this serves as a nice example of the expected flow in a real\n // implementation, and as a sanity check that the interface is sufficient.\n\n unconstrained fn compute_note_hash(\n packed_note: BoundedVec,\n owner: AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n } else {\n Option::none()\n }\n }\n\n unconstrained fn compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n note.compute_nullifier_unconstrained(owner, unique_note_hash)\n } else {\n Option::none()\n }\n }\n\n global VALUE: Field = 7;\n global FIRST_NULLIFIER_IN_TX: Field = 47;\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress::from_field(13);\n global OWNER: AztecAddress = AztecAddress::from_field(14);\n global STORAGE_SLOT: Field = 99;\n global RANDOMNESS: Field = 99;\n\n #[test]\n unconstrained fn no_note_hashes() {\n let unique_note_hashes_in_tx = BoundedVec::new();\n let packed_note = BoundedVec::new();\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n packed_note,\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_hash_computation_is_ignored() {\n let unique_note_hashes_in_tx = BoundedVec::from_array([random()]);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n |_, _, _, _, _, _| Option::none(),\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::new(),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_nullifier_computation_is_ignored() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n |_, _, _, _, _, _, _| Option::none(),\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n struct NoteAndData {\n note: MockNote,\n note_nonce: Field,\n note_hash: Field,\n unique_note_hash: Field,\n inner_nullifier: Field,\n }\n\n unconstrained fn construct_note(value: Field, note_index_in_tx: u32) -> NoteAndData {\n let note_nonce = compute_note_hash_nonce(FIRST_NULLIFIER_IN_TX, note_index_in_tx);\n\n let hinted_note = MockNote::new(value)\n .contract_address(CONTRACT_ADDRESS)\n .owner(OWNER)\n .randomness(RANDOMNESS)\n .storage_slot(STORAGE_SLOT)\n .note_metadata(SettledNoteMetadata::new(note_nonce).into())\n .build_hinted_note();\n let note = hinted_note.note;\n\n let note_hash = note.compute_note_hash(OWNER, STORAGE_SLOT, RANDOMNESS);\n let unique_note_hash = compute_unique_note_hash(\n note_nonce,\n compute_siloed_note_hash(CONTRACT_ADDRESS, note_hash),\n );\n let inner_nullifier = note\n .compute_nullifier_unconstrained(OWNER, compute_note_hash_for_nullification(hinted_note))\n .expect(f\"Could not compute nullifier for note owned by {OWNER}\");\n\n NoteAndData { note, note_nonce, note_hash, unique_note_hash, inner_nullifier }\n }\n\n #[test]\n unconstrained fn single_note() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn multiple_notes_same_preimage() {\n let first_note_index_in_tx = 3;\n let first_note_and_data = construct_note(VALUE, first_note_index_in_tx);\n\n let second_note_index_in_tx = 5;\n let second_note_and_data = construct_note(VALUE, second_note_index_in_tx);\n\n // Both notes have the same preimage (and therefore packed representation), so both should be found in the same\n // call.\n assert_eq(first_note_and_data.note, second_note_and_data.note);\n let packed_note = first_note_and_data.note.pack();\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(first_note_index_in_tx, first_note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(second_note_index_in_tx, second_note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(packed_note),\n );\n\n assert_eq(discovered_notes.len(), 2);\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == first_note_and_data.note_nonce)\n & (discovered_note.note_hash == first_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == first_note_and_data.inner_nullifier)\n }));\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == second_note_and_data.note_nonce)\n & (discovered_note.note_hash == second_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == second_note_and_data.inner_nullifier)\n }));\n }\n\n #[test]\n unconstrained fn single_note_misaligned_nonce() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The note is not at the correct index\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn single_note_nonce_with_index_past_note_hashes_in_tx() {\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The nonce is computed with an index that does not exist in the tx\n let note_index_in_tx = unique_note_hashes_in_tx.len() + 5;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n // The note is inserted at an arbitrary index - its true index is out of the array's bounds\n unique_note_hashes_in_tx.set(2, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test(should_fail_with = \"identical note hashes for a transaction\")]\n unconstrained fn duplicate_unique_note_hashes() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The same unique note hash is present in two indices in the array, which is not allowed. Note that we don't\n // test all note hashes for uniqueness, only those that we actually find.\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let _ = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/nonce_discovery.nr","function_locations":[{"start":1866,"name":"attempt_note_nonce_discovery"},{"start":7210,"name":"bvec_filter"},{"start":8458,"name":"test::compute_note_hash"},{"start":9107,"name":"test::compute_note_nullifier"},{"start":9764,"name":"test::no_note_hashes"},{"start":10362,"name":"test::failed_hash_computation_is_ignored"},{"start":10959,"name":"test::failed_nullifier_computation_is_ignored"},{"start":12052,"name":"test::construct_note"},{"start":13085,"name":"test::single_note"},{"start":14249,"name":"test::multiple_notes_same_preimage"},{"start":16275,"name":"test::single_note_misaligned_nonce"},{"start":17515,"name":"test::single_note_nonce_with_index_past_note_hashes_in_tx"},{"start":18937,"name":"test::duplicate_unique_note_hashes"}]},"129":{"source":"use crate::{\n capsules::CapsuleArray,\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::partial_note::{decode_partial_note_private_message, MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN},\n processing::{\n enqueue_note_for_validation,\n get_pending_partial_notes_completion_logs,\n log_retrieval_response::{LogRetrievalResponse, MAX_LOG_CONTENT_LEN},\n },\n },\n utils::array,\n};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{address::AztecAddress, hash::sha256_to_field, traits::{Deserialize, Serialize}};\n\n/// The slot in the PXE capsules where we store a `CapsuleArray` of `DeliveredPendingPartialNote`.\npub(crate) global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT\".as_bytes(),\n);\n\n/// A partial note that was delivered but is still pending completion. Contains the information necessary to find the\n/// log that will complete it and lead to a note being discovered and delivered.\n#[derive(Serialize, Deserialize)]\npub(crate) struct DeliveredPendingPartialNote {\n pub(crate) owner: AztecAddress,\n pub(crate) randomness: Field,\n pub(crate) note_completion_log_tag: Field,\n pub(crate) note_type_id: Field,\n pub(crate) packed_private_note_content: BoundedVec,\n}\n\npub(crate) unconstrained fn process_partial_note_private_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n scope: AztecAddress,\n) {\n let decoded = decode_partial_note_private_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n // We store the information of the partial note we found in a persistent capsule in PXE, so that we can later\n // search for the public log that will complete it.\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content) = decoded.unwrap();\n\n let pending = DeliveredPendingPartialNote {\n owner,\n randomness,\n note_completion_log_tag,\n note_type_id,\n packed_private_note_content,\n };\n\n CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n )\n .push(pending);\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode partial note private message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Searches for logs that would result in the completion of pending partial notes, ultimately resulting in the notes\n/// being delivered to PXE if completed.\npub(crate) unconstrained fn fetch_and_process_partial_note_completion_logs(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n scope: AztecAddress,\n) {\n let pending_partial_notes = CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n );\n\n aztecnr_debug_log_format!(\"{} pending partial notes\")([pending_partial_notes.len() as Field]);\n\n // Each of the pending partial notes might get completed by a log containing its public values. For performance\n // reasons, we fetch all of these logs concurrently and then process them one by one, minimizing the amount of time\n // waiting for the node roundtrip.\n let maybe_completion_logs = get_pending_partial_notes_completion_logs(contract_address, pending_partial_notes);\n\n // Each entry in the maybe completion logs array corresponds to the entry in the pending partial notes array at the\n // same index. This means we can use the same index as we iterate through the responses to get both the partial\n // note and the log that might complete it.\n assert_eq(maybe_completion_logs.len(), pending_partial_notes.len());\n\n maybe_completion_logs.for_each(|i, maybe_log: Option| {\n let pending_partial_note = pending_partial_notes.get(i);\n\n if maybe_log.is_none() {\n aztecnr_debug_log_format!(\"Found no completion logs for partial note with tag {}\")(\n [pending_partial_note.note_completion_log_tag],\n );\n\n // Note that we're not removing the pending partial note from the capsule array, so we will continue\n // searching for this tagged log when performing message discovery in the future until we either find it or\n // the entry is somehow removed from the array.\n } else {\n aztecnr_debug_log_format!(\"Completion log found for partial note with tag {}\")([\n pending_partial_note.note_completion_log_tag,\n ]);\n let log = maybe_log.unwrap();\n\n // The first field in the completion log payload is the storage slot, followed by the public note\n // content fields.\n let storage_slot = log.log_payload.get(0);\n let public_note_content: BoundedVec = array::subbvec(log.log_payload, 1);\n\n // Public fields are assumed to all be placed at the end of the packed representation, so we combine\n // the private and public packed fields (i.e. the contents of the private message and public log\n // plaintext) to get the complete packed content.\n let complete_packed_note = array::append(\n pending_partial_note.packed_private_note_content,\n public_note_content,\n );\n\n let discovered_notes = attempt_note_nonce_discovery(\n log.unique_note_hashes_in_tx,\n log.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n pending_partial_note.note_type_id,\n complete_packed_note,\n );\n\n // TODO(#11627): is there anything reasonable we can do if we get a log but it doesn't result in a note\n // being found?\n if discovered_notes.len() == 0 {\n panic(\n f\"A partial note's completion log did not result in any notes being found - this should never happen\",\n );\n }\n\n aztecnr_debug_log_format!(\"Discovered {0} notes for partial note with tag {1}\")([\n discovered_notes.len() as Field,\n pending_partial_note.note_completion_log_tag,\n ]);\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n discovered_note.note_nonce,\n complete_packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n log.tx_hash,\n );\n });\n\n // Because there is only a single log for a given tag, once we've processed the tagged log then we simply\n // delete the pending work entry, regardless of whether it was actually completed or not.\n pending_partial_notes.remove(i);\n }\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr","function_locations":[{"start":1784,"name":"process_partial_note_private_msg"},{"start":3162,"name":"fetch_and_process_partial_note_completion_logs"}]},"130":{"source":"use crate::{\n event::event_interface::compute_private_serialized_event_commitment,\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::MAX_MESSAGE_CONTENT_LEN, logs::event::decode_private_event_message,\n processing::enqueue_event_for_validation,\n },\n};\nuse crate::protocol::{address::AztecAddress, traits::ToField};\n\npub(crate) unconstrained fn process_private_event_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n) {\n let decoded = decode_private_event_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (event_type_id, randomness, serialized_event) = decoded.unwrap();\n\n let event_commitment =\n compute_private_serialized_event_commitment(serialized_event, randomness, event_type_id.to_field());\n\n enqueue_event_for_validation(\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private event message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_events.nr","function_locations":[{"start":547,"name":"process_private_event_msg"}]},"131":{"source":"use crate::{\n logging::{aztecnr_debug_log_format, aztecnr_warn_log_format},\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::{decode_private_note_message, MAX_NOTE_PACKED_LEN},\n processing::enqueue_note_for_validation,\n },\n protocol::{address::AztecAddress, constants::MAX_NOTE_HASHES_PER_TX, traits::ToField},\n};\n\npub(crate) unconstrained fn process_private_note_msg(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n msg_metadata: u64,\n msg_content: BoundedVec,\n) {\n let decoded = decode_private_note_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (note_type_id, owner, storage_slot, randomness, packed_note) = decoded.unwrap();\n\n attempt_note_discovery(\n contract_address,\n tx_hash,\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private note message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Attempts discovery of a note given information about its contents and the transaction in which it is suspected the\n/// note was created.\npub unconstrained fn attempt_note_discovery(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) {\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n\n if discovered_notes.len() == 0 {\n // A private note message that results in no discovered notes means none of the computed note hashes matched\n // any unique note hash in the transaction. This could indicate a malformed or malicious message (e.g. a sender\n // providing bogus note content).\n aztecnr_warn_log_format!(\n \"Discarding private note message from tx {0} for contract {1}: no matching note hash found in the tx\",\n )(\n [tx_hash, contract_address.to_field()],\n );\n } else {\n aztecnr_debug_log_format!(\n \"Discovered {0} notes from a private message for contract {1}\",\n )(\n [discovered_notes.len() as Field, contract_address.to_field()],\n );\n }\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n owner,\n storage_slot,\n randomness,\n discovered_note.note_nonce,\n packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n tx_hash,\n );\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_notes.nr","function_locations":[{"start":861,"name":"process_private_note_msg"},{"start":2185,"name":"attempt_note_discovery"}]},"132":{"source":"use crate::messages::{\n discovery::{\n ComputeNoteHash, ComputeNoteNullifier, CustomMessageHandler, partial_notes::process_partial_note_private_msg,\n private_events::process_private_event_msg, private_notes::process_private_note_msg,\n },\n encoding::{decode_message, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN},\n encryption::{aes128::AES128, message_encryption::MessageEncryption},\n msg_type::{\n MIN_CUSTOM_MSG_TYPE_ID, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID, PRIVATE_EVENT_MSG_TYPE_ID, PRIVATE_NOTE_MSG_TYPE_ID,\n },\n processing::MessageContext,\n};\n\nuse crate::logging::{aztecnr_debug_log, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\n/// Processes a message that can contain notes, partial notes, or events.\n///\n/// Notes result in nonce discovery being performed prior to delivery, which requires knowledge of the transaction hash\n/// in which the notes would've been created (typically the same transaction in which the log was emitted), along with\n/// the list of unique note hashes in said transaction and the `compute_note_hash` and `compute_note_nullifier`\n/// functions. Once discovered, the notes are enqueued for validation.\n///\n/// Partial notes result in a pending partial note entry being stored in a PXE capsule, which will later be retrieved\n/// to search for the note's completion public log.\n///\n/// Events are processed by computing an event commitment from the serialized event data and its randomness field, then\n/// enqueueing the event data and commitment for validation.\npub unconstrained fn process_message_ciphertext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_ciphertext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n let message_plaintext_option = AES128::decrypt(message_ciphertext, recipient, contract_address);\n\n if message_plaintext_option.is_some() {\n process_message_plaintext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_plaintext_option.unwrap(),\n message_context,\n recipient,\n );\n } else {\n aztecnr_warn_log_format!(\"Could not decrypt message ciphertext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n\npub(crate) unconstrained fn process_message_plaintext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_plaintext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n // The first thing to do after decrypting the message is to determine what type of message we're processing. We\n // have 3 message types: private notes, partial notes and events.\n\n // We decode the message to obtain the message type id, metadata and content.\n let decoded = decode_message(message_plaintext);\n\n if decoded.is_some() {\n let (msg_type_id, msg_metadata, msg_content) = decoded.unwrap();\n\n if msg_type_id == PRIVATE_NOTE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private note msg\");\n\n process_private_note_msg(\n contract_address,\n message_context.tx_hash,\n message_context.unique_note_hashes_in_tx,\n message_context.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n msg_metadata,\n msg_content,\n );\n } else if msg_type_id == PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing partial note private msg\");\n\n process_partial_note_private_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n recipient,\n );\n } else if msg_type_id == PRIVATE_EVENT_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private event msg\");\n\n process_private_event_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n );\n } else if msg_type_id < MIN_CUSTOM_MSG_TYPE_ID {\n // The message type ID falls in the range reserved for aztec.nr built-in types but wasn't matched above.\n // This most likely means the message is malformed or a custom message was incorrectly assigned a reserved\n // ID. Custom message types must use IDs allocated via `custom_msg_type_id`.\n aztecnr_warn_log_format!(\n \"Message type ID {0} is in the reserved range but is not recognized, ignoring. See https://docs.aztec.network/errors/3\",\n )(\n [msg_type_id as Field],\n );\n } else if process_custom_message.is_some() {\n process_custom_message.unwrap()(\n contract_address,\n msg_type_id,\n msg_metadata,\n msg_content,\n message_context,\n recipient,\n );\n } else {\n // A custom message was received but no handler is configured. This likely means the contract emits custom\n // messages but forgot to register a handler via `AztecConfig::custom_message_handler`.\n aztecnr_warn_log_format!(\n \"Received custom message with type id {0} but no handler is configured, ignoring. See https://docs.aztec.network/errors/2\",\n )(\n [msg_type_id as Field],\n );\n }\n } else {\n aztecnr_warn_log_format!(\"Could not decode message plaintext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/process_message.nr","function_locations":[{"start":1975,"name":"process_message_ciphertext"},{"start":2968,"name":"process_message_plaintext"}]},"133":{"source":"// TODO(#12750): don't make these values assume we're using AES.\nuse crate::protocol::constants::PRIVATE_LOG_CIPHERTEXT_LEN;\nuse crate::utils::array;\n\n// We reassign to the constant here to communicate the distinction between a log and a message. In Aztec.nr, unlike in\n// protocol circuits, we have a concept of a message that can be emitted either as a private log or as an offchain\n// message. Message is a piece of data that is to be eventually delivered to a contract via the `process_message(...)`\n// utility function function that is injected by the #[aztec] macro. Note: PRIVATE_LOG_CIPHERTEXT_LEN is an amount of\n// fields, so MESSAGE_CIPHERTEXT_LEN is the size of the message in fields.\npub global MESSAGE_CIPHERTEXT_LEN: u32 = PRIVATE_LOG_CIPHERTEXT_LEN;\n\n// TODO(#12750): The global variables below should not be here as they are AES128 specific.\n// The header plaintext is 2 bytes (ciphertext length), padded to the 16-byte AES block size by PKCS#7.\npub(crate) global HEADER_CIPHERTEXT_SIZE_IN_BYTES: u32 = 16;\n// AES PKCS#7 always adds at least one byte of padding. Since each plaintext field is 32 bytes (a multiple of the\n// 16-byte AES block size), a full 16-byte padding block is always appended.\npub(crate) global AES128_PKCS7_EXPANSION_IN_BYTES: u32 = 16;\n\npub global EPH_PK_X_SIZE_IN_FIELDS: u32 = 1;\n\n// (15 - 1) * 31 - 16 - 16 = 402. Note: We multiply by 31 because ciphertext bytes are stored in fields using\n// encode_bytes_as_fields, which packs 31 bytes per field (since a Field is ~254 bits and can safely store 31 whole\n// bytes).\npub(crate) global MESSAGE_PLAINTEXT_SIZE_IN_BYTES: u32 = (MESSAGE_CIPHERTEXT_LEN - EPH_PK_X_SIZE_IN_FIELDS) * 31\n - HEADER_CIPHERTEXT_SIZE_IN_BYTES\n - AES128_PKCS7_EXPANSION_IN_BYTES;\n// The plaintext bytes represent Field values that were originally serialized using encode_fields_as_bytes, which\n// converts each Field to 32 bytes. To convert the plaintext bytes back to fields, we divide by 32. 402 / 32 = 12\npub global MESSAGE_PLAINTEXT_LEN: u32 = MESSAGE_PLAINTEXT_SIZE_IN_BYTES / 32;\n\npub global MESSAGE_EXPANDED_METADATA_LEN: u32 = 1;\n\n// The standard message layout is composed of:\n// - an initial field called the 'expanded metadata'\n// - an arbitrary number of fields following that called the 'message content'\n//\n// ```\n// message: [ msg_expanded_metadata, ...msg_content ]\n// ```\n//\n// The expanded metadata itself is interpreted as a u128, of which:\n// - the upper 64 bits are the message type id\n// - the lower 64 bits are called the 'message metadata'\n//\n// ```\n// msg_expanded_metadata: [ msg_type_id | msg_metadata ]\n// <--- 64 bits --->|<--- 64 bits --->\n// ```\n//\n// The meaning of the message metadata and message content depend on the value of the message type id. Note that there\n// is nothing special about the message metadata, it _can_ be considered part of the content. It just has a different\n// name to make it distinct from the message content given that it is not a full field.\n\n/// The maximum length of a message's content, i.e. not including the expanded message metadata.\npub global MAX_MESSAGE_CONTENT_LEN: u32 = MESSAGE_PLAINTEXT_LEN - MESSAGE_EXPANDED_METADATA_LEN;\n\n/// Encodes a message following aztec-nr's standard message encoding. This message can later be decoded with\n/// `decode_message` to retrieve the original values.\n///\n/// - The `msg_type` is an identifier that groups types of messages that are all processed the same way, e.g. private\n/// notes or events. Possible values are defined in `aztec::messages::msg_type`.\n/// - The `msg_metadata` and `msg_content` are the values stored in the message, whose meaning depends on the\n/// `msg_type`. The only special thing about `msg_metadata` that separates it from `msg_content` is that it is a u64\n/// instead of a full Field (due to details of how messages are encoded), allowing applications that can fit values\n/// into this smaller variable to achieve higher data efficiency.\npub fn encode_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; N],\n) -> [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] {\n std::static_assert(\n msg_content.len() <= MAX_MESSAGE_CONTENT_LEN,\n \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\",\n );\n\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n let mut message: [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] = std::mem::zeroed();\n\n message[0] = to_expanded_metadata(msg_type, msg_metadata);\n for i in 0..msg_content.len() {\n message[MESSAGE_EXPANDED_METADATA_LEN + i] = msg_content[i];\n }\n\n message\n}\n\n/// Decodes a standard aztec-nr message, i.e. one created via `encode_message`, returning the original encoded values.\n///\n/// Returns `None` if the message is empty or has invalid (>128 bit) expanded metadata.\n///\n/// Note that `encode_message` returns a fixed size array while this function takes a `BoundedVec`: this is because\n/// prior to decoding the message type is unknown, and consequentially not known at compile time. If working with\n/// fixed-size messages, consider using `BoundedVec::from_array` to convert them.\npub unconstrained fn decode_message(\n message: BoundedVec,\n) -> Option<(u64, u64, BoundedVec)> {\n Option::some(message)\n .and_then(|message| {\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring\n // of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n if message.len() < MESSAGE_EXPANDED_METADATA_LEN {\n Option::none()\n } else {\n Option::some(message.get(0))\n }\n })\n .and_then(|msg_expanded_metadata| from_expanded_metadata(msg_expanded_metadata))\n .map(|(msg_type_id, msg_metadata)| {\n let msg_content = array::subbvec(message, MESSAGE_EXPANDED_METADATA_LEN);\n (msg_type_id, msg_metadata, msg_content)\n })\n}\n\nglobal U64_SHIFT_MULTIPLIER: Field = 2.pow_32(64);\n\nfn to_expanded_metadata(msg_type: u64, msg_metadata: u64) -> Field {\n // We use multiplication instead of bit shifting operations to shift the type bits as bit shift operations are\n // expensive in circuits.\n let type_field: Field = (msg_type as Field) * U64_SHIFT_MULTIPLIER;\n let msg_metadata_field = msg_metadata as Field;\n\n type_field + msg_metadata_field\n}\n\nglobal TWO_POW_128: Field = 2.pow_32(128);\n\n/// Unpacks expanded metadata into (msg_type, msg_metadata). Returns `None` if `input >= 2^128`.\nfn from_expanded_metadata(input: Field) -> Option<(u64, u64)> {\n if input.lt(TWO_POW_128) {\n let msg_metadata = (input as u64);\n let msg_type = ((input - (msg_metadata as Field)) / U64_SHIFT_MULTIPLIER) as u64;\n // Use division instead of bit shift since bit shifts are expensive in circuits\n Option::some((msg_type, msg_metadata))\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray::subarray;\n use super::{\n decode_message, encode_message, from_expanded_metadata, MAX_MESSAGE_CONTENT_LEN, to_expanded_metadata,\n TWO_POW_128,\n };\n\n global U64_MAX: u64 = (2.pow_32(64) - 1) as u64;\n global U128_MAX: Field = (2.pow_32(128) - 1);\n\n #[test]\n unconstrained fn encode_decode_empty_message(msg_type: u64, msg_metadata: u64) {\n let encoded = encode_message(msg_type, msg_metadata, []);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), 0);\n }\n\n #[test]\n unconstrained fn encode_decode_short_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN / 2],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn encode_decode_full_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn to_expanded_metadata_packing() {\n // Test case 1: All bits set\n let packed = to_expanded_metadata(U64_MAX, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let packed = to_expanded_metadata(U64_MAX, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let packed = to_expanded_metadata(0, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let packed = to_expanded_metadata(0, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn from_expanded_metadata_packing() {\n // Test case 1: All bits set\n let input = U128_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let input = (U128_MAX - U64_MAX as Field);\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let input = U64_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let input = 0;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn to_from_expanded_metadata(original_msg_type: u64, original_msg_metadata: u64) {\n let packed = to_expanded_metadata(original_msg_type, original_msg_metadata);\n let (unpacked_msg_type, unpacked_msg_metadata) = from_expanded_metadata(packed).unwrap();\n\n assert_eq(original_msg_type, unpacked_msg_type);\n assert_eq(original_msg_metadata, unpacked_msg_metadata);\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_message() {\n let msg_type_id: u64 = 42;\n let msg_metadata: u64 = 99;\n let mut msg_content = [0; MAX_MESSAGE_CONTENT_LEN];\n for i in 0..MAX_MESSAGE_CONTENT_LEN {\n msg_content[i] = i as Field;\n }\n\n let encoded = encode_message(msg_type_id, msg_metadata, msg_content);\n let (decoded_type_id, decoded_metadata, decoded_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_type_id, msg_type_id);\n assert_eq(decoded_metadata, msg_metadata);\n assert_eq(decoded_content, BoundedVec::from_array(msg_content));\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_message_fails() {\n let msg_content = [0; MAX_MESSAGE_CONTENT_LEN + 1];\n let _ = encode_message(0, 0, msg_content);\n }\n\n #[test]\n unconstrained fn decode_empty_message_returns_none() {\n assert(decode_message(BoundedVec::new()).is_none());\n }\n\n #[test]\n unconstrained fn decode_message_with_oversized_metadata_returns_none() {\n let message = BoundedVec::from_array([TWO_POW_128]);\n assert(decode_message(message).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encoding.nr","function_locations":[{"start":4136,"name":"encode_message"},{"start":5594,"name":"decode_message"},{"start":6617,"name":"to_expanded_metadata"},{"start":7131,"name":"from_expanded_metadata"},{"start":7894,"name":"tests::encode_decode_empty_message"},{"start":8444,"name":"tests::encode_decode_short_message"},{"start":9090,"name":"tests::encode_decode_full_message"},{"start":9628,"name":"tests::to_expanded_metadata_packing"},{"start":10713,"name":"tests::from_expanded_metadata_packing"},{"start":11770,"name":"tests::to_from_expanded_metadata"},{"start":12151,"name":"tests::encode_decode_max_size_message"},{"start":12934,"name":"tests::encode_oversized_message_fails"},{"start":13123,"name":"tests::decode_empty_message_returns_none"},{"start":13280,"name":"tests::decode_message_with_oversized_metadata_returns_none"}]},"134":{"source":"use crate::protocol::{address::AztecAddress, public_keys::AddressPoint, traits::ToField};\n\nuse crate::{\n keys::{\n ecdh_shared_secret::{\n compute_app_siloed_shared_secret, derive_ecdh_shared_secret, derive_shared_secret_field_mask,\n derive_shared_secret_subkey,\n },\n ephemeral::generate_positive_ephemeral_key_pair,\n },\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::{\n EPH_PK_X_SIZE_IN_FIELDS, HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN,\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES,\n },\n encryption::message_encryption::MessageEncryption,\n logs::arithmetic_generics_utils::{\n get_arr_of_size__message_bytes__from_PT, get_arr_of_size__message_bytes_padding__from_PT,\n },\n },\n oracle::{aes128_decrypt::try_aes128_decrypt, random::random, shared_secret::get_shared_secret},\n utils::{\n array,\n conversion::{\n bytes_as_fields::{decode_bytes_from_fields, encode_bytes_as_fields},\n fields_as_bytes::{encode_fields_as_bytes, try_decode_fields_from_bytes},\n },\n point::point_from_x_coord_and_sign,\n },\n};\n\nuse std::aes128::aes128_encrypt;\n\n/// Computes N close-to-uniformly-random 256 bits from a given app-siloed shared secret.\n///\n/// NEVER re-use the same iv and sym_key. DO NOT call this function more than once with the same s_app.\n///\n/// This function is only known to be safe if s_app is derived from combining a random ephemeral key with an\n/// address point and a contract address. See big comment within the body of the function.\nfn extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app: Field) -> [[u8; 32]; N] {\n /*\n * Unsafe because of https://eprint.iacr.org/2010/264.pdf Page 13, Lemma 2 (and the two paragraphs below it).\n *\n * If you call this function, you need to be careful and aware of how the arg `s_app` has been derived.\n *\n * The paper says that the way you derive aes keys and IVs should be fine with poseidon2 (modelled as a RO),\n * as long as you _don't_ use Poseidon2 as a PRG to generate the two exponents x & y which multiply to the\n * shared secret S:\n *\n * S = [x*y]*G.\n *\n * (Otherwise, you would have to \"key\" poseidon2, i.e. generate a uniformly string K which can be public and\n * compute Hash(x) as poseidon(K,x)).\n * In that lemma, k would be 2*254=508, and m would be the number of points on the grumpkin curve (which is\n * close to r according to the Hasse bound).\n *\n * Our shared secret S is [esk * address_sk] * G, and the question is: Can we compute hash(S) using poseidon2\n * instead of sha256?\n *\n * Well, esk is random and not generated with poseidon2, so that's good.\n * What about address_sk?\n * Well, address_sk = poseidon2(stuff) + ivsk, so there was some discussion about whether address_sk is\n * independent of poseidon2. Given that ivsk is random and independent of poseidon2, the address_sk is also\n * independent of poseidon2.\n *\n * Tl;dr: we believe it's safe to hash S = [esk * address_sk] * G using poseidon2, in order to derive a\n * symmetric key.\n *\n * If you're calling this function for a differently-derived `s_app`, be careful.\n */\n \n\n /* The output of this function needs to be 32 random bytes.\n * A single field won't give us 32 bytes of entropy. So we compute two \"random\" fields, by poseidon-hashing\n * with two different indices. We then extract the last 16 (big endian) bytes of each \"random\" field.\n * Note: we use to_be_bytes because it's slightly more efficient. But we have to be careful not to take bytes\n * from the \"big end\", because the \"big\" byte is not uniformly random over the byte: it only has < 6 bits of\n * randomness, because it's the big end of a 254-bit field element.\n */\n\n let mut all_bytes: [[u8; 32]; N] = std::mem::zeroed();\n std::static_assert(N < 256, \"N too large\");\n for k in 0..N {\n let rand1: Field = derive_shared_secret_subkey(s_app, 2 * k);\n let rand2: Field = derive_shared_secret_subkey(s_app, 2 * k + 1);\n\n let rand1_bytes: [u8; 32] = rand1.to_be_bytes();\n let rand2_bytes: [u8; 32] = rand2.to_be_bytes();\n\n let mut bytes: [u8; 32] = [0; 32];\n for i in 0..16 {\n // We take bytes from the \"little end\" of the be-bytes arrays:\n let j = 32 - i - 1;\n bytes[i] = rand1_bytes[j];\n bytes[16 + i] = rand2_bytes[j];\n }\n\n all_bytes[k] = bytes;\n }\n\n all_bytes\n}\n\nfn derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(\n many_random_256_bits: [[u8; 32]; N],\n) -> [([u8; 16], [u8; 16]); N] {\n // Many (sym_key, iv) pairs:\n let mut many_pairs: [([u8; 16], [u8; 16]); N] = std::mem::zeroed();\n for k in 0..N {\n let random_256_bits = many_random_256_bits[k];\n let mut sym_key = [0; 16];\n let mut iv = [0; 16];\n for i in 0..16 {\n sym_key[i] = random_256_bits[i];\n iv[i] = random_256_bits[i + 16];\n }\n many_pairs[k] = (sym_key, iv);\n }\n\n many_pairs\n}\n\npub fn derive_aes_symmetric_key_and_iv_from_shared_secret(s_app: Field) -> [([u8; 16], [u8; 16]); N] {\n let many_random_256_bits: [[u8; 32]; N] = extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app);\n\n derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(many_random_256_bits)\n}\n\npub struct AES128 {}\n\nimpl MessageEncryption for AES128 {\n\n /// AES128-CBC encryption for Aztec protocol messages.\n ///\n /// ## Overview\n ///\n /// The plaintext is an array of up to `MESSAGE_PLAINTEXT_LEN` (12) fields. The output is always exactly\n /// `MESSAGE_CIPHERTEXT_LEN` (15) fields, regardless of plaintext size. All output fields except the\n /// ephemeral public key are uniformly random `Field` values to any observer without knowledge of the\n /// shared secret, making all encrypted messages indistinguishable by size or content.\n ///\n /// ## PKCS#7 Padding\n ///\n /// AES operates on 16-byte blocks, so the plaintext must be padded to a multiple of 16. PKCS#7 padding always\n /// adds at least 1 byte (so the receiver can always detect and strip it), which means:\n /// - 1 B plaintext -> 15 B padding -> 16 B total\n /// - 15 B plaintext -> 1 B padding -> 16 B total\n /// - 16 B plaintext -> 16 B padding -> 32 B total (full extra block)\n ///\n /// In general: if the plaintext is already a multiple of 16, a full 16-byte padding block is appended.\n ///\n /// ## Encryption Steps\n ///\n /// **1. Body encryption.** The plaintext fields are serialized to bytes (32 bytes per field) and AES-128-CBC\n /// encrypted. Since 32 is a multiple of 16, PKCS#7 always adds a full 16-byte padding block (see above):\n ///\n /// ```text\n /// +---------------------------------------------+\n /// | body ct |\n /// | PlaintextLen*32 + 16 B |\n /// +-------------------------------+--------------+\n /// | encrypted plaintext fields | PKCS#7 (16B) |\n /// | (serialized at 32 B each) | |\n /// +-------------------------------+--------------+\n /// ```\n ///\n /// **2. Header encryption.** The byte length of `body_ct` is stored as a 2-byte big-endian integer. This 2-byte\n /// header plaintext is then AES-encrypted; PKCS#7 pads the remaining 14 bytes to fill one 16-byte AES block,\n /// producing a 16-byte header ciphertext:\n ///\n /// ```text\n /// +---------------------------+\n /// | header ct |\n /// | 16 B |\n /// +--------+------------------+\n /// | body ct| PKCS#7 (14B) |\n /// | length | |\n /// | (2 B) | |\n /// +--------+------------------+\n /// ```\n ///\n /// ## Wire Format\n ///\n /// Messages are transmitted as fields, not bytes. A field is ~254 bits and can safely store 31 whole bytes, so\n /// we need to pack our byte data into 31-byte chunks. This packing drives the wire format.\n ///\n /// **Step 1 -- Assemble bytes.** The ciphertexts are laid out in a byte array, padded with zero bytes to a\n /// multiple of 31 so it divides evenly into fields:\n ///\n /// ```text\n /// +------------+-------------------------+---------+\n /// | header ct | body ct | byte pad|\n /// | 16 B | PlaintextLen*32 + 16 B | (zeros) |\n /// +------------+-------------------------+---------+\n /// |<-------- padded to a multiple of 31 B -------->|\n /// ```\n ///\n /// **Step 2 -- Pack and mask.** The byte array is split into 31-byte chunks, each stored in one field. A\n /// Poseidon2-derived mask (see `derive_shared_secret_field_mask`) is added to each so that the resulting\n /// fields appear as uniformly random `Field` values to any observer without knowledge of the shared secret,\n /// hiding the fact that the underlying ciphertext consists of 128-bit AES blocks.\n ///\n /// **Step 3 -- Assemble ciphertext.** The ephemeral public key x-coordinate is prepended and random field padding\n /// is appended to fill to 15 fields:\n ///\n /// ```text\n /// +----------+-------------------------+-------------------+\n /// | eph_pk.x | masked message fields | random field pad |\n /// | | (packed 31 B per field) | (fills to 15) |\n /// +----------+-------------------------+-------------------+\n /// |<---------- MESSAGE_CIPHERTEXT_LEN = 15 fields -------->|\n /// ```\n ///\n /// ## Key Derivation\n ///\n /// The raw ECDH shared secret point is first app-siloed into a scalar `s_app` by hashing with the contract\n /// address (see\n /// [`compute_app_siloed_shared_secret`](crate::keys::ecdh_shared_secret::compute_app_siloed_shared_secret)).\n /// Two (key, IV) pairs are then derived from `s_app` via indexed Poseidon2 hashing: one pair for the body\n /// ciphertext and one for the header ciphertext.\n fn encrypt(\n plaintext: [Field; PlaintextLen],\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> [Field; MESSAGE_CIPHERTEXT_LEN] {\n std::static_assert(\n PlaintextLen <= MESSAGE_PLAINTEXT_LEN,\n \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\",\n );\n\n // AES 128 operates on bytes, not fields, so we need to convert the fields to bytes. (This process is then\n // reversed when processing the message in `process_message_ciphertext`)\n let plaintext_bytes = encode_fields_as_bytes(plaintext);\n\n // Derive ECDH shared secret with recipient using a fresh ephemeral keypair.\n let (eph_sk, eph_pk) = generate_positive_ephemeral_key_pair();\n\n let raw_shared_secret = derive_ecdh_shared_secret(\n eph_sk,\n recipient\n .to_address_point()\n .unwrap_or_else(|| {\n aztecnr_warn_log_format!(\n \"Attempted to encrypt message for an invalid recipient ({0})\",\n )(\n [recipient.to_field()],\n );\n\n // Safety: if the recipient is an invalid address, then it is not possible to encrypt a message for\n // them because we cannot establish a shared secret. This is never expected to occur during normal\n // operation. However, it is technically possible for us to receive an invalid address, and we must\n // therefore handle it. We could simply fail, but that'd introduce a potential security issue in\n // which an attacker forces a contract to encrypt a message for an invalid address, resulting in an\n // impossible transaction - this is sometimes called a 'king of the hill' attack. We choose instead\n // to not fail and encrypt the plaintext regardless using the shared secret that results from a\n // random valid address. The sender is free to choose this address and hence shared secret, but\n // this has no security implications as they already know not only the full plaintext but also the\n // ephemeral private key anyway.\n unsafe {\n random_address_point()\n }\n })\n .inner,\n );\n\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n // It is safe to derive AES keys from `s_app` using Poseidon2 because `s_app` was derived from an ECDH shared\n // secret using an AztecAddress (the recipient). See the block comment in\n // `extract_many_close_to_uniformly_random_256_bits_using_poseidon2` for more info.\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n let ciphertext_bytes = aes128_encrypt(plaintext_bytes, body_iv, body_sym_key);\n\n // Each plaintext field is 32 bytes (a multiple of the 16-byte AES block\n // size), so PKCS#7 always appends a full 16-byte padding block:\n // |ciphertext| = PlaintextLen*32 + 16 = 16 * (1 + PlaintextLen*32 / 16)\n std::static_assert(\n ciphertext_bytes.len() == 16 * (1 + (PlaintextLen * 32) / 16),\n \"unexpected ciphertext length\",\n );\n\n // Encrypt a 2-byte header containing the body ciphertext length.\n let header_plaintext = encode_header(ciphertext_bytes.len());\n\n // Note: the aes128_encrypt builtin fn automatically appends bytes to the input, according to pkcs#7; hence why\n // the output `header_ciphertext_bytes` is 16 bytes larger than the input in this case.\n let header_ciphertext_bytes = aes128_encrypt(header_plaintext, header_iv, header_sym_key);\n // Verify expected header ciphertext size at compile time.\n std::static_assert(\n header_ciphertext_bytes.len() == HEADER_CIPHERTEXT_SIZE_IN_BYTES,\n \"unexpected ciphertext header length\",\n );\n\n // Assemble the message byte array:\n // [header_ct (16B)] [body_ct] [padding to mult of 31]\n let message_bytes_padding_to_mult_31 = get_arr_of_size__message_bytes_padding__from_PT::();\n\n let mut message_bytes = get_arr_of_size__message_bytes__from_PT::();\n\n std::static_assert(\n message_bytes.len() % 31 == 0,\n \"Unexpected error: message_bytes.len() should be divisible by 31, by construction.\",\n );\n\n let mut offset = 0;\n for i in 0..header_ciphertext_bytes.len() {\n message_bytes[offset + i] = header_ciphertext_bytes[i];\n }\n offset += header_ciphertext_bytes.len();\n\n for i in 0..ciphertext_bytes.len() {\n message_bytes[offset + i] = ciphertext_bytes[i];\n }\n offset += ciphertext_bytes.len();\n\n for i in 0..message_bytes_padding_to_mult_31.len() {\n message_bytes[offset + i] = message_bytes_padding_to_mult_31[i];\n }\n offset += message_bytes_padding_to_mult_31.len();\n\n // Ideally we would be able to have a static assert where we check that the offset would be such that we've\n // written to the entire log_bytes array, but we cannot since Noir does not treat the offset as a comptime\n // value (despite the values that it goes through being known at each stage). We instead check that the\n // computation used to obtain the offset computes the expected value (which we _can_ do in a static check), and\n // then add a cheap runtime check to also validate that the offset matches this.\n std::static_assert(\n header_ciphertext_bytes.len() + ciphertext_bytes.len() + message_bytes_padding_to_mult_31.len()\n == message_bytes.len(),\n \"unexpected message length\",\n );\n assert(offset == message_bytes.len(), \"unexpected encrypted message length\");\n\n // Pack message bytes into fields (31 bytes per field) and prepend eph_pk.x.\n let message_bytes_as_fields = encode_bytes_as_fields(message_bytes);\n\n let mut ciphertext: [Field; MESSAGE_CIPHERTEXT_LEN] = [0; MESSAGE_CIPHERTEXT_LEN];\n\n ciphertext[0] = eph_pk.x;\n\n // Mask each content field with a Poseidon2-derived value, so that they appear as uniformly random `Field`\n // values\n let mut offset = 1;\n for i in 0..message_bytes_as_fields.len() {\n let mask = derive_shared_secret_field_mask(s_app, i as u32);\n ciphertext[offset + i] = message_bytes_as_fields[i] + mask;\n }\n offset += message_bytes_as_fields.len();\n\n // Pad with random fields so that padding is indistinguishable from masked data fields.\n for i in offset..MESSAGE_CIPHERTEXT_LEN {\n // Safety: we assume that the sender wants for the message to be private - a malicious one could simply\n // reveal its contents publicly. It is therefore fine to trust the sender to provide random padding.\n ciphertext[i] = unsafe { random() };\n }\n\n ciphertext\n }\n\n unconstrained fn decrypt(\n ciphertext: BoundedVec,\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> Option> {\n // Extract the ephemeral public key x-coordinate and masked fields, returning None for empty ciphertext.\n if ciphertext.len() > 0 {\n let masked_fields: BoundedVec =\n array::subbvec(ciphertext, EPH_PK_X_SIZE_IN_FIELDS);\n Option::some((ciphertext.get(0), masked_fields))\n } else {\n Option::none()\n }\n .and_then(|(eph_pk_x, masked_fields)| {\n // With the x-coordinate of the ephemeral public key we can reconstruct the point as we know that the\n // y-coordinate must be positive. This may fail however, as not all x-coordinates are on the curve. In\n // that case, we simply return `Option::none`.\n point_from_x_coord_and_sign(eph_pk_x, true).and_then(|eph_pk| {\n let s_app = get_shared_secret(recipient, eph_pk, contract_address);\n\n let unmasked_fields = masked_fields.mapi(|i, field| {\n let unmasked = unmask_field(s_app, i, field);\n // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it\n // later, so we can simply set it to 0\n unmasked.unwrap_or(0)\n });\n let ciphertext_without_eph_pk_x = decode_bytes_from_fields(unmasked_fields);\n\n // Derive symmetric keys:\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n // Extract the header ciphertext\n let header_start = 0;\n let header_ciphertext: [u8; HEADER_CIPHERTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), header_start);\n // We need to convert the array to a BoundedVec because the oracle expects a BoundedVec as it's\n // designed to work with messages with unknown length at compile time. This would not be necessary\n // here as the header ciphertext length is fixed. But we do it anyway to not have to have duplicate\n // oracles.\n let header_ciphertext_bvec =\n BoundedVec::::from_array(header_ciphertext);\n\n try_aes128_decrypt(header_ciphertext_bvec, header_iv, header_sym_key)\n // Extract ciphertext length from header (2 bytes, big-endian)\n .and_then(|header_plaintext| extract_ciphertext_length(header_plaintext))\n .filter(|ciphertext_length| ciphertext_length <= MESSAGE_PLAINTEXT_SIZE_IN_BYTES)\n .map(|ciphertext_length| {\n // Extract and decrypt main ciphertext\n let ciphertext_start = header_start + HEADER_CIPHERTEXT_SIZE_IN_BYTES;\n let ciphertext_with_padding: [u8; MESSAGE_PLAINTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), ciphertext_start);\n BoundedVec::from_parts(ciphertext_with_padding, ciphertext_length)\n })\n // Decrypt main ciphertext and return it\n .and_then(|ciphertext| try_aes128_decrypt(ciphertext, body_iv, body_sym_key))\n // Convert bytes back to fields (32 bytes per field). Returns None if the actual bytes are\n // not valid.\n .and_then(|plaintext_bytes| try_decode_fields_from_bytes(plaintext_bytes))\n })\n })\n }\n}\n\n/// Encodes the body ciphertext length into a 2-byte big-endian header.\nfn encode_header(ciphertext_length: u32) -> [u8; 2] {\n [(ciphertext_length >> 8) as u8, ciphertext_length as u8]\n}\n\n/// Extracts the body ciphertext length from a decrypted header as a 2-byte big-endian integer.\n///\n/// Returns `Option::none()` if the header has fewer than 2 bytes.\nunconstrained fn extract_ciphertext_length(header: BoundedVec) -> Option {\n if header.len() >= 2 {\n Option::some(((header.get(0) as u32) << 8) | (header.get(1) as u32))\n } else {\n Option::none()\n }\n}\n\n/// 2^248: upper bound for values that fit in 31 bytes\nglobal TWO_POW_248: Field = 2.pow_32(248);\n\n/// Removes the Poseidon2-derived mask from a ciphertext field. Returns the unmasked value if it fits in 31 bytes\n/// (a content field), or `None` if it doesn't (random padding). Unconstrained to prevent accidental use in\n/// constrained context.\nunconstrained fn unmask_field(s_app: Field, index: u32, masked: Field) -> Option {\n let unmasked = masked - derive_shared_secret_field_mask(s_app, index);\n if unmasked.lt(TWO_POW_248) {\n Option::some(unmasked)\n } else {\n Option::none()\n }\n}\n\n/// Produces a random valid address point, i.e. one that is on the curve. This is equivalent to calling\n/// [`AztecAddress::to_address_point`] on a random valid address.\nunconstrained fn random_address_point() -> AddressPoint {\n let mut result = std::mem::zeroed();\n\n loop {\n // We simply produce random x coordinates until we find one that is on the curve. About half of the x\n // coordinates fulfill this condition, so this should only take a few iterations at most.\n let x_coord = random();\n let point = point_from_x_coord_and_sign(x_coord, true);\n if point.is_some() {\n result = AddressPoint { inner: point.unwrap() };\n break;\n }\n }\n\n result\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::{compute_app_siloed_shared_secret, derive_ecdh_shared_secret},\n messages::{\n encoding::{HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_PLAINTEXT_LEN, MESSAGE_PLAINTEXT_SIZE_IN_BYTES},\n encryption::message_encryption::MessageEncryption,\n },\n test::helpers::test_environment::TestEnvironment,\n };\n use crate::protocol::{address::AztecAddress, traits::FromField};\n use super::{AES128, encode_header, random_address_point};\n use std::{embedded_curve_ops::EmbeddedCurveScalar, test::OracleMock};\n\n #[test]\n unconstrained fn encrypt_decrypt_deterministic() {\n let env = TestEnvironment::new();\n\n // Message decryption requires oracles that are only available during private execution\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n\n let recipient = AztecAddress::from_field(\n 0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70c,\n );\n\n // Mock random values for deterministic test\n let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(eph_sk).times(1);\n\n let randomness = 0x0101010101010101010101010101010101010101010101010101010101010101;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(randomness).times(1000000);\n\n let _ = OracleMock::mock(\"aztec_prv_getNextAppTagAsSender\").returns(42);\n\n // Encrypt the message\n let encrypted_message = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n // Compute the same app-siloed shared secret that the oracle would return\n let raw_shared_secret = derive_ecdh_shared_secret(\n EmbeddedCurveScalar::from_field(eph_sk),\n recipient.to_address_point().unwrap().inner,\n );\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n let _ = OracleMock::mock(\"aztec_utl_getSharedSecret\").returns(s_app);\n\n // Decrypt the message\n let decrypted = AES128::decrypt(encrypted_message, recipient, contract_address).unwrap();\n\n // The decryption function spits out a BoundedVec because it's designed to work with messages with unknown\n // length at compile time. For this reason we need to convert the original input to a BoundedVec.\n let plaintext_bvec = BoundedVec::::from_array(plaintext);\n\n // Verify decryption matches original plaintext\n assert_eq(decrypted, plaintext_bvec, \"Decrypted bytes should match original plaintext\");\n\n // The following is a workaround of \"struct is never constructed\" Noir compilation error (we only ever use\n // static methods of the struct).\n let _ = AES128 {};\n });\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_random() {\n // Same as `encrypt_decrypt_deterministic`, except we don't mock any of the oracles and rely on\n // `TestEnvironment` instead.\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test]\n unconstrained fn encrypt_to_invalid_address() {\n // x = 3 is a non-residue for this curve, resulting in an invalid address\n let invalid_address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n\n let _ = AES128::encrypt([1, 2, 3, 4], invalid_address, contract_address);\n }\n\n // Documents the PKCS#7 padding behavior that `encrypt` relies on (see its static_assert).\n #[test]\n fn pkcs7_padding_always_adds_at_least_one_byte() {\n let key = [0 as u8; 16];\n let iv = [0 as u8; 16];\n\n // 1 byte input + 15 bytes padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 1], iv, key).len(), 16);\n\n // 15 bytes input + 1 byte padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 15], iv, key).len(), 16);\n\n // 16 bytes input (block-aligned) + full 16-byte padding block = 32 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 16], iv, key).len(), 32);\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_max_size_plaintext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let mut plaintext = [0; MESSAGE_PLAINTEXT_LEN];\n for i in 0..MESSAGE_PLAINTEXT_LEN {\n plaintext[i] = i as Field;\n }\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test(should_fail_with = \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\")]\n unconstrained fn encrypt_oversized_plaintext() {\n let address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n let plaintext: [Field; MESSAGE_PLAINTEXT_LEN + 1] = [0; MESSAGE_PLAINTEXT_LEN + 1];\n let _ = AES128::encrypt(plaintext, address, contract_address);\n }\n\n #[test]\n unconstrained fn random_address_point_produces_valid_points() {\n // About half of random addresses are invalid, so testing just a couple gives us high confidence that\n // `random_address_point` is indeed producing valid addresses.\n for _ in 0..10 {\n let random_address = AztecAddress { inner: random_address_point().inner.x };\n assert(random_address.to_address_point().is_some());\n }\n }\n\n #[test]\n unconstrained fn decrypt_invalid_ephemeral_public_key() {\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3, 4];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n // The first field of the ciphertext is the x-coordinate of the ephemeral public key. We set it to a known\n // non-residue (3), causing `decrypt` to fail to produce a decryption shared secret.\n let mut bad_ciphertext = BoundedVec::from_array(ciphertext);\n bad_ciphertext.set(0, 3);\n\n assert(AES128::decrypt(bad_ciphertext, recipient, contract_address).is_none());\n });\n }\n\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_ciphertext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n assert(AES128::decrypt(BoundedVec::new(), recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header AES decrypt oracle to return an empty result. The TS oracle never throws on invalid\n // input: it decrypts to garbage bytes or returns empty\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_header() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let empty_header = BoundedVec::::new();\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(empty_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header oracle to return a 2-byte header that decodes to a ciphertext_length one past the maximum\n // allowed value, verifying the edge case is handled correctly.\n #[test]\n unconstrained fn decrypt_returns_none_on_oversized_ciphertext_length() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let bad_header = BoundedVec::::from_array(encode_header(\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES + 1,\n ));\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(bad_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr","function_locations":[{"start":1764,"name":"extract_many_close_to_uniformly_random_256_bits_using_poseidon2"},{"start":4783,"name":"derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits"},{"start":5332,"name":"derive_aes_symmetric_key_and_iv_from_shared_secret"},{"start":10365,"name":"::encrypt"},{"start":17702,"name":"::decrypt"},{"start":21732,"name":"encode_header"},{"start":22063,"name":"extract_ciphertext_length"},{"start":22648,"name":"unmask_field"},{"start":23061,"name":"random_address_point"},{"start":24228,"name":"test::encrypt_decrypt_deterministic"},{"start":26706,"name":"test::encrypt_decrypt_random"},{"start":27552,"name":"test::encrypt_to_invalid_address"},{"start":28002,"name":"test::pkcs7_padding_always_adds_at_least_one_byte"},{"start":28566,"name":"test::encrypt_decrypt_max_size_plaintext"},{"start":29465,"name":"test::encrypt_oversized_plaintext"},{"start":29823,"name":"test::random_address_point_produces_valid_points"},{"start":30274,"name":"test::decrypt_invalid_ephemeral_public_key"},{"start":31119,"name":"test::decrypt_returns_none_on_empty_ciphertext"},{"start":31673,"name":"test::decrypt_returns_none_on_empty_header"},{"start":32599,"name":"test::decrypt_returns_none_on_oversized_ciphertext_length"}]},"139":{"source":"use crate::{\n event::{event_interface::EventInterface, EventSelector},\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n utils::array,\n};\nuse crate::protocol::traits::{FromField, Serialize, ToField};\n\n/// The number of fields in a private event message content that are not the event's serialized representation (1 field\n/// for randomness).\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 1;\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 0;\n\n/// The maximum length of the packed representation of an event's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, randomness, etc.).\npub global MAX_EVENT_SERIALIZED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_event_message`].\npub fn encode_private_event_message(\n event: Event,\n randomness: Field,\n) -> [Field; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Event: EventInterface + Serialize,\n{\n std::static_assert(\n ::N <= MAX_EVENT_SERIALIZED_LEN,\n \"event's serialized length exceeds the maximum allowed for private events\",\n );\n\n // We use `Serialize` because we want for events to be processable by off-chain actors, e.g. block explorers,\n // wallets and apps, without having to rely on contract invocation. If we used `Packable` we'd need to call utility\n // functions in order to unpack events, which would introduce a level of complexity we don't currently think is\n // worth the savings in DA (for public events) and proving time (when encrypting private event messages).\n let serialized_event = event.serialize();\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_plaintext = [0; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n\n for i in 0..serialized_event.len() {\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = serialized_event[i];\n }\n\n // The event type id is stored in the message metadata\n encode_message(\n PRIVATE_EVENT_MSG_TYPE_ID,\n Event::get_event_type_id().to_field() as u64,\n msg_plaintext,\n )\n}\n\n/// Decodes the plaintext from a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_event_message`].\n///\n/// Note that while [`encode_private_event_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_event_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(EventSelector, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let event_type_id = EventSelector::from_field(msg_metadata as Field);\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // destructuring of the private event message encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let randomness = msg_content.get(PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let serialized_event = array::subbvec(msg_content, PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((event_type_id, randomness, serialized_event))\n }\n}\n\nmod test {\n use crate::{\n event::event_interface::EventInterface,\n messages::{\n encoding::decode_message,\n logs::event::{decode_private_event_message, encode_private_event_message},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n };\n use crate::protocol::traits::Serialize;\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let event = MockEvent::new(VALUE).build_event();\n\n let message_plaintext = encode_private_event_message(event, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_EVENT_MSG_TYPE_ID);\n\n let (event_type_id, randomness, serialized_event) =\n decode_private_event_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(event_type_id, MockEvent::get_event_type_id());\n assert_eq(randomness, RANDOMNESS);\n assert_eq(serialized_event, BoundedVec::from_array(event.serialize()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_event_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0]);\n assert(decode_private_event_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/event.nr","function_locations":[{"start":1377,"name":"encode_private_event_message"},{"start":3755,"name":"decode_private_event_message"},{"start":5127,"name":"test::encode_decode"},{"start":5869,"name":"test::decode_empty_content_returns_none"},{"start":6064,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"141":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\n\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX: u32 = 1;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 2;\n\n/// The maximum length of the packed representation of a note's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, storage slot, randomness, etc.).\npub global MAX_NOTE_PACKED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_note_message`].\npub fn encode_private_note_message(\n note: Note,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n) -> [Field; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Note: NoteType + Packable,\n{\n let packed_note = note.pack();\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_content = [0; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX] = storage_slot;\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n for i in 0..packed_note.len() {\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_note[i];\n }\n\n // Notes use the note type id for metadata\n encode_message(PRIVATE_NOTE_MSG_TYPE_ID, Note::get_id() as u64, msg_content)\n}\n\n/// Decodes the plaintext from a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_note_message`].\n///\n/// Note that while [`encode_private_note_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_note_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(Field, AztecAddress, Field, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // decoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let owner = AztecAddress::from_field(msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX));\n let storage_slot = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX);\n let randomness = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let packed_note = array::subbvec(msg_content, PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((note_type_id, owner, storage_slot, randomness, packed_note))\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::note::{decode_private_note_message, encode_private_note_message, MAX_NOTE_PACKED_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global STORAGE_SLOT: Field = 9;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[derive(Packable)]\n struct MaxSizeNote {\n data: [Field; MAX_NOTE_PACKED_LEN],\n }\n\n impl NoteType for MaxSizeNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_note() {\n let mut data = [0; MAX_NOTE_PACKED_LEN];\n for i in 0..MAX_NOTE_PACKED_LEN {\n data[i] = i as Field;\n }\n let note = MaxSizeNote { data };\n\n let encoded = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n let (msg_type_id, msg_metadata, msg_content) = decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MaxSizeNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(data));\n }\n\n #[derive(Packable)]\n struct OversizedNote {\n data: [Field; MAX_NOTE_PACKED_LEN + 1],\n }\n\n impl NoteType for OversizedNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_note_fails() {\n let note = OversizedNote { data: [0; MAX_NOTE_PACKED_LEN + 1] };\n let _ = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_note_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0, 0, 0]);\n assert(decode_private_note_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/note.nr","function_locations":[{"start":1518,"name":"encode_private_note_message"},{"start":3312,"name":"decode_private_note_message"},{"start":5000,"name":"test::encode_decode"},{"start":5923,"name":"test::::get_id"},{"start":6019,"name":"test::encode_decode_max_size_note"},{"start":7035,"name":"test::::get_id"},{"start":7221,"name":"test::encode_oversized_note_fails"},{"start":7456,"name":"test::decode_empty_content_returns_none"},{"start":7650,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"142":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 1;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX: u32 = 2;\n\n/// Partial notes have a maximum packed length of their private fields bound by extra content in their private message\n/// (e.g. the storage slot, note completion log tag, etc.).\npub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 =\n MAX_MESSAGE_CONTENT_LEN - PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a partial note private message (i.e. one of type [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_partial_note_private_message`].\npub fn encode_partial_note_private_message(\n partial_note_private_content: PartialNotePrivateContent,\n owner: AztecAddress,\n randomness: Field,\n note_completion_log_tag: Field,\n ) -> [Field; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n PartialNotePrivateContent: NoteType + Packable,\n{\n let packed_private_content = partial_note_private_content.pack();\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail, then\n // the encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n let mut msg_content =\n [0; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX] = note_completion_log_tag;\n\n for i in 0..packed_private_content.len() {\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_private_content[i];\n }\n\n encode_message(\n PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n // Notes use the note type id for metadata\n PartialNotePrivateContent::get_id() as u64,\n msg_content,\n )\n}\n\n/// Decodes the plaintext from a partial note private message (i.e. one of type\n/// [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_partial_note_private_message`].\n///\n/// Note that while [`encode_partial_note_private_message`] returns a fixed-size array, this function takes a\n/// [`BoundedVec`] instead. This is because when decoding we're typically processing runtime-sized plaintexts, more\n/// specifically, those that originate from\n/// [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_partial_note_private_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(AztecAddress, Field, Field, Field, BoundedVec)> {\n if msg_content.len() < PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id: Field = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail,\n // then the destructuring of the partial note private message encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n // We currently have three fields that are not the partial note's packed representation, which are the owner,\n // the randomness, and the note completion log tag.\n let owner = AztecAddress::from_field(\n msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX),\n );\n let randomness = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let note_completion_log_tag = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX);\n\n let packed_private_note_content: BoundedVec = array::subbvec(\n msg_content,\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN,\n );\n\n Option::some(\n (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content),\n )\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::partial_note::{decode_partial_note_private_message, encode_partial_note_private_message},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global RANDOMNESS: Field = 10;\n global NOTE_COMPLETION_LOG_TAG: Field = 11;\n\n #[test]\n unconstrained fn encode_decode() {\n // Note that here we use MockNote as the private fields of a partial note\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_partial_note_private_message(note, OWNER, RANDOMNESS, NOTE_COMPLETION_LOG_TAG);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID);\n\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_note) =\n decode_partial_note_private_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(note_completion_log_tag, NOTE_COMPLETION_LOG_TAG);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_partial_note_private_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_succeeds_with_only_reserved_fields() {\n let content = BoundedVec::from_array([0, 0, 0]);\n let (_, _, _, _, packed_note) = decode_partial_note_private_message(0, content).unwrap();\n assert_eq(packed_note.len(), 0);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/partial_note.nr","function_locations":[{"start":1715,"name":"encode_partial_note_private_message"},{"start":3810,"name":"decode_partial_note_private_message"},{"start":6022,"name":"test::encode_decode"},{"start":6999,"name":"test::decode_empty_content_returns_none"},{"start":7197,"name":"test::decode_succeeds_with_only_reserved_fields"}]},"152":{"source":"pub(crate) mod event_validation_request;\npub mod offchain;\n\nmod message_context;\npub use message_context::MessageContext;\n\npub(crate) mod note_validation_request;\npub(crate) mod log_retrieval_request;\npub(crate) mod log_retrieval_response;\npub(crate) mod pending_tagged_log;\n\nuse crate::{\n capsules::CapsuleArray,\n ephemeral::EphemeralArray,\n event::EventSelector,\n messages::{\n discovery::partial_notes::DeliveredPendingPartialNote,\n encoding::MESSAGE_CIPHERTEXT_LEN,\n logs::{event::MAX_EVENT_SERIALIZED_LEN, note::MAX_NOTE_PACKED_LEN},\n processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse,\n note_validation_request::NoteValidationRequest,\n },\n },\n oracle::message_processing,\n};\nuse crate::protocol::{\n address::AztecAddress,\n constants::DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n hash::{compute_log_tag, sha256_to_field},\n traits::{Deserialize, Serialize},\n};\nuse event_validation_request::EventValidationRequest;\n\nglobal NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\n/// An offchain-delivered message with resolved context, ready for processing during sync.\n#[derive(Serialize, Deserialize)]\npub struct OffchainMessageWithContext {\n pub message_ciphertext: BoundedVec,\n pub message_context: MessageContext,\n}\n\n/// Enqueues a note for validation and storage by PXE.\n///\n/// Once validated, the note becomes retrievable via the `get_notes` oracle. The note will be scoped to\n/// `contract_address`, meaning other contracts will not be able to access it unless authorized.\n///\n/// In order for the note validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many note validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// The `packed_note` is what `getNotes` will later return. PXE indexes notes by `storage_slot`, so this value is\n/// typically used to filter notes that correspond to different state variables. `note_hash` and `nullifier` are the\n/// inner hashes, i.e. the raw hashes returned by `NoteHash::compute_note_hash` and `NoteHash::compute_nullifier`. PXE\n/// will verify that the siloed unique note hash was inserted into the tree at `tx_hash`, and will store the nullifier\n/// to later check for nullification.\n///\n/// `owner` is the address used in note hash and nullifier computation, often requiring knowledge of their nullifier\n/// secret key.\n///\n/// `scope` is the account to which the note message was delivered (i.e. the address the message was encrypted to).\n/// This determines which PXE account can see the note - other accounts will not be able to access it (e.g. other\n/// accounts will not be able to see one another's token balance notes, even in the same PXE) unless authorized. In\n/// most cases `recipient` equals `owner`, but they can differ in scenarios like delegated discovery.\npub unconstrained fn enqueue_note_for_validation(\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_nonce: Field,\n packed_note: BoundedVec,\n note_hash: Field,\n nullifier: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n NoteValidationRequest {\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_nonce,\n packed_note,\n note_hash,\n nullifier,\n tx_hash,\n },\n )\n}\n\n/// Enqueues an event for validation and storage by PXE.\n///\n/// This is the primary way for custom message handlers (registered via\n/// [`crate::macros::AztecConfig::custom_message_handler`]) to deliver reassembled events back to PXE after processing\n/// application-specific message formats.\n///\n/// In order for the event validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many event validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// Note that `validate_and_store_enqueued_notes_and_events` is called by Aztec.nr after processing messages, so custom\n/// message processors do not need to be concerned with this.\npub unconstrained fn enqueue_event_for_validation(\n contract_address: AztecAddress,\n event_type_id: EventSelector,\n randomness: Field,\n serialized_event: BoundedVec,\n event_commitment: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n EventValidationRequest {\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n },\n )\n}\n\n/// Validates and stores all enqueued notes and events.\n///\n/// Processes all requests enqueued via [`enqueue_note_for_validation`] and [`enqueue_event_for_validation`], inserting\n/// them into the note database and event store respectively, making them queryable via `get_notes` oracle and our TS\n/// API (PXE::getPrivateEvents).\npub unconstrained fn validate_and_store_enqueued_notes_and_events(scope: AztecAddress) {\n message_processing::validate_and_store_enqueued_notes_and_events(\n NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n MAX_NOTE_PACKED_LEN as Field,\n MAX_EVENT_SERIALIZED_LEN as Field,\n scope,\n );\n\n // Defensive clearing: purge the queues after processing to prevent double-processing if this function is called\n // more than once in the same call frame. It is currently defensive because we only call this once per sync run.\n let _ = EphemeralArray::::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n let _ = EphemeralArray::::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n}\n\n/// Efficiently queries the node for logs that result in the completion of all `DeliveredPendingPartialNote`s stored in\n/// a `CapsuleArray` by performing all node communication concurrently. Returns an `EphemeralArray` with Options\n/// for the responses that correspond to the pending partial notes at the same index.\n///\n/// For example, given an array with pending partial notes `[ p1, p2, p3 ]`, where `p1` and `p3` have corresponding\n/// completion logs but `p2` does not, the returned `EphemeralArray` will have contents `[some(p1_log), none(),\n/// some(p3_log)]`.\npub(crate) unconstrained fn get_pending_partial_notes_completion_logs(\n contract_address: AztecAddress,\n pending_partial_notes: CapsuleArray,\n) -> EphemeralArray> {\n let log_retrieval_requests = EphemeralArray::at(LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT);\n\n // We create a LogRetrievalRequest for each PendingPartialNote in the EphemeralArray. Because we need the indices in\n // the request array to match the indices in the partial note array, we can't use EphemeralArray::for_each, as that\n // function has arbitrary iteration order. Instead, we manually iterate the array from the beginning and push into\n // the requests array, which we expect to be empty.\n let mut i = 0;\n let pending_partial_notes_count = pending_partial_notes.len();\n while i < pending_partial_notes_count {\n let pending_partial_note = pending_partial_notes.get(i);\n // Partial note completion logs are emitted with a domain-separated tag. To find matching logs, we apply the\n // same domain separation to the stored raw tag.\n let log_tag = compute_log_tag(\n pending_partial_note.note_completion_log_tag,\n DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n );\n log_retrieval_requests.push(LogRetrievalRequest { contract_address, unsiloed_tag: log_tag });\n i += 1;\n }\n\n let responses = message_processing::get_logs_by_tag(log_retrieval_requests);\n\n // Defensive clearing: prevent stale requests if this function is called more than once in the same call frame.\n let _ = log_retrieval_requests.clear();\n\n responses\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/mod.nr","function_locations":[{"start":3763,"name":"enqueue_note_for_validation"},{"start":5177,"name":"enqueue_event_for_validation"},{"start":5884,"name":"validate_and_store_enqueued_notes_and_events"},{"start":7412,"name":"get_pending_partial_notes_completion_logs"}]},"154":{"source":"use crate::{\n capsules::CapsuleArray,\n context::UtilityContext,\n ephemeral::EphemeralArray,\n messages::{encoding::MESSAGE_CIPHERTEXT_LEN, processing::OffchainMessageWithContext},\n oracle::contract_sync::set_contract_sync_cache_invalid,\n protocol::{\n address::AztecAddress,\n constants::MAX_TX_LIFETIME,\n hash::sha256_to_field,\n traits::{Deserialize, Serialize},\n },\n};\n\n/// Base capsule slot for the persistent inbox of [`PendingOffchainMsg`] entries.\n///\n/// This is the slot where we accumulate messages received through [`receive`].\nglobal OFFCHAIN_INBOX_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_INBOX_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to pass tx hash resolution requests to PXE.\nglobal OFFCHAIN_CONTEXT_REQUESTS_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_CONTEXT_REQUESTS_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to collect messages ready for processing.\nglobal OFFCHAIN_READY_MESSAGES_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_READY_MESSAGES_SLOT\".as_bytes());\n\n/// Maximum number of offchain messages accepted by `offchain_receive` in a single call.\npub global MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL: u32 = 16;\n\n/// Tolerance added to the `MAX_TX_LIFETIME` cap for message expiration.\nglobal TX_EXPIRATION_TOLERANCE: u64 = 7200; // 2 hours\n\n/// Maximum time-to-live for a tx-bound offchain message.\n///\n/// After `anchor_block_timestamp + MAX_MSG_TTL`, the message is evicted from the inbox.\nglobal MAX_MSG_TTL: u64 = MAX_TX_LIFETIME + TX_EXPIRATION_TOLERANCE;\n\n/// A function that manages offchain-delivered messages for processing during sync.\n///\n/// Offchain messages are messages that are not broadcasted via onchain logs. They are instead delivered to the\n/// recipient by calling the `offchain_receive` utility function (injected by the `#[aztec]` macro). Message transport\n/// is the app's responsibility. Typical examples of transport methods are: messaging apps, email, QR codes, etc.\n///\n/// Once offchain messages are delivered to the recipient's private environment via `offchain_receive`, messages are\n/// locally stored in a persistent inbox.\n///\n/// This function determines when each message in said inbox is ready for processing, when it can be safely disposed\n/// of, etc.\n///\n/// The only current implementation of an `OffchainInboxSync` is [`sync_inbox`], which manages an inbox with expiration\n/// based eviction and automatic transaction context resolution.\npub(crate) type OffchainInboxSync = unconstrained fn[Env](\n/* contract_address */AztecAddress, /* scope */ AztecAddress) -> EphemeralArray;\n\n/// A message delivered via the `offchain_receive` utility function.\n#[derive(Serialize, Deserialize)]\npub struct OffchainMessage {\n /// The encrypted message payload.\n pub ciphertext: BoundedVec,\n /// The intended recipient of the message.\n pub recipient: AztecAddress,\n /// The hash of the transaction that produced this message. `Option::none` indicates a tx-less message.\n pub tx_hash: Option,\n /// Anchor block timestamp at message emission.\n pub anchor_block_timestamp: u64,\n}\n\n/// An offchain message awaiting processing (or re-processing) in the inbox.\n///\n/// Messages remain in the inbox until they expire, even if they have already been processed. This is necessary to\n/// handle reorgs: a processed message may need to be re-processed if the transaction that provided its context is\n/// reverted. On each sync, resolved messages are promoted to [`OffchainMessageWithContext`] for processing.\n#[derive(Serialize, Deserialize)]\nstruct PendingOffchainMsg {\n /// The encrypted message payload.\n ciphertext: BoundedVec,\n /// The intended recipient of the message.\n recipient: AztecAddress,\n /// The hash of the transaction that produced this message. A value of 0 indicates a tx-less message.\n tx_hash: Field,\n /// Anchor block timestamp at message emission. Used to compute the effective expiration: messages are evicted\n /// after `anchor_block_timestamp + MAX_MSG_TTL`.\n anchor_block_timestamp: u64,\n}\n\n/// Delivers offchain messages to the given contract's offchain inbox for subsequent processing.\n///\n/// Offchain messages are transaction effects that are not broadcasted via onchain logs. Instead, the sender shares the\n/// message to the recipient through an external channel (e.g. a URL accessible by the recipient). The recipient then\n/// calls this function to hand the messages to the contract so they can be processed through the same mechanisms as\n/// onchain messages.\n///\n/// Each message is routed to the inbox scoped to its `recipient` field, so messages for different accounts are\n/// automatically isolated.\n///\n/// Messages are processed when their originating transaction is found onchain (providing the context needed to\n/// validate resulting notes and events).\n///\n/// Messages are kept in the inbox until they expire. The effective expiration is\n/// `anchor_block_timestamp + MAX_MSG_TTL`.\n///\n/// Processing order is not guaranteed.\npub unconstrained fn receive(\n contract_address: AztecAddress,\n messages: BoundedVec,\n) {\n // May contain duplicates if multiple messages target the same recipient. This is harmless since\n // cache invalidation on the TS side is idempotent (deleting an already-deleted key is a no-op).\n let mut scopes: BoundedVec = BoundedVec::new();\n let mut i = 0;\n let messages_len = messages.len();\n while i < messages_len {\n let msg = messages.get(i);\n let tx_hash = if msg.tx_hash.is_some() {\n msg.tx_hash.unwrap()\n } else {\n 0\n };\n let inbox: CapsuleArray =\n CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, msg.recipient);\n inbox.push(\n PendingOffchainMsg {\n ciphertext: msg.ciphertext,\n recipient: msg.recipient,\n tx_hash,\n anchor_block_timestamp: msg.anchor_block_timestamp,\n },\n );\n scopes.push(msg.recipient);\n i += 1;\n }\n\n set_contract_sync_cache_invalid(contract_address, scopes);\n}\n\n/// Returns offchain-delivered messages to process during sync.\n///\n/// Messages remain in the inbox and are reprocessed on each sync until their originating transaction is no longer at\n/// risk of being dropped by a reorg.\npub unconstrained fn sync_inbox(\n contract_address: AztecAddress,\n scope: AztecAddress,\n) -> EphemeralArray {\n let inbox: CapsuleArray = CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, scope);\n let context_resolution_requests: EphemeralArray = EphemeralArray::at(OFFCHAIN_CONTEXT_REQUESTS_SLOT).clear();\n let ready_to_process: EphemeralArray =\n EphemeralArray::at(OFFCHAIN_READY_MESSAGES_SLOT).clear();\n\n // Build a request list aligned with the inbox indices.\n let mut i = 0;\n let inbox_len = inbox.len();\n while i < inbox_len {\n let msg = inbox.get(i);\n context_resolution_requests.push(msg.tx_hash);\n i += 1;\n }\n\n // Ask PXE to resolve contexts for all requested tx hashes. The oracle returns responses in a new\n // ephemeral array.\n let resolved_contexts =\n crate::oracle::message_processing::get_message_contexts_by_tx_hash(context_resolution_requests);\n\n assert_eq(resolved_contexts.len(), inbox_len);\n\n let now = UtilityContext::new().timestamp();\n\n let mut j = inbox_len;\n while j > 0 {\n // This loop decides what to do with each message in the offchain message inbox. We need to handle 3\n // different scenarios for each message.\n //\n // 1. The TX that emitted this message is still not known to PXE: in this case we can't yet process this\n // message, as any notes or events discovered will fail to be validated. So we leave the message in the inbox,\n // awaiting for future syncs to detect that the TX became available.\n //\n // 2. The message is not associated to a TX to begin with. The current version of offchain message processing\n // does not support this case, but in the future it will. Right now, a message without an associated TX will\n // sit in the inbox until it expires.\n //\n // 3. The TX that emitted this message has been found by PXE. That gives us all the information needed to\n // process the message. We add the message to the `ready_to_process` EphemeralArray so that the `sync_state`\n // loop\n // processes it.\n //\n // In all cases, if the message has expired (i.e. `now > anchor_block_timestamp + MAX_MSG_TTL`), we remove it\n // from the inbox.\n //\n // Note: the loop runs backwards because it might call `inbox.remove(j)` to purge expired messages and we also\n // need to align it with `resolved_contexts.get(j)`. Going from last to first simplifies the algorithm as\n // not yet visited element indexes remain stable.\n j -= 1;\n let maybe_ctx = resolved_contexts.get(j);\n let msg = inbox.get(j);\n\n // Compute the message's effective expiration timestamp to determine if we can purge it from the inbox.\n let effective_expiration = msg.anchor_block_timestamp + MAX_MSG_TTL;\n\n // Message expired. We remove it from the inbox.\n if now > effective_expiration {\n inbox.remove(j);\n }\n\n // Scenario 1: associated TX not yet available. We keep the message in the inbox, as it might become\n // processable as new blocks get mined.\n // Scenario 2: no TX associated to message. The message will sit in the inbox until it expires.\n if maybe_ctx.is_none() {\n continue;\n }\n\n // Scenario 3: Message is ready to process, add to result array. Note we still keep it in the inbox unless we\n // consider it has expired: this is because we need to account for reorgs. If reorg occurs after we processed\n // a message, the effects of processing the message get rewind. However, the associated TX can be included in\n // a subsequent block. Should that happen, the message must be re-processed to ensure consistency.\n let message_context = maybe_ctx.unwrap();\n ready_to_process.push(OffchainMessageWithContext { message_ciphertext: msg.ciphertext, message_context });\n }\n\n ready_to_process\n}\n\nmod test {\n use crate::{\n capsules::CapsuleArray, oracle::random::random, protocol::address::AztecAddress,\n test::helpers::test_environment::TestEnvironment,\n };\n use super::{\n MAX_MSG_TTL, MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL, OFFCHAIN_INBOX_SLOT, OffchainMessage, PendingOffchainMsg,\n receive, sync_inbox,\n };\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n /// Creates an `OffchainMessage` with dummy ciphertext and the given scope as recipient.\n fn make_msg(recipient: AztecAddress, tx_hash: Option, anchor_block_timestamp: u64) -> OffchainMessage {\n OffchainMessage { ciphertext: BoundedVec::new(), recipient, tx_hash, anchor_block_timestamp }\n }\n\n /// Advances the TXE block timestamp by `offset` seconds and returns the resulting timestamp.\n unconstrained fn advance_by(env: TestEnvironment, offset: u64) -> u64 {\n env.advance_next_block_timestamp_by(offset);\n env.mine_block();\n env.last_block_timestamp()\n }\n\n #[test]\n unconstrained fn empty_inbox_returns_empty_result() {\n let (env, scope) = setup();\n env.utility_context(|context| {\n let result = sync_inbox(context.this_address(), scope);\n let inbox: CapsuleArray =\n CapsuleArray::at(context.this_address(), OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0);\n assert_eq(inbox.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_not_expired_before_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance, but not past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn tx_less_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::none(), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn unresolved_tx_stays_in_inbox() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // not resolved, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn multiple_messages_mixed_expiration() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n let survivor_tx_hash = random();\n\n env.utility_context(|context| {\n let address = context.this_address();\n let mut msgs: BoundedVec = BoundedVec::new();\n // Message 0: tx-bound, anchor_ts in the past so it expires at\n // anchor_ts + MAX_MSG_TTL. We set anchor to 0 so it expires quickly.\n msgs.push(make_msg(scope, Option::some(random()), 0));\n // Message 1: tx-bound, anchor_ts is recent so it survives.\n msgs.push(make_msg(scope, Option::some(survivor_tx_hash), anchor_ts));\n // Message 2: tx-less, anchor_ts=0 so it also expires.\n msgs.push(make_msg(scope, Option::none(), 0));\n receive(address, msgs);\n });\n\n // Advance past MAX_MSG_TTL for anchor_ts=0, but not for anchor_ts=anchor_ts.\n let _now = advance_by(env, MAX_MSG_TTL);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // all contexts are None\n // Message 0 expired (anchor=0), message 1 survived (anchor=anchor_ts),\n // Message 2 expired (anchor=0).\n assert_eq(inbox.len(), 1);\n assert_eq(inbox.get(0).tx_hash, survivor_tx_hash);\n });\n }\n\n // -- Resolved context (ready to process) ------------------------------\n\n #[test]\n unconstrained fn resolved_msg_is_ready_to_process() {\n let (env, scope) = setup();\n // TestEnvironment::new() deploys protocol contracts, creating blocks with tx effects.\n // In TXE, tx hashes equal Fr(blockNumber), so Fr(1) is the tx effect from block 1.\n // We use this as a \"known resolvable\" tx hash.\n let known_tx_hash: Field = 1;\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(known_tx_hash), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n // The message should be ready to process since its tx context was resolved.\n assert_eq(result.len(), 1);\n\n let ctx = result.get(0).message_context;\n assert_eq(ctx.tx_hash, known_tx_hash);\n assert(ctx.first_nullifier_in_tx != 0, \"resolved context must have a first nullifier\");\n\n // Message stays in inbox (not expired) for potential reorg reprocessing.\n assert_eq(inbox.len(), 1);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/offchain.nr","function_locations":[{"start":5332,"name":"receive"},{"start":6775,"name":"sync_inbox"},{"start":11145,"name":"test::setup"},{"start":11475,"name":"test::make_msg"},{"start":11758,"name":"test::advance_by"},{"start":11949,"name":"test::empty_inbox_returns_empty_result"},{"start":12412,"name":"test::tx_bound_msg_expires_after_max_msg_ttl"},{"start":13377,"name":"test::tx_bound_msg_not_expired_before_max_msg_ttl"},{"start":14335,"name":"test::tx_less_msg_expires_after_max_msg_ttl"},{"start":15277,"name":"test::unresolved_tx_stays_in_inbox"},{"start":16171,"name":"test::multiple_messages_mixed_expiration"},{"start":17910,"name":"test::resolved_msg_is_ready_to_process"}]},"172":{"source":"#[oracle(aztec_utl_decryptAes128)]\nunconstrained fn aes128_decrypt_oracle(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {}\n\n/// Attempts to decrypt a ciphertext using AES128.\n///\n/// Returns `Option::some(plaintext)` on success, or `Option::none()` if decryption fails (e.g. due to malformed\n/// ciphertext or invalid PKCS#7 padding). Note that decryption with the wrong key will almost always return `None`\n/// because the decrypted garbage data will have invalid PKCS#7 padding.\n///\n/// Note that we accept ciphertext as a BoundedVec, not as an array. This is because this function is typically used\n/// when processing logs and at that point we don't have comptime information about the length of the ciphertext as\n/// the log is not specific to any individual note.\n// TODO(F-498): review naming consistency\npub unconstrained fn try_aes128_decrypt(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {\n aes128_decrypt_oracle(ciphertext, iv, sym_key)\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::compute_app_siloed_shared_secret,\n messages::encryption::aes128::derive_aes_symmetric_key_and_iv_from_shared_secret,\n utils::{array::subarray::subarray, point::point_from_x_coord},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::try_aes128_decrypt;\n use std::aes128::aes128_encrypt;\n\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress { inner: 42 };\n global TEST_PLAINTEXT_LENGTH: u32 = 10;\n global TEST_CIPHERTEXT_LENGTH: u32 = 16;\n global TEST_PADDING_LENGTH: u32 = TEST_CIPHERTEXT_LENGTH - TEST_PLAINTEXT_LENGTH;\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n\n let received_plaintext = try_aes128_decrypt(ciphertext_bvec, iv, sym_key).unwrap();\n assert_eq(received_plaintext.len(), TEST_PLAINTEXT_LENGTH);\n assert_eq(received_plaintext.max_len(), TEST_CIPHERTEXT_LENGTH);\n assert_eq(subarray::<_, _, TEST_PLAINTEXT_LENGTH>(received_plaintext.storage(), 0), plaintext);\n assert_eq(\n subarray::<_, _, TEST_PADDING_LENGTH>(received_plaintext.storage(), TEST_PLAINTEXT_LENGTH),\n [0 as u8; TEST_PADDING_LENGTH],\n );\n })\n }\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt_with_bad_sym_key_is_caught() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n // Decrypting with the wrong key results in garbage data with invalid PKCS#7 padding,\n // so the oracle returns None.\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let mut bad_sym_key = sym_key;\n bad_sym_key[0] = 0;\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n // Decryption with wrong key returns None because the garbage output has invalid PKCS#7 padding.\n let result = try_aes128_decrypt(ciphertext_bvec, iv, bad_sym_key);\n assert(result.is_none(), \"decryption with bad key should return None\");\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/aes128_decrypt.nr","function_locations":[{"start":194,"name":"aes128_decrypt_oracle"},{"start":1046,"name":"try_aes128_decrypt"},{"start":1860,"name":"test::aes_encrypt_then_decrypt"},{"start":3150,"name":"test::aes_encrypt_then_decrypt_with_bad_sym_key_is_caught"}]},"174":{"source":"//! AVM oracles.\n//!\n//! There are only available during public execution. Calling any of them from a private or utility function will\n//! result in runtime errors.\n\nuse crate::protocol::address::{AztecAddress, EthAddress};\n\npub unconstrained fn address() -> AztecAddress {\n address_opcode()\n}\npub unconstrained fn sender() -> AztecAddress {\n sender_opcode()\n}\npub unconstrained fn transaction_fee() -> Field {\n transaction_fee_opcode()\n}\npub unconstrained fn chain_id() -> Field {\n chain_id_opcode()\n}\npub unconstrained fn version() -> Field {\n version_opcode()\n}\npub unconstrained fn block_number() -> u32 {\n block_number_opcode()\n}\npub unconstrained fn timestamp() -> u64 {\n timestamp_opcode()\n}\npub unconstrained fn min_fee_per_l2_gas() -> u128 {\n min_fee_per_l2_gas_opcode()\n}\npub unconstrained fn min_fee_per_da_gas() -> u128 {\n min_fee_per_da_gas_opcode()\n}\npub unconstrained fn l2_gas_left() -> u32 {\n l2_gas_left_opcode()\n}\npub unconstrained fn da_gas_left() -> u32 {\n da_gas_left_opcode()\n}\npub unconstrained fn is_static_call() -> bool {\n is_static_call_opcode()\n}\npub unconstrained fn note_hash_exists(note_hash: Field, leaf_index: u64) -> bool {\n note_hash_exists_opcode(note_hash, leaf_index)\n}\npub unconstrained fn emit_note_hash(note_hash: Field) {\n emit_note_hash_opcode(note_hash)\n}\npub unconstrained fn nullifier_exists(siloed_nullifier: Field) -> bool {\n nullifier_exists_opcode(siloed_nullifier)\n}\npub unconstrained fn emit_nullifier(nullifier: Field) {\n emit_nullifier_opcode(nullifier)\n}\npub unconstrained fn emit_public_log(message: [Field]) {\n emit_public_log_opcode(message)\n}\npub unconstrained fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: u64) -> bool {\n l1_to_l2_msg_exists_opcode(msg_hash, msg_leaf_index)\n}\npub unconstrained fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {\n send_l2_to_l1_msg_opcode(recipient, content)\n}\n\npub unconstrained fn call(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn call_static(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_static_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn calldata_copy(cdoffset: u32, copy_size: u32) -> [Field; N] {\n calldata_copy_opcode(cdoffset, copy_size)\n}\n\n/// `success_copy` is placed immediately after the CALL opcode to get the success value\npub unconstrained fn success_copy() -> bool {\n success_copy_opcode()\n}\n\npub unconstrained fn returndata_size() -> u32 {\n returndata_size_opcode()\n}\n\npub unconstrained fn returndata_copy(rdoffset: u32, copy_size: u32) -> [Field] {\n returndata_copy_opcode(rdoffset, copy_size)\n}\n\n/// The additional prefix is to avoid clashing with the `return` Noir keyword.\npub unconstrained fn avm_return(returndata: [Field]) {\n return_opcode(returndata)\n}\n\n/// This opcode reverts using the exact data given. In general it should only be used to do rethrows, where the revert\n/// data is the same as the original revert data. For normal reverts, use Noir's `assert` which, on top of reverting,\n/// will also add an error selector to the revert data.\npub unconstrained fn revert(revertdata: [Field]) {\n revert_opcode(revertdata)\n}\n\npub unconstrained fn storage_read(storage_slot: Field, contract_address: Field) -> Field {\n storage_read_opcode(storage_slot, contract_address)\n}\n\npub unconstrained fn storage_write(storage_slot: Field, value: Field) {\n storage_write_opcode(storage_slot, value);\n}\n\n#[oracle(aztec_avm_address)]\nunconstrained fn address_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_sender)]\nunconstrained fn sender_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_transactionFee)]\nunconstrained fn transaction_fee_opcode() -> Field {}\n\n#[oracle(aztec_avm_chainId)]\nunconstrained fn chain_id_opcode() -> Field {}\n\n#[oracle(aztec_avm_version)]\nunconstrained fn version_opcode() -> Field {}\n\n#[oracle(aztec_avm_blockNumber)]\nunconstrained fn block_number_opcode() -> u32 {}\n\n#[oracle(aztec_avm_timestamp)]\nunconstrained fn timestamp_opcode() -> u64 {}\n\n#[oracle(aztec_avm_minFeePerL2Gas)]\nunconstrained fn min_fee_per_l2_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_minFeePerDaGas)]\nunconstrained fn min_fee_per_da_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_l2GasLeft)]\nunconstrained fn l2_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_daGasLeft)]\nunconstrained fn da_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_isStaticCall)]\nunconstrained fn is_static_call_opcode() -> bool {}\n\n#[oracle(aztec_avm_noteHashExists)]\nunconstrained fn note_hash_exists_opcode(note_hash: Field, leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_emitNoteHash)]\nunconstrained fn emit_note_hash_opcode(note_hash: Field) {}\n\n#[oracle(aztec_avm_nullifierExists)]\nunconstrained fn nullifier_exists_opcode(siloed_nullifier: Field) -> bool {}\n\n#[oracle(aztec_avm_emitNullifier)]\nunconstrained fn emit_nullifier_opcode(nullifier: Field) {}\n\n#[oracle(aztec_avm_emitPublicLog)]\nunconstrained fn emit_public_log_opcode(message: [Field]) {}\n\n#[oracle(aztec_avm_l1ToL2MsgExists)]\nunconstrained fn l1_to_l2_msg_exists_opcode(msg_hash: Field, msg_leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_sendL2ToL1Msg)]\nunconstrained fn send_l2_to_l1_msg_opcode(recipient: EthAddress, content: Field) {}\n\n#[oracle(aztec_avm_calldataCopy)]\nunconstrained fn calldata_copy_opcode(cdoffset: u32, copy_size: u32) -> [Field; N] {}\n\n#[oracle(aztec_avm_returndataSize)]\nunconstrained fn returndata_size_opcode() -> u32 {}\n\n#[oracle(aztec_avm_returndataCopy)]\nunconstrained fn returndata_copy_opcode(rdoffset: u32, copy_size: u32) -> [Field] {}\n\n#[oracle(aztec_avm_return)]\nunconstrained fn return_opcode(returndata: [Field]) {}\n\n#[oracle(aztec_avm_revert)]\nunconstrained fn revert_opcode(revertdata: [Field]) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_call)]\nunconstrained fn call_opcode(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_staticCall)]\nunconstrained fn call_static_opcode(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n#[oracle(aztec_avm_successCopy)]\nunconstrained fn success_copy_opcode() -> bool {}\n\n#[oracle(aztec_avm_storageRead)]\nunconstrained fn storage_read_opcode(storage_slot: Field, contract_address: Field) -> Field {}\n\n#[oracle(aztec_avm_storageWrite)]\nunconstrained fn storage_write_opcode(storage_slot: Field, value: Field) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/avm.nr","function_locations":[{"start":272,"name":"address"},{"start":343,"name":"sender"},{"start":415,"name":"transaction_fee"},{"start":489,"name":"chain_id"},{"start":555,"name":"version"},{"start":623,"name":"block_number"},{"start":693,"name":"timestamp"},{"start":770,"name":"min_fee_per_l2_gas"},{"start":856,"name":"min_fee_per_da_gas"},{"start":934,"name":"l2_gas_left"},{"start":1005,"name":"da_gas_left"},{"start":1080,"name":"is_static_call"},{"start":1193,"name":"note_hash_exists"},{"start":1302,"name":"emit_note_hash"},{"start":1414,"name":"nullifier_exists"},{"start":1518,"name":"emit_nullifier"},{"start":1614,"name":"emit_public_log"},{"start":1741,"name":"l1_to_l2_msg_exists"},{"start":1880,"name":"send_l2_to_l1_msg"},{"start":2080,"name":"call"},{"start":2310,"name":"call_static"},{"start":2486,"name":"calldata_copy"},{"start":2669,"name":"success_copy"},{"start":2746,"name":"returndata_size"},{"start":2859,"name":"returndata_copy"},{"start":3044,"name":"avm_return"},{"start":3421,"name":"revert"},{"start":3545,"name":"storage_read"},{"start":3676,"name":"storage_write"},{"start":3807,"name":"address_opcode"},{"start":3888,"name":"sender_opcode"},{"start":3979,"name":"transaction_fee_opcode"},{"start":4056,"name":"chain_id_opcode"},{"start":4132,"name":"version_opcode"},{"start":4215,"name":"block_number_opcode"},{"start":4293,"name":"timestamp_opcode"},{"start":4386,"name":"min_fee_per_l2_gas_opcode"},{"start":4479,"name":"min_fee_per_da_gas_opcode"},{"start":4559,"name":"l2_gas_left_opcode"},{"start":4639,"name":"da_gas_left_opcode"},{"start":4726,"name":"is_static_call_opcode"},{"start":4850,"name":"note_hash_exists_opcode"},{"start":4945,"name":"emit_note_hash_opcode"},{"start":5060,"name":"nullifier_exists_opcode"},{"start":5156,"name":"emit_nullifier_opcode"},{"start":5253,"name":"emit_public_log_opcode"},{"start":5384,"name":"l1_to_l2_msg_exists_opcode"},{"start":5504,"name":"send_l2_to_l1_msg_opcode"},{"start":5637,"name":"calldata_copy_opcode"},{"start":5726,"name":"returndata_size_opcode"},{"start":5848,"name":"returndata_copy_opcode"},{"start":5932,"name":"return_opcode"},{"start":6016,"name":"revert_opcode"},{"start":6463,"name":"call_opcode"},{"start":6923,"name":"call_static_opcode"},{"start":7007,"name":"success_copy_opcode"},{"start":7136,"name":"storage_read_opcode"},{"start":7247,"name":"storage_write_opcode"}]},"178":{"source":"use crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Stores arbitrary information in a per-contract non-volatile database, which can later be retrieved with `load`. If\n/// data was already stored at this slot, it is overwritten.\n// TODO(F-498): review naming consistency\npub unconstrained fn store(contract_address: AztecAddress, slot: Field, value: T, scope: AztecAddress)\nwhere\n T: Serialize,\n{\n let serialized = value.serialize();\n set_capsule_oracle(contract_address, slot, serialized, scope);\n}\n\n/// Returns data previously stored via `storeCapsule` in the per-contract non-volatile database. Returns\n/// Option::none() if nothing was stored at the given slot.\n// TODO(F-498): review naming consistency\npub unconstrained fn load(contract_address: AztecAddress, slot: Field, scope: AztecAddress) -> Option\nwhere\n T: Deserialize,\n{\n let serialized_option = get_capsule_oracle(contract_address, slot, ::N, scope);\n serialized_option.map(|arr| Deserialize::deserialize(arr))\n}\n\n/// Deletes data in the per-contract non-volatile database. Does nothing if no data was present.\npub unconstrained fn delete(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {\n delete_oracle(contract_address, slot, scope);\n}\n\n/// Copies a number of contiguous entries in the per-contract non-volatile database. This allows for efficient data\n/// structures by avoiding repeated calls to `loadCapsule` and `storeCapsule`. Supports overlapping source and\n/// destination regions (which will result in the overlapped source values being overwritten). All copied slots must\n/// exist in the database (i.e. have been stored and not deleted)\npub unconstrained fn copy(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {\n copy_oracle(contract_address, src_slot, dst_slot, num_entries, scope);\n}\n\n#[oracle(aztec_utl_setCapsule)]\nunconstrained fn set_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n values: [Field; N],\n scope: AztecAddress,\n) {}\n\n/// We need to pass in `array_len` (the value of N) as a parameter to tell the oracle how many fields the response must\n/// have.\n///\n/// Note that the oracle returns an Option<[Field; N]> because we cannot return an Option directly. That would\n/// require for the oracle resolver to know the shape of T (e.g. if T were a struct of 3 u32 values then the expected\n/// response shape would be 3 single items, whereas it were a struct containing `u32, [Field;10], u32` then the\n/// expected shape would be single, array, single.). Instead, we return the serialization and deserialize in Noir.\n#[oracle(aztec_utl_getCapsule)]\nunconstrained fn get_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n array_len: u32,\n scope: AztecAddress,\n) -> Option<[Field; N]> {}\n\n#[oracle(aztec_utl_deleteCapsule)]\nunconstrained fn delete_oracle(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {}\n\n#[oracle(aztec_utl_copyCapsule)]\nunconstrained fn copy_oracle(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {}\n\nmod test {\n // These tests are sort of redundant since we already test the oracle implementation directly in TypeScript, but\n // they are cheap regardless and help ensure both that the TXE implementation works accordingly and that the Noir\n // oracles are hooked up correctly.\n\n use crate::{\n oracle::capsules::{copy, delete, load, store},\n test::{helpers::test_environment::TestEnvironment, mocks::MockStruct},\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, ToField}};\n\n global SLOT: Field = 1;\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n #[test]\n unconstrained fn stores_and_loads() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), value);\n });\n }\n\n #[test]\n unconstrained fn store_overwrites() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n let new_value = MockStruct::new(7, 8);\n store(contract_address, SLOT, new_value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), new_value);\n });\n }\n\n #[test]\n unconstrained fn loads_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_stored_value() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n delete(contract_address, SLOT, scope);\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n delete(contract_address, SLOT, scope);\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn copies_non_overlapping_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 5;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 10;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_src_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 1;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 2;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[1] and src[2] should have been overwritten since they are also dst[0] and dst[1]\n assert_eq(load(contract_address, src, scope).unwrap(), values[0]); // src[0] (unchanged)\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[0]); // dst[0]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[1]); // dst[1]\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_dst_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 2;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 1;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[0] and src[1] should have been overwritten since they are also dst[1] and dst[2]\n assert_eq(load(contract_address, src, scope).unwrap(), values[1]); // dst[1]\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[2]); // dst[2]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[2]); // src[2] (unchanged)\n });\n }\n\n #[test(should_fail_with = \"copy empty slot\")]\n unconstrained fn cannot_copy_empty_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n copy(contract_address, SLOT, SLOT, 1, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_store_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let value = MockStruct::new(5, 6);\n store(other_contract_address, SLOT, value, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_load_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let _: Option = load(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_delete_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n delete(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_copy_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n copy(other_contract_address, SLOT, SLOT, 0, scope);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/capsules.nr","function_locations":[{"start":433,"name":"store"},{"start":886,"name":"load"},{"start":1247,"name":"delete"},{"start":1866,"name":"copy"},{"start":2131,"name":"set_capsule_oracle"},{"start":2931,"name":"get_capsule_oracle"},{"start":3067,"name":"delete_oracle"},{"start":3261,"name":"copy_oracle"},{"start":3884,"name":"test::setup"},{"start":4060,"name":"test::stores_and_loads"},{"start":4450,"name":"test::store_overwrites"},{"start":4957,"name":"test::loads_empty_slot"},{"start":5311,"name":"test::deletes_stored_value"},{"start":5819,"name":"test::deletes_empty_slot"},{"start":6233,"name":"test::copies_non_overlapping_values"},{"start":7106,"name":"test::copies_overlapping_values_with_src_ahead"},{"start":8366,"name":"test::copies_overlapping_values_with_dst_ahead"},{"start":9648,"name":"test::cannot_copy_empty_values"},{"start":9970,"name":"test::cannot_store_other_contract"},{"start":10443,"name":"test::cannot_load_other_contract"},{"start":10891,"name":"test::cannot_delete_other_contract"},{"start":11311,"name":"test::cannot_copy_other_contract"}]},"179":{"source":"use crate::protocol::address::AztecAddress;\n\n#[oracle(aztec_utl_setContractSyncCacheInvalid)]\nunconstrained fn set_contract_sync_cache_invalid_oracle(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {}\n\n/// Forces the PXE to re-sync the given contract for a set of scopes on the next query.\n///\n/// Call this after writing data (e.g. offchain messages) that the contract's `sync_state` function needs to discover.\n/// Without invalidation, the sync cache would skip re-running `sync_state` until the next block.\npub unconstrained fn set_contract_sync_cache_invalid(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {\n set_contract_sync_cache_invalid_oracle(contract_address, scopes);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/contract_sync.nr","function_locations":[{"start":242,"name":"set_contract_sync_cache_invalid_oracle"},{"start":700,"name":"set_contract_sync_cache_invalid"}]},"181":{"source":"use crate::context::UtilityContext;\n\n#[oracle(aztec_utl_getUtilityContext)]\nunconstrained fn get_utility_context_oracle() -> UtilityContext {}\n\n/// Returns a utility context built from the global variables of anchor block and the contract address of the function\n/// being executed.\npub unconstrained fn get_utility_context() -> UtilityContext {\n get_utility_context_oracle()\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/execution.nr","function_locations":[{"start":140,"name":"get_utility_context_oracle"},{"start":344,"name":"get_utility_context"}]},"191":{"source":"use crate::ephemeral::EphemeralArray;\nuse crate::messages::processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse, MessageContext,\n pending_tagged_log::PendingTaggedLog,\n};\nuse crate::protocol::address::AztecAddress;\n\n/// Finds new private logs that may have been sent to all registered accounts in PXE in the current contract and\n/// returns them in an ephemeral array with an oracle-allocated base slot.\npub(crate) unconstrained fn get_pending_tagged_logs(scope: AztecAddress) -> EphemeralArray {\n let result_slot = get_pending_tagged_logs_oracle(scope);\n EphemeralArray::at(result_slot)\n}\n\n#[oracle(aztec_utl_getPendingTaggedLogs_v2)]\nunconstrained fn get_pending_tagged_logs_oracle(scope: AztecAddress) -> Field {}\n\n/// Validates note/event requests stored in ephemeral arrays.\npub(crate) unconstrained fn validate_and_store_enqueued_notes_and_events(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {\n validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot,\n event_validation_requests_array_slot,\n max_note_packed_len,\n max_event_serialized_len,\n scope,\n );\n}\n\n#[oracle(aztec_utl_validateAndStoreEnqueuedNotesAndEvents_v2)]\nunconstrained fn validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {}\n\n/// Fetches logs by tag from an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_logs_by_tag(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_logs_by_tag_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getLogsByTag_v2)]\nunconstrained fn get_logs_by_tag_v2_oracle(request_array_slot: Field) -> Field {}\n\n/// Resolves message contexts for tx hashes in an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_message_contexts_by_tx_hash(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_message_contexts_by_tx_hash_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getMessageContextsByTxHash_v2)]\nunconstrained fn get_message_contexts_by_tx_hash_v2_oracle(request_array_slot: Field) -> Field {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/message_processing.nr","function_locations":[{"start":570,"name":"get_pending_tagged_logs"},{"start":795,"name":"get_pending_tagged_logs_oracle"},{"start":1128,"name":"validate_and_store_enqueued_notes_and_events"},{"start":1692,"name":"validate_and_store_enqueued_notes_and_events_oracle"},{"start":1938,"name":"get_logs_by_tag"},{"start":2163,"name":"get_logs_by_tag_v2_oracle"},{"start":2423,"name":"get_message_contexts_by_tx_hash"},{"start":2694,"name":"get_message_contexts_by_tx_hash_v2_oracle"}]},"198":{"source":"use crate::protocol::address::aztec_address::AztecAddress;\nuse crate::protocol::point::Point;\n\n#[oracle(aztec_utl_getSharedSecret)]\nunconstrained fn get_shared_secret_oracle(\n address: AztecAddress,\n ephPk: Point,\n contract_address: AztecAddress,\n) -> Field {}\n\n/// Returns an app-siloed shared secret between `address` and someone who knows the secret key behind an ephemeral\n/// public key `ephPk`.\n///\n/// The returned value is a Field `s_app`, computed as:\n///\n/// ```text\n/// S = address_secret * ephPk (raw ECDH point)\n/// s_app = h(DOM_SEP, S.x, S.y, contract) (app-siloed scalar)\n/// ```\n///\n/// where `contract` is the address of the calling contract. The oracle host validates this matches its execution\n/// context.\n///\n/// Without app-siloing, a malicious contract could call this oracle with public information (address, ephPk) and\n/// obtain the same raw secret as the legitimate contract, enabling cross-contract decryption. By including the\n/// contract address in the hash, each contract receives a different `s_app`, preventing this attack.\n///\n/// Callers derive indexed subkeys from `s_app` via\n/// [`derive_shared_secret_subkey`](crate::keys::ecdh_shared_secret::derive_shared_secret_subkey).\npub unconstrained fn get_shared_secret(address: AztecAddress, ephPk: Point, contract_address: AztecAddress) -> Field {\n get_shared_secret_oracle(address, ephPk, contract_address)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr","function_locations":[{"start":267,"name":"get_shared_secret_oracle"},{"start":1354,"name":"get_shared_secret"}]},"247":{"source":"/// Appends the elements of the second `BoundedVec` to the end of the first one. The resulting `BoundedVec` can have\n/// any arbitrary maximum length, but it must be large enough to fit all of the elements of both the first and second\n/// vectors.\npub fn append(\n a: BoundedVec,\n b: BoundedVec,\n) -> BoundedVec {\n let mut dst = BoundedVec::new();\n\n dst.extend_from_bounded_vec(a);\n dst.extend_from_bounded_vec(b);\n\n dst\n}\n\nmod test {\n use super::append;\n\n #[test]\n unconstrained fn append_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::new();\n let b: BoundedVec<_, 14> = BoundedVec::new();\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 0);\n assert_eq(result.storage(), std::mem::zeroed());\n }\n\n #[test]\n unconstrained fn append_non_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 6);\n assert_eq(result.storage(), [1, 2, 3, 4, 5, 6, std::mem::zeroed(), std::mem::zeroed()]);\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn append_non_empty_vecs_insufficient_max_len() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let _: BoundedVec = append(a, b);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/append.nr","function_locations":[{"start":396,"name":"append"},{"start":608,"name":"test::append_empty_vecs"},{"start":933,"name":"test::append_non_empty_vecs"},{"start":1387,"name":"test::append_non_empty_vecs_insufficient_max_len"}]},"250":{"source":"/// Returns `DstLen` elements from a source array, starting at `offset`. `DstLen` must not be larger than the number of\n/// elements past `offset`.\n///\n/// Examples:\n/// ```\n/// let foo: [Field; 2] = subarray([1, 2, 3, 4, 5], 2);\n/// assert_eq(foo, [3, 4]);\n///\n/// let bar: [Field; 5] = subarray([1, 2, 3, 4, 5], 2); // fails - we can't return 5 elements since only 3 remain\n/// ```\npub fn subarray(src: [T; SrcLen], offset: u32) -> [T; DstLen] {\n assert(offset + DstLen <= SrcLen, \"DstLen too large for offset\");\n\n let mut dst: [T; DstLen] = std::mem::zeroed();\n for i in 0..DstLen {\n dst[i] = src[i + offset];\n }\n\n dst\n}\n\nmod test {\n use super::subarray;\n\n #[test]\n unconstrained fn subarray_into_empty() {\n // In all of these cases we're setting DstLen to be 0, so we always get back an empty array.\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 2), []);\n }\n\n #[test]\n unconstrained fn subarray_complete() {\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), [1, 2, 3, 4, 5]);\n }\n\n #[test]\n unconstrained fn subarray_different_end_sizes() {\n // We implicitly select how many values to read in the size of the return array\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4, 5]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2]);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subarray_offset_too_large() {\n // With an offset of 1 we can only request up to 4 elements\n let _: [_; 5] = subarray([1, 2, 3, 4, 5], 1);\n }\n\n #[test(should_fail)]\n unconstrained fn subarray_bad_return_value() {\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [3, 3, 4, 5]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr","function_locations":[{"start":483,"name":"subarray"},{"start":776,"name":"test::subarray_into_empty"},{"start":1100,"name":"test::subarray_complete"},{"start":1294,"name":"test::subarray_different_end_sizes"},{"start":1736,"name":"test::subarray_offset_too_large"},{"start":1941,"name":"test::subarray_bad_return_value"}]},"251":{"source":"use crate::utils::array;\n\n/// Returns `DstMaxLen` elements from a source BoundedVec, starting at `offset`. `offset` must not be larger than the\n/// original length, and `DstLen` must not be larger than the total number of elements past `offset` (including the\n/// zeroed elements past `len()`).\n///\n/// Only elements at the beginning of the vector can be removed: it is not possible to also remove elements at the end\n/// of the vector by passing a value for `DstLen` that is smaller than `len() - offset`.\n///\n/// Examples:\n/// ```\n/// let foo = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n/// assert_eq(subbvec(foo, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n///\n/// let bar: BoundedVec<_, 1> = subbvec(foo, 2); // fails - we can't return just 1 element since 3 remain\n/// let baz: BoundedVec<_, 10> = subbvec(foo, 3); // fails - we can't return 10 elements since only 7 remain\n/// ```\npub fn subbvec(\n bvec: BoundedVec,\n offset: u32,\n) -> BoundedVec {\n // from_parts_unchecked does not verify that the elements past len are zeroed, but that is not an issue in our case\n // because we're constructing the new storage array as a subarray of the original one (which should have zeroed\n // storage past len), guaranteeing correctness. This is because `subarray` does not allow extending arrays past\n // their original length.\n BoundedVec::from_parts_unchecked(array::subarray(bvec.storage(), offset), bvec.len() - offset)\n}\n\nmod test {\n use super::subbvec;\n\n #[test]\n unconstrained fn subbvec_empty() {\n let bvec = BoundedVec::::from_array([]);\n assert_eq(subbvec(bvec, 0), bvec);\n }\n\n #[test]\n unconstrained fn subbvec_complete() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), bvec);\n\n let smaller_capacity = BoundedVec::<_, 5>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), smaller_capacity);\n }\n\n #[test]\n unconstrained fn subbvec_partial() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 3>::from_array([3, 4, 5]));\n }\n\n #[test]\n unconstrained fn subbvec_into_empty() {\n let bvec: BoundedVec<_, 10> = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 5), BoundedVec::<_, 5>::from_array([]));\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_offset_past_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n let _: BoundedVec<_, 1> = subbvec(bvec, 6);\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_insufficient_dst_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // We're not providing enough space to hold all of the items inside the original BoundedVec. subbvec can cause\n // for the capacity to reduce, but not the length (other than by len - offset).\n let _: BoundedVec<_, 1> = subbvec(bvec, 2);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_causes_enlarge() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // subbvec does not support capacity increases\n let _: BoundedVec<_, 11> = subbvec(bvec, 0);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_too_large_for_offset() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // This effectively requests a capacity increase, since there'd be just one element plus the 5 empty slots,\n // which is less than 7.\n let _: BoundedVec<_, 7> = subbvec(bvec, 4);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr","function_locations":[{"start":1041,"name":"subbvec"},{"start":1612,"name":"test::subbvec_empty"},{"start":1775,"name":"test::subbvec_complete"},{"start":2083,"name":"test::subbvec_partial"},{"start":2376,"name":"test::subbvec_into_empty"},{"start":2609,"name":"test::subbvec_offset_past_len"},{"start":2816,"name":"test::subbvec_insufficient_dst_len"},{"start":3270,"name":"test::subbvec_dst_len_causes_enlarge"},{"start":3579,"name":"test::subbvec_dst_len_too_large_for_offset"}]},"254":{"source":"use std::static_assert;\n\n/// Encodes an array of bytes as fields.\n///\n/// Use\n/// [`decode_bytes_from_fields`](crate::utils::conversion::bytes_as_fields::decode_bytes_from_fields) to recover\n/// the original bytes.\n///\n/// The `bytes` array length must be a multiple of 31. If padding is added, it will need to be manually removed\n/// after decoding.\n///\n/// ## Encoding\n///\n/// Each 31-byte chunk is interpreted as a big-endian integer and stored in a `Field`. For input `[1, 10, 3, ..., 0]`\n/// (31 bytes), the resulting `Field` is `1 * 256^30 + 10 * 256^29 + 3 * 256^28 + ... + 0`.\npub fn encode_bytes_as_fields(bytes: [u8; N]) -> [Field; N / 31] {\n static_assert(N % 31 == 0, \"N must be a multiple of 31\");\n\n let mut fields = [0; N / 31];\n for i in 0..N / 31 {\n let mut field = 0;\n for j in 0..31 {\n field = field * 256 + bytes[i * 31 + j] as Field;\n }\n fields[i] = field;\n }\n\n fields\n}\n\n/// Decodes fields back into bytes.\n///\n/// Inverse of\n/// [`encode_bytes_as_fields`](crate::utils::conversion::bytes_as_fields::encode_bytes_as_fields).\n/// Each input `Field` must fit in 248 bits; `Field::to_be_bytes::<31>()` fails the proof otherwise.\npub fn decode_bytes_from_fields(fields: BoundedVec) -> BoundedVec {\n let mut bytes = BoundedVec::new();\n for i in 0..fields.len() {\n let chunk: [u8; 31] = fields.get(i).to_be_bytes();\n for j in 0..31 {\n bytes.push(chunk[j]);\n }\n }\n bytes\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_bytes_from_fields, encode_bytes_as_fields};\n\n #[test]\n unconstrained fn round_trips_bytes(input: [u8; 93]) {\n let fields = encode_bytes_as_fields(input);\n\n // In production the fields fly through the system and arrive as a BoundedVec on the other end.\n let fields_bvec = BoundedVec::<_, 6>::from_array(fields);\n let bytes_back = decode_bytes_from_fields(fields_bvec);\n\n assert_eq(bytes_back.len(), input.len());\n assert_eq(subarray(bytes_back.storage(), 0), input);\n }\n\n #[test(should_fail_with = \"N must be a multiple of 31\")]\n unconstrained fn encode_rejects_length_not_multiple_of_31() {\n let _fields = encode_bytes_as_fields([0; 32]);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 31 limbs\")]\n unconstrained fn decode_rejects_oversized_field() {\n // `Field::to_be_bytes::<31>()` fails the proof when a field has any bit above position 247 set.\n let oversized: Field = (1 as Field) * 2.pow_32(249);\n let input = BoundedVec::<_, 1>::from_array([oversized]);\n let _bytes = decode_bytes_from_fields(input);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/bytes_as_fields.nr","function_locations":[{"start":662,"name":"encode_bytes_as_fields"},{"start":1313,"name":"decode_bytes_from_fields"},{"start":1719,"name":"tests::round_trips_bytes"},{"start":2252,"name":"tests::encode_rejects_length_not_multiple_of_31"},{"start":2454,"name":"tests::decode_rejects_oversized_field"}]},"255":{"source":"/// Encodes an array of fields as bytes.\n///\n/// Losslessly preserves any field value; use\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes) to\n/// recover the original fields.\n///\n/// ## Encoding\n///\n/// Each field is written as 32 big-endian bytes and the chunks are concatenated. The field array `[5, 42]` becomes:\n///\n/// ```text\n/// [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, // First field (32 bytes)\n/// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42] // Second field (32 bytes)\n/// ```\n///\n/// ## Privacy\n///\n/// The BN254 modulus is `< 2^254`, so every 32-byte chunk has its top bit at zero and the next bit biased. The output\n/// is therefore distinguishable from uniform random bytes; take this into account when feeding it into anything that\n/// assumes uniform randomness (e.g. ciphertexts meant to look random).\npub fn encode_fields_as_bytes(fields: [Field; N]) -> [u8; 32 * N] {\n let mut bytes = [0; 32 * N];\n for i in 0..N {\n let chunk: [u8; 32] = fields[i].to_be_bytes();\n for j in 0..32 {\n bytes[i * 32 + j] = chunk[j];\n }\n }\n bytes\n}\n\n/// Decodes bytes back into fields.\n///\n/// Panics if the input length is not a multiple of 32 or if any chunk exceeds the BN254 field modulus. See\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes)\n/// for a non-panicking variant.\npub fn decode_fields_from_bytes(bytes: BoundedVec) -> BoundedVec {\n assert(bytes.len() % 32 == 0, \"Input length must be a multiple of 32\");\n try_decode_fields_from_bytes(bytes).expect(f\"Value does not fit in field\")\n}\n\n/// Decodes bytes back into fields, returning None on failure.\n///\n/// Inverse of\n/// [`encode_fields_as_bytes`](crate::utils::conversion::fields_as_bytes::encode_fields_as_bytes).\n/// Returns `Option::none()` if the input length is not a multiple of 32, or if any 32-byte chunk is `>=` the BN254\n/// field modulus.\npub fn try_decode_fields_from_bytes(bytes: BoundedVec) -> Option> {\n if bytes.len() % 32 == 0 {\n let num_chunks = bytes.len() / 32;\n let mut fields: BoundedVec = BoundedVec::new();\n for i in 0..num_chunks {\n let maybe_field = try_decode_field_from_bytes(bytes, i * 32);\n if maybe_field.is_some() {\n fields.push(maybe_field.unwrap());\n }\n }\n if fields.len() == num_chunks {\n Option::some(fields)\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n}\n\nfn try_decode_field_from_bytes(bytes: BoundedVec, offset: u32) -> Option {\n // Field arithmetic silently wraps values >= the modulus, so we compare each chunk against the modulus\n // byte-by-byte (big-endian) while building `field`. cmp: 0 = equal so far, 1 = less than modulus, 2 = exceeds.\n let p = std::field::modulus_be_bytes();\n let mut field = 0;\n let mut cmp: u8 = 0;\n for j in 0..32 {\n let byte = bytes.get(offset + j);\n field = field * 256 + byte as Field;\n if cmp == 0 {\n if byte < p[j] {\n cmp = 1;\n } else if byte > p[j] {\n cmp = 2;\n }\n }\n }\n\n if cmp == 1 {\n Option::some(field)\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_fields_from_bytes, encode_fields_as_bytes, try_decode_fields_from_bytes};\n\n #[test]\n unconstrained fn round_trips_fields(input: [Field; 3]) {\n let bytes = encode_fields_as_bytes(input);\n\n // In production the bytes fly through the system and arrive as a BoundedVec on the other end. 113 is an\n // arbitrary max length larger than the input length of 96.\n let bytes_bvec = BoundedVec::<_, 113>::from_array(bytes);\n let fields_back = try_decode_fields_from_bytes(bytes_bvec).unwrap();\n\n assert_eq(fields_back.len(), input.len());\n assert_eq(subarray(fields_back.storage(), 0), input);\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_length_not_multiple_of_32() {\n let input = BoundedVec::<_, 64>::from_parts([0 as u8; 64], 33);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test]\n unconstrained fn try_decode_accepts_max_field() {\n // -1 in field arithmetic wraps to `modulus - 1`, the largest valid field value.\n let max_field_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let input = BoundedVec::<_, 32>::from_array(max_field_as_bytes);\n\n let fields = try_decode_fields_from_bytes(input).unwrap();\n\n assert_eq(fields.get(0), -1);\n }\n\n // Verifies the overflow check: take the max allowed value, bump a random byte, feed it in.\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n // Skip if the selected byte is already 255. Acceptable under fuzz testing.\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_equal_to_modulus() {\n // The field modulus itself is not a valid field value (it wraps to 0).\n let p: [u8; 32] = std::field::modulus_be_bytes().as_array();\n let input = BoundedVec::::from_array(p);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test(should_fail_with = \"Input length must be a multiple of 32\")]\n unconstrained fn decode_asserts_length_multiple_of_32() {\n let input = BoundedVec::<_, 143>::from_array([\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n 30, 31, 32, 33,\n ]);\n let _fields = decode_fields_from_bytes(input);\n }\n\n #[test(should_fail_with = \"Value does not fit in field\")]\n unconstrained fn decode_panics_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n let _fields = decode_fields_from_bytes(input);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/fields_as_bytes.nr","function_locations":[{"start":1007,"name":"encode_fields_as_bytes"},{"start":1603,"name":"decode_fields_from_bytes"},{"start":2190,"name":"try_decode_fields_from_bytes"},{"start":2829,"name":"try_decode_field_from_bytes"},{"start":3733,"name":"tests::round_trips_fields"},{"start":4320,"name":"tests::try_decode_returns_none_on_length_not_multiple_of_32"},{"start":4528,"name":"tests::try_decode_accepts_max_field"},{"start":5063,"name":"tests::try_decode_returns_none_on_chunk_above_modulus"},{"start":5718,"name":"tests::try_decode_returns_none_on_chunk_equal_to_modulus"},{"start":6128,"name":"tests::decode_asserts_length_multiple_of_32"},{"start":6544,"name":"tests::decode_panics_on_chunk_above_modulus"}]},"258":{"source":"use crate::protocol::{point::Point, utils::field::sqrt};\n\n// I am storing the modulus minus 1 divided by 2 here because full modulus would throw \"String literal too large\" error\n// Full modulus is 21888242871839275222246405745257275088548364400416034343698204186575808495617\nglobal BN254_FR_MODULUS_DIV_2: Field = 10944121435919637611123202872628637544274182200208017171849102093287904247808;\n\n/// Returns: true if p.y <= MOD_DIV_2, else false.\npub fn get_sign_of_point(p: Point) -> bool {\n // We store only a \"sign\" of the y coordinate because the rest can be derived from the x coordinate. To get the\n // sign we check if the y coordinate is less or equal than the field's modulus minus 1 divided by 2. Ideally we'd\n // do `y <= MOD_DIV_2`, but there's no `lte` function, so instead we do `!(y > MOD_DIV_2)`, which is equivalent,\n // and then rewrite that as `!(MOD_DIV_2 < y)`, since we also have no `gt` function.\n !BN254_FR_MODULUS_DIV_2.lt(p.y)\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\npub fn point_from_x_coord(x: Field) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n sqrt(rhs).map(|y| Point { x, y, is_infinite: false })\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate and sign for the y coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\n///\n/// @param x - The x coordinate of the point @param sign - The \"sign\" of the y coordinate - determines whether y <=\n/// (Fr.MODULUS - 1) / 2\npub fn point_from_x_coord_and_sign(x: Field, sign: bool) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n\n sqrt(rhs).map(|y| {\n // If there is a square root, we need to ensure it has the correct \"sign\"\n let y_is_positive = !BN254_FR_MODULUS_DIV_2.lt(y);\n let final_y = if y_is_positive == sign { y } else { -y };\n Point { x, y: final_y, is_infinite: false }\n })\n}\n\nmod test {\n use crate::protocol::point::Point;\n use crate::utils::point::{\n BN254_FR_MODULUS_DIV_2, get_sign_of_point, point_from_x_coord, point_from_x_coord_and_sign,\n };\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign() {\n // Test positive y coordinate\n let x = 0x1af41f5de96446dc3776a1eb2d98bb956b7acd9979a67854bec6fa7c2973bd73;\n let sign = true;\n let p = point_from_x_coord_and_sign(x, sign).unwrap();\n\n assert_eq(p.x, x);\n assert_eq(p.y, 0x07fc22c7f2c7057571f137fe46ea9c95114282bc95d37d71ec4bfb88de457d4a);\n assert_eq(p.is_infinite, false);\n\n // Test negative y coordinate\n let x2 = 0x247371652e55dd74c9af8dbe9fb44931ba29a9229994384bd7077796c14ee2b5;\n let sign2 = false;\n let p2 = point_from_x_coord_and_sign(x2, sign2).unwrap();\n\n assert_eq(p2.x, x2);\n assert_eq(p2.y, 0x26441aec112e1ae4cee374f42556932001507ad46e255ffb27369c7e3766e5c0);\n assert_eq(p2.is_infinite, false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_valid() {\n // x = 8 is a known quadratic residue - should give a valid point\n let result = point_from_x_coord(Field::from(8));\n assert(result.is_some());\n\n let point = result.unwrap();\n assert_eq(point.x, Field::from(8));\n // Check curve equation y^2 = x^3 - 17\n assert_eq(point.y * point.y, point.x * point.x * point.x - 17);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_invalid() {\n // x = 3 is a non-residue for this curve - should give None\n let x = Field::from(3);\n let maybe_point = point_from_x_coord(x);\n assert(maybe_point.is_none());\n }\n\n #[test]\n unconstrained fn test_both_roots_satisfy_curve() {\n // Derive a point from x = 8 (known to be valid from test_point_from_x_coord_valid)\n let x: Field = 8;\n let point = point_from_x_coord(x).unwrap();\n\n // Check y satisfies curve equation\n assert_eq(point.y * point.y, x * x * x - 17);\n\n // Check -y also satisfies curve equation\n let neg_y = 0 - point.y;\n assert_eq(neg_y * neg_y, x * x * x - 17);\n\n // Verify they are different (unless y = 0)\n assert(point.y != neg_y);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign_invalid() {\n // x = 3 has no valid point on the curve (from test_point_from_x_coord_invalid)\n let x = Field::from(3);\n let result_positive = point_from_x_coord_and_sign(x, true);\n let result_negative = point_from_x_coord_and_sign(x, false);\n\n assert(result_positive.is_none());\n assert(result_negative.is_none());\n }\n\n #[test]\n unconstrained fn test_get_sign_of_point() {\n // Derive a point from x = 8, then test both possible y values\n let point = point_from_x_coord(8).unwrap();\n let neg_point = Point { x: point.x, y: 0 - point.y, is_infinite: false };\n\n // One should be \"positive\" (y <= MOD_DIV_2) and one \"negative\"\n let sign1 = get_sign_of_point(point);\n let sign2 = get_sign_of_point(neg_point);\n assert(sign1 != sign2);\n\n // y = 0 should return true (0 <= MOD_DIV_2)\n let zero_y_point = Point { x: 0, y: 0, is_infinite: false };\n assert(get_sign_of_point(zero_y_point) == true);\n\n // y = MOD_DIV_2 should return true (exactly at boundary)\n let boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2, is_infinite: false };\n assert(get_sign_of_point(boundary_point) == true);\n\n // y = MOD_DIV_2 + 1 should return false (just over boundary)\n let over_boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2 + 1, is_infinite: false };\n assert(get_sign_of_point(over_boundary_point) == false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_zero() {\n // x = 0: y^2 = 0^3 - 17 = -17, which is not a quadratic residue in BN254 scalar field\n let result = point_from_x_coord(0);\n assert(result.is_none());\n }\n\n #[test]\n unconstrained fn test_bn254_fr_modulus_div_2() {\n // Verify that BN254_FR_MODULUS_DIV_2 == (p - 1) / 2 This means: 2 * BN254_FR_MODULUS_DIV_2 + 1 == p == 0 (in\n // the field)\n assert_eq(2 * BN254_FR_MODULUS_DIV_2 + 1, 0);\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/point.nr","function_locations":[{"start":488,"name":"get_sign_of_point"},{"start":1371,"name":"point_from_x_coord"},{"start":2088,"name":"point_from_x_coord_and_sign"},{"start":2697,"name":"test::test_point_from_x_coord_and_sign"},{"start":3524,"name":"test::test_point_from_x_coord_valid"},{"start":3966,"name":"test::test_point_from_x_coord_invalid"},{"start":4228,"name":"test::test_both_roots_satisfy_curve"},{"start":4803,"name":"test::test_point_from_x_coord_and_sign_invalid"},{"start":5214,"name":"test::test_get_sign_of_point"},{"start":6328,"name":"test::test_point_from_x_coord_zero"},{"start":6573,"name":"test::test_bn254_fr_modulus_div_2"}]},"268":{"source":"use std::default::Default;\nuse std::hash::Hasher;\n\nglobal RATE: u32 = 3;\n\npub struct Poseidon2 {\n cache: [Field; 3],\n state: [Field; 4],\n cache_size: u32,\n squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2 {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2::hash_internal(input, message_size)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2 {\n let mut result =\n Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n self.state[0] += self.cache[0];\n self.state[1] += self.cache[1];\n self.state[2] += self.cache[2];\n self.state = crate::poseidon2_permutation(self.state);\n }\n\n fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(input: [Field; N], in_len: u32) -> Field {\n let two_pow_64 = 18446744073709551616;\n let iv: Field = (in_len as Field) * two_pow_64;\n let mut state = [0; 4];\n state[RATE] = iv;\n\n if std::runtime::is_unconstrained() {\n for i in 0..(in_len / RATE) {\n state[0] += input[i * RATE];\n state[1] += input[i * RATE + 1];\n state[2] += input[i * RATE + 2];\n state = crate::poseidon2_permutation(state);\n }\n\n // handle remaining elements after last full RATE-sized chunk\n let num_extra_fields = in_len % RATE;\n if num_extra_fields != 0 {\n let remainder_start = in_len - num_extra_fields;\n state[0] += input[remainder_start];\n if num_extra_fields > 1 {\n state[1] += input[remainder_start + 1];\n }\n }\n } else {\n let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];\n states[0] = state;\n\n // process all full RATE-sized chunks, storing state after each permutation\n for chunk_idx in 0..(N / RATE) {\n for i in 0..RATE {\n state[i] += input[chunk_idx * RATE + i];\n }\n state = crate::poseidon2_permutation(state);\n states[chunk_idx + 1] = state;\n }\n\n // get state at the last full block before in_len\n let first_partially_filled_chunk = in_len / RATE;\n state = states[first_partially_filled_chunk];\n\n // handle remaining elements after last full RATE-sized chunk\n let remainder_start = (in_len / RATE) * RATE;\n for j in 0..RATE {\n let idx = remainder_start + j;\n if idx < in_len {\n state[j] += input[idx];\n }\n }\n }\n\n // always run final permutation unless we just completed a full chunk\n // still need to permute once if in_len is 0\n if (in_len == 0) | (in_len % RATE != 0) {\n state = crate::poseidon2_permutation(state);\n };\n\n state[0]\n }\n}\n\npub struct Poseidon2Hasher {\n _state: [Field],\n}\n\nimpl Hasher for Poseidon2Hasher {\n fn finish(self) -> Field {\n let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)\n let mut sponge = Poseidon2::new(iv);\n for i in 0..self._state.len() {\n sponge.absorb(self._state[i]);\n }\n sponge.squeeze()\n }\n\n fn write(&mut self, input: Field) {\n self._state = self._state.push_back(input);\n }\n}\n\nimpl Default for Poseidon2Hasher {\n fn default() -> Self {\n Poseidon2Hasher { _state: @[] }\n }\n}\n","path":"/Users/maximvezenov/nargo/github.com/noir-lang/poseidon/v0.3.0/src/poseidon2.nr","function_locations":[{"start":333,"name":"Poseidon2::hash"},{"start":442,"name":"Poseidon2::new"},{"start":649,"name":"Poseidon2::perform_duplex"},{"start":923,"name":"Poseidon2::absorb"},{"start":1453,"name":"Poseidon2::squeeze"},{"start":1814,"name":"Poseidon2::hash_internal"},{"start":4105,"name":"::finish"},{"start":4426,"name":"::write"},{"start":4549,"name":"::default"}]},"288":{"source":"use crate::traits::{Deserialize, Empty, FromField, Serialize, ToField};\nuse std::meta::derive;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct FunctionSelector {\n // Low 32 bits of the poseidon2 hash of the function signature.\n pub inner: u32,\n}\n\nimpl FromField for FunctionSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for FunctionSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for FunctionSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl FunctionSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = crate::hash::poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n FunctionSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n\n#[test]\nfn test_is_valid_selector() {\n let selector = FunctionSelector::from_signature(\"IS_VALID()\");\n assert_eq(selector.to_field(), 0x73cdda47);\n}\n\n#[test]\nfn test_long_selector() {\n let selector =\n FunctionSelector::from_signature(\"foo_and_bar_and_baz_and_foo_bar_baz_and_bar_foo\");\n assert_eq(selector.to_field(), 0x7590a997);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr","function_locations":[{"start":333,"name":"::from_field"},{"start":448,"name":"::to_field"},{"start":544,"name":"::empty"},{"start":652,"name":"FunctionSelector::from_u32"},{"start":756,"name":"FunctionSelector::from_signature"},{"start":1006,"name":"FunctionSelector::zero"},{"start":1079,"name":"test_is_valid_selector"},{"start":1231,"name":"test_long_selector"}]},"357":{"source":"mod poseidon2_chunks;\n\nuse crate::{\n abis::{\n contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage,\n function_selector::FunctionSelector, nullifier::Nullifier, private_log::PrivateLog,\n transaction::tx_request::TxRequest,\n },\n address::{AztecAddress, EthAddress},\n constants::{\n CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, DOM_SEP__NOTE_HASH_NONCE,\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__SILOED_NOTE_HASH, DOM_SEP__SILOED_NULLIFIER,\n DOM_SEP__UNIQUE_NOTE_HASH, FUNCTION_TREE_HEIGHT, NULL_MSG_SENDER_CONTRACT_ADDRESS,\n TWO_POW_64,\n },\n merkle_tree::root_from_sibling_path,\n messaging::l2_to_l1_message::L2ToL1Message,\n poseidon2::Poseidon2Sponge,\n side_effect::{Counted, Scoped},\n traits::{FromField, Hash, ToField},\n utils::field::{field_from_bytes, field_from_bytes_32_trunc},\n};\n\npub use poseidon2_chunks::poseidon2_absorb_in_chunks_existing_sponge;\nuse poseidon2_chunks::poseidon2_absorb_in_chunks;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\n// TODO: refactor these into their own files: sha256, poseidon2, some protocol-specific hash computations, some merkle computations.\n\npub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field {\n let sha256_hashed = sha256::digest(bytes_to_hash);\n let hash_in_a_field = field_from_bytes_32_trunc(sha256_hashed);\n\n hash_in_a_field\n}\n\npub fn private_functions_root_from_siblings(\n selector: FunctionSelector,\n vk_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT],\n) -> Field {\n let function_leaf_preimage = ContractClassFunctionLeafPreimage { selector, vk_hash };\n let function_leaf = function_leaf_preimage.hash();\n root_from_sibling_path(\n function_leaf,\n function_leaf_index,\n function_leaf_sibling_path,\n )\n}\n\n/// Siloing in the context of Aztec refers to the process of hashing a note hash with a contract address (this way\n/// the note hash is scoped to a specific contract). This is used to prevent intermingling of notes between contracts.\npub fn compute_siloed_note_hash(contract_address: AztecAddress, note_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), note_hash],\n DOM_SEP__SILOED_NOTE_HASH,\n )\n}\n\n/// Computes unique, siloed note hashes from siloed note hashes.\n///\n/// The protocol injects uniqueness into every note_hash, so that every single note_hash in the\n/// tree is unique. This prevents faerie gold attacks, where a malicious sender could create\n/// two identical note_hashes for a recipient (meaning only one would be nullifiable in future).\n///\n/// Most privacy protocols will inject the note's leaf_index (its position in the Note Hashes Tree)\n/// into the note, but this requires the creator of a note to wait until their tx is included in\n/// a block to know the note's final note hash (the unique, siloed note hash), because inserting\n/// leaves into trees is the job of a block producer.\n///\n/// We took a different approach so that the creator of a note will know each note's unique, siloed\n/// note hash before broadcasting their tx to the network.\n/// (There was also a historical requirement relating to \"chained transactions\" -- a feature that\n/// Aztec Connect had to enable notes to be spent from distinct txs earlier in the same block,\n/// and hence before an archive block root had been established for that block -- but that feature\n/// was abandoned for the Aztec Network for having too many bad tradeoffs).\n///\n/// (\n/// Edit: it is no longer true that all final note_hashes will be known by the creator of a tx\n/// before they send it to the network. If a tx makes public function calls, then _revertible_\n/// note_hashes that are created in private will not be made unique in private by the Reset circuit,\n/// but will instead be made unique by the AVM, because the `note_index_in_tx` will not be known\n/// until the AVM has executed the public functions of the tx. (See an explanation in\n/// reset_output_composer.nr for why).\n/// For some such txs, the `note_index_in_tx` might still be predictable through simulation, but\n/// for txs whose public functions create a varying number of non-revertible notes (determined at\n/// runtime), the `note_index_in_tx` will not be deterministically derivable before submitting the\n/// tx to the network.\n/// )\n///\n/// We use the `first_nullifier` of a tx as a seed of uniqueness. We have a guarantee that there will\n/// always be at least one nullifier per tx, because the init circuit will create one if one isn't\n/// created naturally by any functions of the tx. (Search \"protocol_nullifier\").\n/// We combine the `first_nullifier` with the note's index (its position within this tx's new\n/// note_hashes array) (`note_index_in_tx`) to get a truly unique value to inject into a note, which\n/// we call a `note_nonce`.\npub fn compute_unique_note_hash(note_nonce: Field, siloed_note_hash: Field) -> Field {\n let inputs = [note_nonce, siloed_note_hash];\n poseidon2_hash_with_separator(inputs, DOM_SEP__UNIQUE_NOTE_HASH)\n}\n\npub fn compute_note_hash_nonce(first_nullifier_in_tx: Field, note_index_in_tx: u32) -> Field {\n // Hashing the first nullifier with note index in tx is guaranteed to be unique (because all nullifiers are also\n // unique).\n poseidon2_hash_with_separator(\n [first_nullifier_in_tx, note_index_in_tx as Field],\n DOM_SEP__NOTE_HASH_NONCE,\n )\n}\n\npub fn compute_note_nonce_and_unique_note_hash(\n siloed_note_hash: Field,\n first_nullifier: Field,\n note_index_in_tx: u32,\n) -> Field {\n let note_nonce = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n compute_unique_note_hash(note_nonce, siloed_note_hash)\n}\n\npub fn compute_siloed_nullifier(contract_address: AztecAddress, nullifier: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), nullifier],\n DOM_SEP__SILOED_NULLIFIER,\n )\n}\n\npub fn create_protocol_nullifier(tx_request: TxRequest) -> Scoped> {\n // The protocol nullifier is ascribed a special side-effect counter of 1. No other side-effect\n // can have counter 1 (see `validate_as_first_call` for that assertion).\n Nullifier { value: tx_request.hash(), note_hash: 0 }.count(1).scope(\n NULL_MSG_SENDER_CONTRACT_ADDRESS,\n )\n}\n\npub fn compute_log_tag(raw_tag: Field, dom_sep: u32) -> Field {\n poseidon2_hash_with_separator([raw_tag], dom_sep)\n}\n\npub fn compute_siloed_private_log_first_field(\n contract_address: AztecAddress,\n field: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), field],\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD,\n )\n}\n\npub fn compute_siloed_private_log(contract_address: AztecAddress, log: PrivateLog) -> PrivateLog {\n let mut fields = log.fields;\n fields[0] = compute_siloed_private_log_first_field(contract_address, fields[0]);\n PrivateLog::new(fields, log.length)\n}\n\npub fn compute_contract_class_log_hash(log: [Field; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS]) -> Field {\n poseidon2_hash(log)\n}\n\npub fn compute_app_siloed_secret_key(\n master_secret_key: EmbeddedCurveScalar,\n app_address: AztecAddress,\n key_type_domain_separator: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [master_secret_key.hi, master_secret_key.lo, app_address.to_field()],\n key_type_domain_separator,\n )\n}\n\npub fn compute_l2_to_l1_message_hash(\n message: Scoped,\n rollup_version_id: Field,\n chain_id: Field,\n) -> Field {\n let contract_address_bytes: [u8; 32] = message.contract_address.to_field().to_be_bytes();\n let recipient_bytes: [u8; 20] = message.inner.recipient.to_be_bytes();\n let content_bytes: [u8; 32] = message.inner.content.to_be_bytes();\n let rollup_version_id_bytes: [u8; 32] = rollup_version_id.to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n\n let mut bytes: [u8; 148] = std::mem::zeroed();\n for i in 0..32 {\n bytes[i] = contract_address_bytes[i];\n bytes[i + 32] = rollup_version_id_bytes[i];\n // 64 - 84 are for recipient.\n bytes[i + 84] = chain_id_bytes[i];\n bytes[i + 116] = content_bytes[i];\n }\n\n for i in 0..20 {\n bytes[64 + i] = recipient_bytes[i];\n }\n\n sha256_to_field(bytes)\n}\n\n// TODO: consider a variant that enables domain separation with a u32 (we seem to have standardised u32s for domain separators)\n/// Computes sha256 hash of 2 input fields.\n///\n/// @returns A truncated field (i.e., the first byte is always 0).\npub fn accumulate_sha256(v0: Field, v1: Field) -> Field {\n // Concatenate two fields into 32 x 2 = 64 bytes\n let v0_as_bytes: [u8; 32] = v0.to_be_bytes();\n let v1_as_bytes: [u8; 32] = v1.to_be_bytes();\n let hash_input_flattened = v0_as_bytes.concat(v1_as_bytes);\n\n sha256_to_field(hash_input_flattened)\n}\n\npub fn poseidon2_hash(inputs: [Field; N]) -> Field {\n poseidon::poseidon2::Poseidon2::hash(inputs, N)\n}\n\n#[no_predicates]\npub fn poseidon2_hash_with_separator(inputs: [Field; N], separator: T) -> Field\nwhere\n T: ToField,\n{\n let inputs_with_separator = [separator.to_field()].concat(inputs);\n poseidon2_hash(inputs_with_separator)\n}\n\n/// Computes a Poseidon2 hash over a dynamic-length subarray of the given input.\n/// Only the first `in_len` fields of `input` are absorbed; any remaining fields are ignored.\n/// The caller is responsible for ensuring that the input is padded with zeros if required.\n#[no_predicates]\npub fn poseidon2_hash_subarray(input: [Field; N], in_len: u32) -> Field {\n let mut sponge = poseidon2_absorb_in_chunks(input, in_len);\n sponge.squeeze()\n}\n\n// This function is unconstrained because it is intended to be used in unconstrained context only as\n// in constrained contexts it would be too inefficient.\npub unconstrained fn poseidon2_hash_with_separator_bounded_vec(\n inputs: BoundedVec,\n separator: T,\n) -> Field\nwhere\n T: ToField,\n{\n let in_len = inputs.len() + 1;\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n sponge.absorb(separator.to_field());\n\n for i in 0..inputs.len() {\n sponge.absorb(inputs.get(i));\n }\n\n sponge.squeeze()\n}\n\n#[no_predicates]\npub fn poseidon2_hash_bytes(inputs: [u8; N]) -> Field {\n let mut fields = [0; (N + 30) / 31];\n let mut field_index = 0;\n let mut current_field = [0; 31];\n for i in 0..inputs.len() {\n let index = i % 31;\n current_field[index] = inputs[i];\n if index == 30 {\n fields[field_index] = field_from_bytes(current_field, false);\n current_field = [0; 31];\n field_index += 1;\n }\n }\n if field_index != fields.len() {\n fields[field_index] = field_from_bytes(current_field, false);\n }\n poseidon2_hash(fields)\n}\n\n#[test]\nfn subarray_hash_matches_fixed() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash the entire values_to_hash.\n let fixed_len_hash = poseidon::poseidon2::Poseidon2::hash(values_to_hash, values_to_hash.len());\n\n assert_eq(subarray_hash, fixed_len_hash);\n}\n\n#[test]\nfn subarray_hash_matches_variable() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash up to values_to_hash.len() fields of the padded array.\n let variable_len_hash = poseidon::poseidon2::Poseidon2::hash(padded, values_to_hash.len());\n\n assert_eq(subarray_hash, variable_len_hash);\n}\n\n#[test]\nfn smoke_sha256_to_field() {\n let full_buffer = [\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\n 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,\n 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,\n 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,\n 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,\n 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,\n 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\n ];\n let result = sha256_to_field(full_buffer);\n\n assert(result == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184c7);\n\n // to show correctness of the current ver (truncate one byte) vs old ver (mod full bytes):\n let result_bytes = sha256::digest(full_buffer);\n let truncated_field = crate::utils::field::field_from_bytes_32_trunc(result_bytes);\n assert(truncated_field == result);\n let mod_res = result + (result_bytes[31] as Field);\n assert(mod_res == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184e0);\n}\n\n#[test]\nfn unique_siloed_note_hash_matches_typescript() {\n let inner_note_hash = 1;\n let contract_address = AztecAddress::from_field(2);\n let first_nullifier = 3;\n let note_index_in_tx = 4;\n\n let siloed_note_hash = compute_siloed_note_hash(contract_address, inner_note_hash);\n let siloed_note_hash_from_ts =\n 0x1986a4bea3eddb1fff917d629a13e10f63f514f401bdd61838c6b475db949169;\n assert_eq(siloed_note_hash, siloed_note_hash_from_ts);\n\n let nonce: Field = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n let note_hash_nonce_from_ts =\n 0x28e7799791bf066a57bb51fdd0fbcaf3f0926414314c7db515ea343f44f5d58b;\n assert_eq(nonce, note_hash_nonce_from_ts);\n\n let unique_siloed_note_hash_from_nonce = compute_unique_note_hash(nonce, siloed_note_hash);\n let unique_siloed_note_hash = compute_note_nonce_and_unique_note_hash(\n siloed_note_hash,\n first_nullifier,\n note_index_in_tx,\n );\n assert_eq(unique_siloed_note_hash_from_nonce, unique_siloed_note_hash);\n\n let unique_siloed_note_hash_from_ts =\n 0x29949aef207b715303b24639737c17fbfeb375c1d965ecfa85c7e4f0febb7d16;\n assert_eq(unique_siloed_note_hash, unique_siloed_note_hash_from_ts);\n}\n\n#[test]\nfn siloed_nullifier_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let nullifier = 456;\n\n let res = compute_siloed_nullifier(contract_address, nullifier);\n\n let siloed_nullifier_from_ts =\n 0x169b50336c1f29afdb8a03d955a81e485f5ac7d5f0b8065673d1e407e5877813;\n\n assert_eq(res, siloed_nullifier_from_ts);\n}\n\n#[test]\nfn siloed_private_log_first_field_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let field = 456;\n let res = compute_siloed_private_log_first_field(contract_address, field);\n\n let siloed_private_log_first_field_from_ts =\n 0x29480984f7b9257fded523d50addbcfc8d1d33adcf2db73ef3390a8fd5cdffaa;\n\n assert_eq(res, siloed_private_log_first_field_from_ts);\n}\n\n#[test]\nfn empty_l2_to_l1_message_hash_matches_typescript() {\n // All zeroes\n let res = compute_l2_to_l1_message_hash(\n L2ToL1Message { recipient: EthAddress::zero(), content: 0 }.scope(AztecAddress::from_field(\n 0,\n )),\n 0,\n 0,\n );\n\n let empty_l2_to_l1_msg_hash_from_ts =\n 0x003b18c58c739716e76429634a61375c45b3b5cd470c22ab6d3e14cee23dd992;\n\n assert_eq(res, empty_l2_to_l1_msg_hash_from_ts);\n}\n\n#[test]\nfn l2_to_l1_message_hash_matches_typescript() {\n let message = L2ToL1Message { recipient: EthAddress::from_field(1), content: 2 }.scope(\n AztecAddress::from_field(3),\n );\n let version = 4;\n let chainId = 5;\n\n let hash = compute_l2_to_l1_message_hash(message, version, chainId);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let l2_to_l1_message_hash_from_ts =\n 0x0081edf209e087ad31b3fd24263698723d57190bd1d6e9fe056fc0c0a68ee661;\n\n assert_eq(hash, l2_to_l1_message_hash_from_ts);\n}\n\n#[test]\nunconstrained fn poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version() {\n let inputs = BoundedVec::::from_array([1, 2, 3]);\n let separator = 42;\n\n // Hash using bounded vec version\n let bounded_result = poseidon2_hash_with_separator_bounded_vec(inputs, separator);\n\n // Hash using regular version\n let regular_result = poseidon2_hash_with_separator([1, 2, 3], separator);\n\n // Results should match\n assert_eq(bounded_result, regular_result);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr","function_locations":[{"start":1253,"name":"sha256_to_field"},{"start":1605,"name":"private_functions_root_from_siblings"},{"start":2202,"name":"compute_siloed_note_hash"},{"start":5031,"name":"compute_unique_note_hash"},{"start":5247,"name":"compute_note_hash_nonce"},{"start":5663,"name":"compute_note_nonce_and_unique_note_hash"},{"start":5899,"name":"compute_siloed_nullifier"},{"start":6116,"name":"create_protocol_nullifier"},{"start":6480,"name":"compute_log_tag"},{"start":6651,"name":"compute_siloed_private_log_first_field"},{"start":6882,"name":"compute_siloed_private_log"},{"start":7142,"name":"compute_contract_class_log_hash"},{"start":7333,"name":"compute_app_siloed_secret_key"},{"start":7628,"name":"compute_l2_to_l1_message_hash"},{"start":8709,"name":"accumulate_sha256"},{"start":9037,"name":"poseidon2_hash"},{"start":9228,"name":"poseidon2_hash_with_separator"},{"start":9714,"name":"poseidon2_hash_subarray"},{"start":10126,"name":"poseidon2_hash_with_separator_bounded_vec"},{"start":10487,"name":"poseidon2_hash_bytes"},{"start":11063,"name":"subarray_hash_matches_fixed"},{"start":11462,"name":"subarray_hash_matches_variable"},{"start":11878,"name":"smoke_sha256_to_field"},{"start":13280,"name":"unique_siloed_note_hash_matches_typescript"},{"start":14502,"name":"siloed_nullifier_matches_typescript"},{"start":14882,"name":"siloed_private_log_first_field_matches_typescript"},{"start":15292,"name":"empty_l2_to_l1_message_hash_matches_typescript"},{"start":15743,"name":"l2_to_l1_message_hash_matches_typescript"},{"start":16359,"name":"poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version"}]},"359":{"source":"// Log levels matching the JS logger:\n\n// global SILENT_LOG_LEVEL: u8 = 0;\nglobal FATAL_LOG_LEVEL: u8 = 1;\nglobal ERROR_LOG_LEVEL: u8 = 2;\nglobal WARN_LOG_LEVEL: u8 = 3;\nglobal INFO_LOG_LEVEL: u8 = 4;\nglobal VERBOSE_LOG_LEVEL: u8 = 5;\nglobal DEBUG_LOG_LEVEL: u8 = 6;\nglobal TRACE_LOG_LEVEL: u8 = 7;\n\n// --- Per-level log functions (no format args) ---\n\npub fn fatal_log(msg: str) {\n fatal_log_format(msg, []);\n}\n\npub fn error_log(msg: str) {\n error_log_format(msg, []);\n}\n\npub fn warn_log(msg: str) {\n warn_log_format(msg, []);\n}\n\npub fn info_log(msg: str) {\n info_log_format(msg, []);\n}\n\npub fn verbose_log(msg: str) {\n verbose_log_format(msg, []);\n}\n\npub fn debug_log(msg: str) {\n debug_log_format(msg, []);\n}\n\npub fn trace_log(msg: str) {\n trace_log_format(msg, []);\n}\n\n// --- Per-level log functions (with format args) ---\n\npub fn fatal_log_format(msg: str, args: [Field; N]) {\n log_format(FATAL_LOG_LEVEL, msg, args);\n}\n\npub fn error_log_format(msg: str, args: [Field; N]) {\n log_format(ERROR_LOG_LEVEL, msg, args);\n}\n\npub fn warn_log_format(msg: str, args: [Field; N]) {\n log_format(WARN_LOG_LEVEL, msg, args);\n}\n\npub fn info_log_format(msg: str, args: [Field; N]) {\n log_format(INFO_LOG_LEVEL, msg, args);\n}\n\npub fn verbose_log_format(msg: str, args: [Field; N]) {\n log_format(VERBOSE_LOG_LEVEL, msg, args);\n}\n\npub fn debug_log_format(msg: str, args: [Field; N]) {\n log_format(DEBUG_LOG_LEVEL, msg, args);\n}\n\npub fn trace_log_format(msg: str, args: [Field; N]) {\n log_format(TRACE_LOG_LEVEL, msg, args);\n}\n\nfn log_format(log_level: u8, msg: str, args: [Field; N]) {\n // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe\n // to call.\n unsafe { log_oracle_wrapper(log_level, msg, args) };\n}\n\nunconstrained fn log_oracle_wrapper(\n log_level: u8,\n msg: str,\n args: [Field; N],\n) {\n log_oracle(log_level, msg, N, args);\n}\n\n// While the length parameter might seem unnecessary given that we have N, we keep it around because at the AVM\n// bytecode level we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally\n// take that route. The AVM transpiler maps this oracle to the DEBUGLOG opcode, which reads the fields size from memory.\n#[oracle(aztec_utl_log)]\nunconstrained fn log_oracle(\n log_level: u8,\n msg: str,\n length: u32,\n args: [Field; N],\n) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/logging.nr","function_locations":[{"start":395,"name":"fatal_log"},{"start":473,"name":"error_log"},{"start":550,"name":"warn_log"},{"start":626,"name":"info_log"},{"start":705,"name":"verbose_log"},{"start":785,"name":"debug_log"},{"start":863,"name":"trace_log"},{"start":1033,"name":"fatal_log_format"},{"start":1161,"name":"error_log_format"},{"start":1288,"name":"warn_log_format"},{"start":1414,"name":"info_log_format"},{"start":1543,"name":"verbose_log_format"},{"start":1673,"name":"debug_log_format"},{"start":1801,"name":"trace_log_format"},{"start":1934,"name":"log_format"},{"start":2248,"name":"log_oracle_wrapper"},{"start":2801,"name":"log_oracle"}]},"378":{"source":"use crate::constants::TWO_POW_64;\nuse crate::traits::{Deserialize, Serialize};\nuse std::meta::derive;\n// NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr\n// It exists as we sometimes need to perform custom absorption, but the stdlib version\n// has a private absorb() method (it's also designed to just be a hasher)\n// Can be removed when standalone noir poseidon lib exists: See noir#6679\n// TODO: Poseidon is stand-alone now\n\nglobal RATE: u32 = 3;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct Poseidon2Sponge {\n pub cache: [Field; 3],\n pub state: [Field; 4],\n pub cache_size: u32,\n pub squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2Sponge {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2Sponge::hash_internal(input, message_size, message_size != N)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2Sponge {\n let mut result =\n Poseidon2Sponge { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n for i in 0..RATE {\n // We effectively zero-pad the cache by only adding to the state\n // cache that is less than the specified `cache_size`\n if i < self.cache_size {\n self.state[i] += self.cache[i];\n }\n }\n self.state = std::hash::poseidon2_permutation(self.state);\n }\n\n pub fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n pub fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(\n input: [Field; N],\n in_len: u32,\n is_variable_length: bool,\n ) -> Field {\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n for i in 0..input.len() {\n if i < in_len {\n sponge.absorb(input[i]);\n }\n }\n\n sponge.squeeze()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr","function_locations":[{"start":798,"name":"Poseidon2Sponge::hash"},{"start":938,"name":"Poseidon2Sponge::new"},{"start":1151,"name":"Poseidon2Sponge::perform_duplex"},{"start":1592,"name":"Poseidon2Sponge::absorb"},{"start":2126,"name":"Poseidon2Sponge::squeeze"},{"start":2544,"name":"Poseidon2Sponge::hash_internal"}]},"397":{"source":"use crate::utils::field::field_from_bytes;\n\npub trait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n #[inline_always]\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for bool {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u8 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u16 {\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u32 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u64 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u128 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for str {\n #[inline_always]\n fn to_field(self) -> Field {\n assert(N < 32, \"String doesn't fit in a field, consider using Serialize instead\");\n field_from_bytes(self.as_bytes(), true)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/traits/to_field.nr","function_locations":[{"start":176,"name":"::to_field"},{"start":276,"name":"::to_field"},{"start":382,"name":"::to_field"},{"start":468,"name":"::to_field"},{"start":575,"name":"::to_field"},{"start":682,"name":"::to_field"},{"start":790,"name":"::to_field"},{"start":912,"name":">::to_field"}]},"405":{"source":"pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n\n// Convert a 32 byte array to a field element by truncating the final byte\npub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..15 {\n // covers bytes 16..30 (31 is truncated and ignored)\n low = low + (bytes32[15 + 15 - i] as Field) * v;\n v = v * 256;\n // covers bytes 0..14\n high = high + (bytes32[14 - i] as Field) * v;\n }\n // covers byte 15\n low = low + (bytes32[15] as Field) * v;\n\n low + high * v\n}\n\npub fn min(f1: Field, f2: Field) -> Field {\n if f1.lt(f2) {\n f1\n } else {\n f2\n }\n}\n\n// TODO: write doc-comments and tests for these magic constants.\n\nglobal KNOWN_NON_RESIDUE: Field = 5; // This is a non-residue in Noir's native Field.\nglobal C1: u32 = 28;\nglobal C3: Field = 40770029410420498293352137776570907027550720424234931066070132305055;\nglobal C5: Field = 19103219067921713944291392827692070036145651957329286315305642004821462161904;\n\n// @dev: only use this for _huge_ exponents y, when writing a constrained function.\n// If you're only exponentiating by a small value, first consider writing-out the multiplications by hand.\n// Only after you've measured the gates of that approach, consider using the native Field::pow_32 function.\n// Only if your exponent is larger than 32 bits, resort to using this function.\npub fn pow(x: Field, y: Field) -> Field {\n let mut r = 1 as Field;\n let b: [bool; 254] = y.to_le_bits();\n\n for i in 0..254 {\n r *= r;\n r *= (b[254 - 1 - i] as Field) * x + (1 - b[254 - 1 - i] as Field);\n }\n\n r\n}\n\n/// Returns Option::some(sqrt) if there is a square root, and Option::none() if there isn't.\npub fn sqrt(x: Field) -> Option {\n // Safety: if the hint returns the square root of x, then we simply square it\n // check the result equals x. If x is not square, we return a value that\n // enables us to prove that fact (see the `else` clause below).\n let (is_sq, maybe_sqrt) = unsafe { __sqrt(x) };\n\n if is_sq {\n let sqrt = maybe_sqrt;\n validate_sqrt_hint(x, sqrt);\n Option::some(sqrt)\n } else {\n let not_sqrt_hint = maybe_sqrt;\n validate_not_sqrt_hint(x, not_sqrt_hint);\n Option::none()\n }\n}\n\n// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.\nunconstrained fn is_square(x: Field) -> bool {\n let v = pow(x, -1 / 2);\n v * (v - 1) == 0\n}\n\n// Tonelli-Shanks algorithm for computing the square root of a Field element.\n// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field\n// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),\n// and C5 = ZETA^C2, where ZETA is a non-square element of Field.\n// These are pre-computed above as globals.\nunconstrained fn tonelli_shanks_sqrt(x: Field) -> Field {\n let mut z = pow(x, C3);\n let mut t = z * z * x;\n z *= x;\n let mut b = t;\n let mut c = C5;\n\n for i in 0..(C1 - 1) {\n for _j in 1..(C1 - i - 1) {\n b *= b;\n }\n\n z *= if b == 1 { 1 } else { c };\n\n c *= c;\n\n t *= if b == 1 { 1 } else { c };\n\n b = t;\n }\n\n z\n}\n\n// NB: this doesn't return an option, because in the case of there _not_ being a square root, we still want to return a field element that allows us to then assert in the _constrained_ sqrt function that there is no sqrt.\nunconstrained fn __sqrt(x: Field) -> (bool, Field) {\n let is_sq = is_square(x);\n if is_sq {\n let sqrt = tonelli_shanks_sqrt(x);\n (true, sqrt)\n } else {\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // sq * sq = sq // 1 * 1 = 1\n // non-sq * non-sq = sq // -1 * -1 = 1\n // sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n let not_sqrt = tonelli_shanks_sqrt(demo_x_not_square);\n (false, not_sqrt)\n }\n}\n\nfn validate_sqrt_hint(x: Field, hint: Field) {\n assert(hint * hint == x, f\"The claimed_sqrt {hint} is not the sqrt of x {x}\");\n}\n\nfn validate_not_sqrt_hint(x: Field, hint: Field) {\n // We need this assertion, because x = 0 would pass the other assertions in this\n // function, and we don't want people to be able to prove that 0 is not square!\n assert(x != 0, \"0 has a square root; you cannot claim it is not square\");\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n //\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // 1. sq * sq = sq // 1 * 1 = 1\n // 2. non-sq * non-sq = sq // -1 * -1 = 1\n // 3. sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n //\n // We want to demonstrate that this below multiplication falls under bullet-point (2):\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n // I.e. we want to demonstrate that `demo_x_not_square` has Legendre symbol 1\n // (i.e. that it is a square), so we prove that it is square below.\n // Why do we want to prove that it has LS 1?\n // Well, since it was computed with a known-non-residue, its squareness implies we're\n // in case 2 (something multiplied by a known-non-residue yielding a result which\n // has a LS of 1), which implies that x must be a non-square. The unconstrained\n // function gave us the sqrt of demo_x_not_square, so all we need to do is\n // assert its squareness:\n assert(\n hint * hint == demo_x_not_square,\n f\"The hint {hint} does not demonstrate that {x} is not a square\",\n );\n}\n\n#[test]\nunconstrained fn bytes_field_test() {\n // Tests correctness of field_from_bytes_32_trunc against existing methods\n // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7\n let inputs = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167,\n ];\n let field = field_from_bytes(inputs, true);\n let return_bytes: [u8; 31] = field.to_be_bytes();\n assert_eq(inputs, return_bytes);\n // 32 bytes - we remove the final byte, and check it matches the field\n let inputs2 = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158,\n ];\n let field2 = field_from_bytes_32_trunc(inputs2);\n let return_bytes2: [u8; 31] = field2.to_be_bytes();\n\n assert_eq(return_bytes2, return_bytes);\n assert_eq(field2, field);\n}\n\n#[test]\nunconstrained fn max_field_test() {\n // Tests the hardcoded value in constants.nr vs underlying modulus\n // NB: We can't use 0-1 in constants.nr as it will be transpiled incorrectly to ts and sol constants files\n let max_value = crate::constants::MAX_FIELD_VALUE;\n assert_eq(max_value, 0 - 1);\n // modulus == 0 is tested elsewhere, so below is more of a sanity check\n let max_bytes: [u8; 32] = max_value.to_be_bytes();\n let mod_bytes = std::field::modulus_be_bytes();\n for i in 0..31 {\n assert_eq(max_bytes[i], mod_bytes[i]);\n }\n assert_eq(max_bytes[31], mod_bytes[31] - 1);\n}\n\n#[test]\nunconstrained fn sqrt_valid_test() {\n let x = 16; // examples: 16, 9, 25, 81\n let result = sqrt(x);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), x);\n}\n\n#[test]\nunconstrained fn sqrt_invalid_test() {\n let x = KNOWN_NON_RESIDUE; // has no square root in the field\n let result = sqrt(x);\n assert(result.is_none());\n}\n\n#[test]\nunconstrained fn sqrt_zero_test() {\n let result = sqrt(0);\n assert(result.is_some());\n assert_eq(result.unwrap(), 0);\n}\n\n#[test]\nunconstrained fn sqrt_one_test() {\n let result = sqrt(1);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), 1);\n}\n\n#[test]\nunconstrained fn field_from_bytes_empty_test() {\n let empty: [u8; 0] = [];\n let result = field_from_bytes(empty, true);\n assert_eq(result, 0);\n\n let result_le = field_from_bytes(empty, false);\n assert_eq(result_le, 0);\n}\n\n#[test]\nunconstrained fn field_from_bytes_little_endian_test() {\n // Test little-endian conversion: [0x01, 0x02] should be 0x0201 = 513\n let bytes = [0x01, 0x02];\n let result_le = field_from_bytes(bytes, false);\n assert_eq(result_le, 0x0201);\n\n // Compare with big-endian: [0x01, 0x02] should be 0x0102 = 258\n let result_be = field_from_bytes(bytes, true);\n assert_eq(result_be, 0x0102);\n}\n\n#[test]\nunconstrained fn pow_test() {\n assert_eq(pow(2, 0), 1);\n assert_eq(pow(2, 1), 2);\n assert_eq(pow(2, 10), 1024);\n assert_eq(pow(3, 5), 243);\n assert_eq(pow(0, 5), 0);\n assert_eq(pow(1, 100), 1);\n}\n\n#[test]\nunconstrained fn min_test() {\n assert_eq(min(5, 10), 5);\n assert_eq(min(10, 5), 5);\n assert_eq(min(7, 7), 7);\n assert_eq(min(0, 1), 0);\n}\n\n#[test]\nunconstrained fn sqrt_has_two_roots_test() {\n // Every square has two roots: r and -r (i.e., p - r)\n // sqrt(16) can return 4 or -4\n let x = 16;\n let result = sqrt(x).unwrap();\n assert(result * result == x);\n // The other root is -result\n let other_root = 0 - result;\n assert(other_root * other_root == x);\n // Verify they are different (unless x = 0)\n assert(result != other_root);\n\n // Same for 9: roots are 3 and -3\n let y = 9;\n let result_y = sqrt(y).unwrap();\n assert(result_y * result_y == y);\n let other_root_y = 0 - result_y;\n assert(other_root_y * other_root_y == y);\n assert(result_y != other_root_y);\n}\n\n#[test]\nunconstrained fn sqrt_negative_one_test() {\n let x = 0 - 1;\n let result = sqrt(x);\n assert(result.unwrap() == 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636);\n}\n\n#[test]\nunconstrained fn validate_sqrt_hint_valid_test() {\n // 4 is a valid sqrt of 16\n validate_sqrt_hint(16, 4);\n // -4 is also a valid sqrt of 16\n validate_sqrt_hint(16, 0 - 4);\n // 0 is a valid sqrt of 0\n validate_sqrt_hint(0, 0);\n // 1 is a valid sqrt of 1\n validate_sqrt_hint(1, 1);\n // -1 is also a valid sqrt of 1\n validate_sqrt_hint(1, 0 - 1);\n}\n\n#[test(should_fail_with = \"is not the sqrt of x\")]\nunconstrained fn validate_sqrt_hint_invalid_test() {\n // 5 is not a valid sqrt of 16\n validate_sqrt_hint(16, 5);\n}\n\n#[test]\nunconstrained fn validate_not_sqrt_hint_valid_test() {\n // 5 (KNOWN_NON_RESIDUE) is not a square.\n let x = KNOWN_NON_RESIDUE;\n let hint = tonelli_shanks_sqrt(x * KNOWN_NON_RESIDUE);\n validate_not_sqrt_hint(x, hint);\n}\n\n#[test(should_fail_with = \"0 has a square root\")]\nunconstrained fn validate_not_sqrt_hint_zero_test() {\n // 0 has a square root, so we cannot claim it is not square\n validate_not_sqrt_hint(0, 0);\n}\n\n#[test(should_fail_with = \"does not demonstrate that\")]\nunconstrained fn validate_not_sqrt_hint_wrong_hint_test() {\n // Provide a wrong hint for a non-square\n let x = KNOWN_NON_RESIDUE;\n validate_not_sqrt_hint(x, 123);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr","function_locations":[{"start":79,"name":"field_from_bytes"},{"start":553,"name":"field_from_bytes_32_trunc"},{"start":1054,"name":"min"},{"start":1899,"name":"pow"},{"start":2233,"name":"sqrt"},{"start":2915,"name":"is_square"},{"start":3343,"name":"tonelli_shanks_sqrt"},{"start":3951,"name":"__sqrt"},{"start":4795,"name":"validate_sqrt_hint"},{"start":4932,"name":"validate_not_sqrt_hint"},{"start":6570,"name":"bytes_field_test"},{"start":7553,"name":"max_field_test"},{"start":8177,"name":"sqrt_valid_test"},{"start":8379,"name":"sqrt_invalid_test"},{"start":8548,"name":"sqrt_zero_test"},{"start":8685,"name":"sqrt_one_test"},{"start":8854,"name":"field_from_bytes_empty_test"},{"start":9107,"name":"field_from_bytes_little_endian_test"},{"start":9492,"name":"pow_test"},{"start":9715,"name":"min_test"},{"start":9889,"name":"sqrt_has_two_roots_test"},{"start":10562,"name":"sqrt_negative_one_test"},{"start":10768,"name":"validate_sqrt_hint_valid_test"},{"start":11199,"name":"validate_sqrt_hint_invalid_test"},{"start":11331,"name":"validate_not_sqrt_hint_valid_test"},{"start":11611,"name":"validate_not_sqrt_hint_zero_test"},{"start":11828,"name":"validate_not_sqrt_hint_wrong_hint_test"}]},"411":{"source":"pub struct Reader {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Reader {\n pub fn new(data: [Field; N]) -> Self {\n Self { data, offset: 0 }\n }\n\n pub fn read(&mut self) -> Field {\n let result = self.data[self.offset];\n self.offset += 1;\n result\n }\n\n pub fn read_u32(&mut self) -> u32 {\n self.read() as u32\n }\n\n pub fn read_u64(&mut self) -> u64 {\n self.read() as u64\n }\n\n pub fn read_bool(&mut self) -> bool {\n self.read() != 0\n }\n\n pub fn read_array(&mut self) -> [Field; K] {\n let mut result = [0; K];\n for i in 0..K {\n result[i] = self.data[self.offset + i];\n }\n self.offset += K;\n result\n }\n\n pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T {\n let result = deserialise(self.read_array());\n result\n }\n\n pub fn read_struct_array(\n &mut self,\n deserialise: fn([Field; K]) -> T,\n mut result: [T; C],\n ) -> [T; C] {\n for i in 0..C {\n result[i] = self.read_struct(deserialise);\n }\n result\n }\n\n pub fn peek_offset(&mut self, offset: u32) -> Field {\n self.data[self.offset + offset]\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) {\n assert_eq(self.offset, self.data.len(), \"Reader did not read all data\");\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/reader.nr","function_locations":[{"start":144,"name":"Reader::new"},{"start":222,"name":"Reader::read"},{"start":355,"name":"Reader::read_u32"},{"start":429,"name":"Reader::read_u64"},{"start":505,"name":"Reader::read_bool"},{"start":598,"name":"Reader::read_array"},{"start":855,"name":"Reader::read_struct"},{"start":1094,"name":"Reader::read_struct_array"},{"start":1263,"name":"Reader::peek_offset"},{"start":1362,"name":"Reader::advance_offset"},{"start":1426,"name":"Reader::finish"}]},"412":{"source":"use crate::{reader::Reader, writer::Writer};\n\n/// Trait for serializing Noir types into arrays of Fields.\n///\n/// An implementation of the Serialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait (and Deserialize) are\n/// typically used to communicate between Noir and TypeScript (via oracles and function arguments).\n///\n/// # On Following Noir's Intrinsic Serialization\n/// When calling a Noir function from TypeScript (TS), first the function arguments are serialized into an array\n/// of fields. This array is then included in the initial witness. Noir's intrinsic serialization is then used\n/// to deserialize the arguments from the witness. When the same Noir function is called from Noir this Serialize trait\n/// is used instead of the serialization in TS. For this reason we need to have a match between TS serialization,\n/// Noir's intrinsic serialization and the implementation of this trait. If there is a mismatch, the function calls\n/// fail with an arguments hash mismatch error message.\n///\n/// # Associated Constants\n/// * `N` - The length of the output Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Serialize for str {\n/// let N: u32 = N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// let bytes = self.as_bytes();\n/// for i in 0..bytes.len() {\n/// writer.write(bytes[i] as Field);\n/// }\n/// }\n/// }\n/// ```\n#[derive_via(derive_serialize)]\npub trait Serialize {\n let N: u32;\n\n fn serialize(self) -> [Field; Self::N];\n\n fn stream_serialize(self, writer: &mut Writer);\n}\n\n/// Generates a `Serialize` trait implementation for a struct type.\n///\n/// # Parameters\n/// - `s`: The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A quoted code block containing the trait implementation\n///\n/// # Example\n/// For a struct defined as:\n/// ```\n/// struct Log {\n/// fields: [Field; N],\n/// length: u32\n/// }\n/// ```\n///\n/// This function generates code equivalent to:\n/// ```\n/// impl Serialize for Log {\n/// let N: u32 = <[Field; N] as Serialize>::N + ::N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// #[inline_always]\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// Serialize::stream_serialize(self.fields, writer);\n/// Serialize::stream_serialize(self.length, writer);\n/// }\n/// }\n/// ```\npub comptime fn derive_serialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n\n // We care only about the name and type so we drop the last item of the tuple\n let params = nested_struct.0.fields(nested_struct.1).map(|(name, typ, _)| (name, typ));\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Serialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_serialize_clause = get_where_trait_clause(s, quote {Serialize});\n\n let params_len_quote = get_params_len_quote(params);\n\n let function_body = params\n .map(|(name, _typ): (Quoted, Type)| {\n quote {\n $crate::serialization::Serialize::stream_serialize(self.$name, writer);\n }\n })\n .join(quote {});\n\n quote {\n impl$generics_declarations $crate::serialization::Serialize for $typ\n $where_serialize_clause\n {\n let N: u32 = $params_len_quote;\n\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n $crate::serialization::Serialize::stream_serialize(self, &mut writer);\n writer.finish()\n }\n\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n $function_body\n }\n }\n }\n}\n\n/// Trait for deserializing Noir types from arrays of Fields.\n///\n/// An implementation of the Deserialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait is typically used when\n/// deserializing return values from function calls in Noir. Since the same function could be called from TypeScript\n/// (TS), in which case the TS deserialization would get used, we need to have a match between the 2.\n///\n/// # Associated Constants\n/// * `N` - The length of the input Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Deserialize for str {\n/// let N: u32 = M;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let mut bytes = [0 as u8; M];\n/// for i in 0..M {\n/// bytes[i] = reader.read() as u8;\n/// }\n/// str::::from(bytes)\n/// }\n/// }\n/// ```\n#[derive_via(derive_deserialize)]\npub trait Deserialize {\n let N: u32;\n\n fn deserialize(fields: [Field; Self::N]) -> Self;\n\n fn stream_deserialize(reader: &mut Reader) -> Self;\n}\n\n/// Generates a `Deserialize` trait implementation for a given struct `s`.\n///\n/// # Arguments\n/// * `s` - The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A `Quoted` block containing the generated trait implementation\n///\n/// # Requirements\n/// Each struct member type must implement the `Deserialize` trait (it gets used in the generated code).\n///\n/// # Example\n/// For a struct like:\n/// ```\n/// struct MyStruct {\n/// x: AztecAddress,\n/// y: Field,\n/// }\n/// ```\n///\n/// This generates:\n/// ```\n/// impl Deserialize for MyStruct {\n/// let N: u32 = ::N + ::N;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// #[inline_always]\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let x = ::stream_deserialize(reader);\n/// let y = ::stream_deserialize(reader);\n/// Self { x, y }\n/// }\n/// }\n/// ```\npub comptime fn derive_deserialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n let params = nested_struct.0.fields(nested_struct.1);\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Deserialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_deserialize_clause = get_where_trait_clause(s, quote {Deserialize});\n\n // The following will give us:\n // ::N + ::N + ...\n // (or 0 if the struct has no members)\n let right_hand_side_of_definition_of_n = if params.len() > 0 {\n params\n .map(|(_, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n <$param_type as $crate::serialization::Deserialize>::N\n }\n })\n .join(quote {+})\n } else {\n quote {0}\n };\n\n // For structs containing a single member, we can enhance performance by directly deserializing the input array,\n // bypassing the need for loop-based array construction. While this optimization yields significant benefits in\n // Brillig where the loops are expected to not be optimized, it is not relevant in ACIR where the loops are\n // expected to be optimized away.\n let function_body = if params.len() > 1 {\n // This generates deserialization code for each struct member and concatenates them together.\n let deserialization_of_struct_members = params\n .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n let $param_name = <$param_type as Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote {});\n\n // We join the struct member names with a comma to be used in the `Self { ... }` syntax\n // This will give us e.g. `a, b, c` for a struct with three fields named `a`, `b`, and `c`.\n let struct_members = params\n .map(|(param_name, _, _): (Quoted, Type, Quoted)| quote { $param_name })\n .join(quote {,});\n\n quote {\n $deserialization_of_struct_members\n\n Self { $struct_members }\n }\n } else if params.len() == 1 {\n let param_name = params[0].0;\n quote {\n Self { $param_name: $crate::serialization::Deserialize::stream_deserialize(reader) }\n }\n } else {\n quote {\n Self {}\n }\n };\n\n quote {\n impl$generics_declarations $crate::serialization::Deserialize for $typ\n $where_deserialize_clause\n {\n let N: u32 = $right_hand_side_of_definition_of_n;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $function_body\n }\n }\n }\n}\n\n/// Generates a quoted expression that computes the total serialized length of function parameters.\n///\n/// # Parameters\n/// * `params` - An array of tuples where each tuple contains a quoted parameter name and its Type. The type needs\n/// to implement the Serialize trait.\n///\n/// # Returns\n/// A quoted expression that evaluates to:\n/// * `0` if there are no parameters\n/// * `(::N + ::N + ...)` for one or more parameters\ncomptime fn get_params_len_quote(params: [(Quoted, Type)]) -> Quoted {\n if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::serialization::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n }\n}\n\ncomptime fn get_generics_declarations(s: TypeDefinition) -> Quoted {\n let generics = s.generics();\n\n if generics.len() > 0 {\n let generics_declarations_items = generics\n .map(|(name, maybe_integer_typ)| {\n // The second item in the generics tuple is an Option of an integer type that is Some only if\n // the generic is numeric.\n if maybe_integer_typ.is_some() {\n // The generic is numeric, so we return a quote defined as e.g. \"let N: u32\"\n let integer_type = maybe_integer_typ.unwrap();\n quote {let $name: $integer_type}\n } else {\n // The generic is not numeric, so we return a quote containing the name of the generic (e.g. \"T\")\n quote {$name}\n }\n })\n .join(quote {,});\n quote {<$generics_declarations_items>}\n } else {\n // The struct doesn't have any generics defined, so we just return an empty quote.\n quote {}\n }\n}\n\ncomptime fn get_where_trait_clause(s: TypeDefinition, trait_name: Quoted) -> Quoted {\n let generics = s.generics();\n\n // The second item in the generics tuple is an Option of an integer type that is Some only if the generic is\n // numeric.\n let non_numeric_generics =\n generics.filter(|(_, maybe_integer_typ)| maybe_integer_typ.is_none());\n\n if non_numeric_generics.len() > 0 {\n let non_numeric_generics_declarations =\n non_numeric_generics.map(|(name, _)| quote {$name: $trait_name}).join(quote {,});\n quote {where $non_numeric_generics_declarations}\n } else {\n // There are no non-numeric generics, so we return an empty quote.\n quote {}\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/serialization.nr","function_locations":[{"start":3018,"name":"derive_serialize"},{"start":7206,"name":"derive_deserialize"},{"start":10928,"name":"get_params_len_quote"},{"start":11387,"name":"get_generics_declarations"},{"start":12469,"name":"get_where_trait_clause"}]},"414":{"source":"use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};\nuse std::embedded_curve_ops::EmbeddedCurvePoint;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\nglobal BOOL_SERIALIZED_LEN: u32 = 1;\nglobal U8_SERIALIZED_LEN: u32 = 1;\nglobal U16_SERIALIZED_LEN: u32 = 1;\nglobal U32_SERIALIZED_LEN: u32 = 1;\nglobal U64_SERIALIZED_LEN: u32 = 1;\nglobal U128_SERIALIZED_LEN: u32 = 1;\nglobal FIELD_SERIALIZED_LEN: u32 = 1;\nglobal I8_SERIALIZED_LEN: u32 = 1;\nglobal I16_SERIALIZED_LEN: u32 = 1;\nglobal I32_SERIALIZED_LEN: u32 = 1;\nglobal I64_SERIALIZED_LEN: u32 = 1;\n\nimpl Serialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> bool {\n reader.read() != 0\n }\n}\n\nimpl Serialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8\n }\n}\n\nimpl Serialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16\n }\n}\n\nimpl Serialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32\n }\n}\n\nimpl Serialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64\n }\n}\n\nimpl Serialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u128\n }\n}\n\nimpl Serialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self);\n }\n}\n\nimpl Deserialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read()\n }\n}\n\nimpl Serialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u8 as Field);\n }\n}\n\nimpl Deserialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8 as i8\n }\n}\n\nimpl Serialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u16 as Field);\n }\n}\n\nimpl Deserialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16 as i16\n }\n}\n\nimpl Serialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u32 as Field);\n }\n}\n\nimpl Deserialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32 as i32\n }\n}\n\nimpl Serialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u64 as Field);\n }\n}\n\nimpl Deserialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64 as i64\n }\n}\n\nimpl Serialize for [T; M]\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n for i in 0..M {\n self[i].stream_serialize(writer);\n }\n }\n}\n\nimpl Deserialize for [T; M]\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut result: [T; M] = std::mem::zeroed();\n for i in 0..M {\n result[i] = T::stream_deserialize(reader);\n }\n result\n }\n}\n\nimpl Serialize for Option\nwhere\n T: Serialize,\n{\n let N: u32 = ::N + 1;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write_bool(self.is_some());\n if self.is_some() {\n self.unwrap_unchecked().stream_serialize(writer);\n } else {\n writer.advance_offset(::N);\n }\n }\n}\n\nimpl Deserialize for Option\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n if reader.read_bool() {\n Option::some(::stream_deserialize(reader))\n } else {\n reader.advance_offset(::N);\n Option::none()\n }\n }\n}\n\nglobal SCALAR_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurveScalar {\n\n let N: u32 = SCALAR_SIZE;\n\n fn serialize(self) -> [Field; SCALAR_SIZE] {\n [self.lo, self.hi]\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.lo);\n writer.write(self.hi);\n }\n}\n\nimpl Deserialize for EmbeddedCurveScalar {\n let N: u32 = SCALAR_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { lo: fields[0], hi: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { lo: reader.read(), hi: reader.read() }\n }\n}\n\nglobal POINT_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn serialize(self) -> [Field; Self::N] {\n [self.x, self.y]\n }\n\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.x);\n writer.write(self.y);\n }\n}\n\nimpl Deserialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { x: fields[0], y: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { x: reader.read(), y: reader.read() }\n }\n}\n\nimpl Deserialize for str {\n let N: u32 = M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);\n str::::from(u8_arr)\n }\n}\n\nimpl Serialize for str {\n let N: u32 = M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.as_bytes().stream_serialize(writer);\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Deserialize for BoundedVec\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut new_bounded_vec: BoundedVec = BoundedVec::new();\n let payload_len = Self::N - 1;\n\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n let len = reader.peek_offset(payload_len) as u32;\n\n for i in 0..M {\n if i < len {\n new_bounded_vec.push(::stream_deserialize(reader));\n }\n }\n\n // +1 for the length of the BoundedVec\n reader.advance_offset((M - len) * ::N + 1);\n\n new_bounded_vec\n }\n}\n\n// This may cause issues if used as program input, because noir disallows empty arrays for program input.\n// I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint\n// if someone does run into this in the future.\nimpl Deserialize for () {\n let N: u32 = 0;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(_reader: &mut Reader) -> Self {\n ()\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Serialize for BoundedVec\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M + 1; // +1 for the length of the BoundedVec\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.storage().stream_serialize(writer);\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n writer.write_u32(self.len() as u32);\n }\n}\n\n// Create a slice of the given length with each element made from `f(i)` where `i` is the current index\ncomptime fn make_slice(length: u32, f: fn[Env](u32) -> T) -> [T] {\n let mut slice = @[];\n for i in 0..length {\n slice = slice.push_back(f(i));\n }\n slice\n}\n\n// Implements Serialize and Deserialize for an arbitrary tuple type\ncomptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {\n // `T0`, `T1`, `T2`\n let type_names = make_slice(length, |i| f\"T{i}\".quoted_contents());\n\n // `result0`, `result1`, `result2`\n let result_names = make_slice(length, |i| f\"result{i}\".quoted_contents());\n\n // `T0, T1, T2`\n let field_generics = type_names.join(quote [,]);\n\n // `::N + ::N + ::N`\n let full_size_serialize = type_names\n .map(|type_name| quote {\n <$type_name as Serialize>::N\n })\n .join(quote [+]);\n\n // `::N + ::N + ::N`\n let full_size_deserialize = type_names\n .map(|type_name| quote {\n <$type_name as Deserialize>::N\n })\n .join(quote [+]);\n\n // `T0: Serialize, T1: Serialize, T2: Serialize,`\n let serialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Serialize,\n })\n .join(quote []);\n\n // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`\n let deserialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Deserialize,\n })\n .join(quote []);\n\n // Statements to serialize each field\n let serialized_fields = type_names\n .mapi(|i, _type_name| quote {\n $crate::serialization::Serialize::stream_serialize(self.$i, writer);\n })\n .join(quote []);\n\n // Statements to deserialize each field\n let deserialized_fields = type_names\n .mapi(|i, type_name| {\n let result_name = result_names[i];\n quote {\n let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote []);\n let deserialize_results = result_names.join(quote [,]);\n\n quote {\n impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {\n let N: u32 = $full_size_serialize;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n\n $serialized_fields\n }\n }\n\n impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {\n let N: u32 = $full_size_deserialize;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n \n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $deserialized_fields\n ($deserialize_results)\n }\n }\n }\n}\n\n// Keeping these manual impls. They are more efficient since they do not\n// require copying sub-arrays from any serialized arrays.\nimpl Serialize for (T1,)\nwhere\n T1: Serialize,\n{\n let N: u32 = ::N;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: crate::writer::Writer = crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.0.stream_serialize(writer);\n }\n}\n\nimpl Deserialize for (T1,)\nwhere\n T1: Deserialize,\n{\n let N: u32 = ::N;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n (::stream_deserialize(reader),)\n }\n}\n\n#[impl_serialize_for_tuple(2)]\n#[impl_serialize_for_tuple(3)]\n#[impl_serialize_for_tuple(4)]\n#[impl_serialize_for_tuple(5)]\n#[impl_serialize_for_tuple(6)]\nmod impls {\n use crate::serialization::{Deserialize, Serialize};\n}\n\n#[test]\nunconstrained fn bounded_vec_serialization() {\n // Test empty BoundedVec\n let empty_vec: BoundedVec = BoundedVec::from_array([]);\n let serialized = empty_vec.serialize();\n let deserialized = BoundedVec::::deserialize(serialized);\n assert_eq(empty_vec, deserialized);\n assert_eq(deserialized.len(), 0);\n\n // Test partially filled BoundedVec\n let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);\n let serialized = partial_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(partial_vec, deserialized);\n assert_eq(deserialized.len(), 1);\n assert_eq(deserialized.get(0), [1, 2]);\n\n // Test full BoundedVec\n let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);\n let serialized = full_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(full_vec, deserialized);\n assert_eq(deserialized.len(), 3);\n assert_eq(deserialized.get(0), [1, 2]);\n assert_eq(deserialized.get(1), [3, 4]);\n assert_eq(deserialized.get(2), [5, 6]);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/type_impls.nr","function_locations":[{"start":693,"name":"::serialize"},{"start":914,"name":"::stream_serialize"},{"start":1082,"name":"::deserialize"},{"start":1328,"name":"::stream_deserialize"},{"start":1470,"name":"::serialize"},{"start":1691,"name":"::stream_serialize"},{"start":1855,"name":"::deserialize"},{"start":2101,"name":"::stream_deserialize"},{"start":2246,"name":"::serialize"},{"start":2467,"name":"::stream_serialize"},{"start":2633,"name":"::deserialize"},{"start":2879,"name":"::stream_deserialize"},{"start":3025,"name":"::serialize"},{"start":3246,"name":"::stream_serialize"},{"start":3412,"name":"::deserialize"},{"start":3658,"name":"::stream_deserialize"},{"start":3804,"name":"::serialize"},{"start":4025,"name":"::stream_serialize"},{"start":4191,"name":"::deserialize"},{"start":4437,"name":"::stream_deserialize"},{"start":4585,"name":"::serialize"},{"start":4806,"name":"::stream_serialize"},{"start":4974,"name":"::deserialize"},{"start":5220,"name":"::stream_deserialize"},{"start":5371,"name":"::serialize"},{"start":5592,"name":"::stream_serialize"},{"start":5753,"name":"::deserialize"},{"start":5999,"name":"::stream_deserialize"},{"start":6136,"name":"::serialize"},{"start":6357,"name":"::stream_serialize"},{"start":6527,"name":"::deserialize"},{"start":6773,"name":"::stream_deserialize"},{"start":6924,"name":"::serialize"},{"start":7145,"name":"::stream_serialize"},{"start":7318,"name":"::deserialize"},{"start":7564,"name":"::stream_deserialize"},{"start":7717,"name":"::serialize"},{"start":7938,"name":"::stream_serialize"},{"start":8111,"name":"::deserialize"},{"start":8357,"name":"::stream_deserialize"},{"start":8510,"name":"::serialize"},{"start":8731,"name":"::stream_serialize"},{"start":8904,"name":"::deserialize"},{"start":9150,"name":"::stream_deserialize"},{"start":9350,"name":"::serialize"},{"start":9571,"name":"::stream_serialize"},{"start":9831,"name":"::deserialize"},{"start":10077,"name":"::stream_deserialize"},{"start":10389,"name":">::serialize"},{"start":10610,"name":">::stream_serialize"},{"start":10997,"name":">::deserialize"},{"start":11243,"name":">::stream_deserialize"},{"start":11621,"name":"::serialize"},{"start":11744,"name":"::stream_serialize"},{"start":11944,"name":"::deserialize"},{"start":12090,"name":"::stream_deserialize"},{"start":12297,"name":"::serialize"},{"start":12397,"name":"::stream_serialize"},{"start":12593,"name":"::deserialize"},{"start":12737,"name":"::stream_deserialize"},{"start":12916,"name":">::deserialize"},{"start":13162,"name":">::stream_deserialize"},{"start":13395,"name":">::serialize"},{"start":13616,"name":">::stream_serialize"},{"start":13997,"name":">::deserialize"},{"start":14243,"name":">::stream_deserialize"},{"start":15299,"name":"::deserialize"},{"start":15546,"name":"::stream_deserialize"},{"start":15911,"name":">::serialize"},{"start":16132,"name":">::stream_serialize"},{"start":16617,"name":"make_slice"},{"start":16867,"name":"impl_serialize_for_tuple"},{"start":20158,"name":"::serialize"},{"start":20409,"name":"::stream_serialize"},{"start":20616,"name":"::deserialize"},{"start":20877,"name":"::stream_deserialize"},{"start":21226,"name":"bounded_vec_serialization"}]},"415":{"source":"pub struct Writer {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Writer {\n pub fn new() -> Self {\n Self { data: [0; N], offset: 0 }\n }\n\n pub fn write(&mut self, value: Field) {\n self.data[self.offset] = value;\n self.offset += 1;\n }\n\n pub fn write_u32(&mut self, value: u32) {\n self.write(value as Field);\n }\n\n pub fn write_u64(&mut self, value: u64) {\n self.write(value as Field);\n }\n\n pub fn write_bool(&mut self, value: bool) {\n self.write(value as Field);\n }\n\n pub fn write_array(&mut self, value: [Field; K]) {\n for i in 0..K {\n self.data[i + self.offset] = value[i];\n }\n self.offset += K;\n }\n\n pub fn write_struct(&mut self, value: T, serialize: fn(T) -> [Field; K]) {\n self.write_array(serialize(value));\n }\n\n pub fn write_struct_array(\n &mut self,\n value: [T; C],\n serialize: fn(T) -> [Field; K],\n ) {\n for i in 0..C {\n self.write_struct(value[i], serialize);\n }\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) -> [Field; N] {\n assert_eq(self.offset, self.data.len(), \"Writer did not write all data\");\n self.data\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/writer.nr","function_locations":[{"start":128,"name":"Writer::new"},{"start":220,"name":"Writer::write"},{"start":339,"name":"Writer::write_u32"},{"start":428,"name":"Writer::write_u64"},{"start":519,"name":"Writer::write_bool"},{"start":629,"name":"Writer::write_array"},{"start":841,"name":"Writer::write_struct"},{"start":1040,"name":"Writer::write_struct_array"},{"start":1185,"name":"Writer::advance_offset"},{"start":1263,"name":"Writer::finish"}]}}} \ No newline at end of file diff --git a/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak b/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak deleted file mode 100644 index 9f3fdb1d7f9a..000000000000 --- a/noir-projects/contract-snapshots/test_programs/compile_success/authorize_once_before_external/target/authorize_once_before_external-AuthorizeOnceBeforeExternal.json.bak +++ /dev/null @@ -1 +0,0 @@ -{"noir_version":"1.0.0-beta.19+842974fcf034b0a652631e69fc24f92f9ddd1d37","name":"AuthorizeOnceBeforeExternal","functions":[{"name":"__aztec_nr_internals__foo","hash":"4876275608018138592","is_unconstrained":true,"custom_attributes":["abi_public"],"abi":{"parameters":[{"name":"from","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"},{"name":"authwit_nonce","type":{"kind":"field"},"visibility":"private"}],"return_type":null,"error_types":{"26387131971136782":{"error_kind":"string","string":"Invalid response from registry"},"7136484461999155778":{"error_kind":"string","string":"Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"},"8502498164115016271":{"error_kind":"string","string":"semantic length returned from oracle does not match data"},"9894212961085021188":{"error_kind":"string","string":"Message not authorized by account"}}},"bytecode":"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","debug_symbols":"tZnRTmM5DIbfpddcJLbjJLzKCKECZVSpKqgDK60Q7742x05apGShZW74/7acr45jJzmnb6uHzd3r79vt/vHpz+r619vq7rDd7ba/b3dP9+uX7dNe3n1bBf0T6+oar1YgL7JIXF3HKAqi+jaakr2fTFk0iWbTYloXxWCqPOGiXA9yHcr1IDxk02zvF1O5HuQ6CqbRFEwlHiiiZJpM2TSbFtO6aAqmyquiYCo8lO9NZCo8lO9JbJpNi2ldlINpNBUeCo/RlEyTqfBIxsvZtJjWRXMwjaZgiqZkmkyNl42XjZeNV4xXlCfxFTBFUzJNpmyaTZXHonXRKrwEotEUTNGUTJMpm2bTYloXjSG4iW7ADbohN0olNewmuyluqpkY3EQ3Sk5q0I2SWU3yd9hNdlPcVDPaI4tRclEDbtANuUlu2E12o+SqpprRdmFUE92AG3RDbpIbdpPdFDfVDDmZnKytxDoK7aXFKDmrUbLGo+2Uo5rspripZrSlFhPdgBt0Q26SGycnJycnJyezk9nJ7GR2MjuZncxOZiezk9nJ2lY5qEE35EY5mh9trcVkN8VNNaNtlbW0tK8Wg24UqFnV1lqMArXYtLkWU8xoW2XNvPbVYsCNAvP7+9XK1+zbl8Nmo0v20SIuS/vz+rDZv6yu96+73dXqn/Xu9eOf/jyv9x/6sj7IpzLEzf5BVICP291G3ftVvzqMLwUMya4GhNQA0jMniDhBBNJGXhiBmBuEywkDJoxcnFCpB5Hxy+Pgwk7IpQzHQWMEEnkqkLinIsMJIf1AJvgvZiIhegwJKR9l4hRRxgiSdc0QJN09ykSdjEIua+OQ5SCOMhHDbEKqzwePUzGPoleFLC9lGMWkNAlCz0VthHRWMo/G8SmZcVKZNXphVuhjoPjVksAQe0lgHJZE5AvTMCvLoEewJQaKkxgmqYylFi8JWV7lyhbGp2T+RGnCxaUZf6I24dLa/EZGAUYZhUvLcxpFDW3pFc9xGMVs4QRqkyI+4zCheQKh2hZwaZXhzM4DSdrMFkiCOgxkPpqSOgTDCIKzKk25VWmPAgp/Z2YKtZmRs/poZhCmZwzqh4ww7jjEWb9AY8ihbbjBI10+u/M4OgNO1tJPccwmV06vjQF9iy6nLYOTQq3A0Jqu9jAwnTY/TiaXQ1sIOXAPA78eRT89ViQYRkGTIpXeR2eEGsaMOFuOHYFHZz/gT2e/WY3G3FfjQucxALFNK0/imJRoim3tSHLz1curfDkMrNl3WrF1GMb/7AvtJCt9H4d9T7PFFELpK7LcZQ4h5QdKrF5eYilcWmIpXl5iU8YXSyzhxSU2DSNB7QtpPm8oiWJjMJ7FwNqGgpXGpZ7yX03Hj3RcjRB7xx3d+31qFg4zSG3bNQQ59Q8hk9HIUyD0QhU/PkgxzPYWgra3HN1C4nfCqH66lXnJwxMQz3b8cHTITuMdfxpI6nut+DI8vvBsy+fcji9c+cxAENthLGEaP14os+cL/RFFzmcHEsNRIHkUSJ49sSncMiKnzDMDobYeip8EMtsvCdoxWZ7fjAOZDUZundqKGODoscs3ulcurC0lAceH7W9AgEeQCYOwLUWER433ca9+Iy/X99vDyc9N7wo7bNd3u429fHzd3x99+vLvs3/iP1c9H57uNw+vh42S+m9W8udXrHwlB4YbfUAvL6V15WW+eddv/w8="},{"name":"offchain_receive","hash":"6201884033566737539","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]},"visibility":"private"}],"return_type":null,"error_types":{"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"}}},"bytecode":"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","debug_symbols":"tZndbhs5DEbfxde5EKkfinmVoCjc1CkMGE7gJgssgrz7khl9sr2FBNdub6qTxnNMcShKk3lffd98e/vxdbt/ev65un94X307bHe77Y+vu+fH9ev2eW//+74K/k/hurqPdzbq6r7YGEMbqY3cxtjG1MbcxtJGaWNtY/Ol5kvNl5ov2+fExmL/rz5yG81P5JAB9g3kIRYBVIA2kAAgAAMiIAEyAGaBWWAWmCvMFeYKc4W5wlxhrjBXmCvMFWaFWWFWmBVmhVmbWYJflR0IwAD/THEoAAHYt3Nw0AYUAARgQATYt7NfThlQAAJwszhoAw4AN6uDmaMHzxGQABlQAAKoAG3gtbkAAWCOMEeYvUCjp8UrdAEBuLk6aAOv0gXs8uRzT/bhxA724ZQctEEOAAsjuTAzIAISIAMKQABu9hxmbVACgABu9hyWCEgAM2cP1RfIAgKoAG3gC2QBApg5k0MEJEAGuNmT6QtkgQpwsyfBF8gCBGBABCRABrjZk+ALZIEK0Aa+QLInwRdI9rvjC2SBCHCzZ8MXyAIFIIAK0AWqL6IFvCsFBwZEQAJ4p2OHAhCAN7vooA18WZXkQAAGRICbq4OZxb/Cl9UCAqgAbeDLagECmFnIIQLMLB6GL6sFCsDN/u2+rBbQBr6sFiAAAyLAzdkhAwpAAG4uDtrAl9UCBPCrxEEAFWBXVZ+Xr68FCGDxVJ+gr68FEiADCkAAFeBmv1++vhYgAAN8pvXj426FTfLr62Gz8T3yZNe0vfRlfdjsX1f3+7fd7m71z3r39vmhny/r/ef4uj7Yby3qzf67jSZ82u42Th93x6vD+FIKtum2y42LdgWFcwmNJcmb86ciJekCOb+ex9fHjBlEy0oPQPQ3ZqG1z8La13AWaSzJuWpz5BLKUZHjmSKPFVwYyWQ7fHRFuTiGIqXHoDyMYaKww1RsCjsnhaGijhW2pzeDnApELp6G9Biy7brDGGhyTyMTbkfkmAe5nBu011UMdWSYFGYihiFR1Cvup20nSIT17XEiJg7189anQvk4iUQXx6B9Elk1XFVTIUBRAo0VJJM1qgVVRSqpO/L5KqdJXZJQ71V2ShgqdJZMBKH1tNWUyw2aeqehPFTwpF8yJziY8/CeMs86Hh/bdqZxGHFSGLU7sm1bJ2HwuWNeGdorg8PYMeuaKfemebypKVxZGDouDJndk0j9nqQ4UvAkipJzz0XWdFUUVARRWB8fKeKk66XcN2MZ10WcbedUuHc9Pb2n53tpnNVn7jckxxNDvDwK7pWV+GSx/xLFpDqJK/YhikTjOCaOaA9u2EVqqOM4yiSOQqnno1BOw3USJ8URUw/kbLXGa+OQOI5j1gGzIqt6Wue/OKaRxGMfLYnGnSNNaiSW48ExDTMyNVyU0zTpoilEtK8UkoznMXFwxDw481VRcO09tJarauPSOk8yO76GvqNYqY1zUf9APuvN+ax/M5+X5iLz7bmYOS7LxdRwcy4s+NrnUeiqjnFxLuTvOi7Mp9ycz+neqH0ecbJWC/2BvXF21pD+xJzC+DQ9zWbFcYXtllx1ZkrUT9P55Cj8P0XJt56Zyqx7BsVqt2SO99Uy29+5HJ94K1/p6FMxXR079NYKn+bzorqYPVZwRsMoXMbPzTJpW/aiBamwNyxx8PA+NVTGadxeu+hVBunzqHLFHxDsVVl/pohh/OQ9Pa+VfpLWQuW6M9+pI47rW+rtO6Lo7R1cbq7vqWHcwb/Yj+vH7eHs9eeHqw7b9bfdpv349LZ/PPnt678v+A1en74cnh83398OGzcd36HaPw/V/kpelb/crezvyA92jr8rLPaTvwZ4qFYwGujLh8fyHw=="},{"name":"public_dispatch","hash":"15893691869641264666","is_unconstrained":true,"custom_attributes":["abi_public"],"abi":{"parameters":[{"name":"selector","type":{"kind":"field"},"visibility":"private"}],"return_type":null,"error_types":{"26387131971136782":{"error_kind":"string","string":"Invalid response from registry"},"7136484461999155778":{"error_kind":"string","string":"Invalid authwit nonce. When 'from' and 'msg_sender' are the same, 'authwit_nonce' must be zero"},"8502498164115016271":{"error_kind":"string","string":"semantic length returned from oracle does not match data"},"9894212961085021188":{"error_kind":"string","string":"Message not authorized by account"},"11194752367584870169":{"error_kind":"fmtstring","length":27,"item_types":[{"kind":"field"}]}}},"bytecode":"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","debug_symbols":"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"},{"name":"sync_state","hash":"7288454187967671611","is_unconstrained":true,"custom_attributes":["abi_utility"],"abi":{"parameters":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"return_type":null,"error_types":{"361444214588792908":{"error_kind":"string","string":"attempt to multiply with overflow"},"992401946138144806":{"error_kind":"string","string":"Attempted to read past end of BoundedVec"},"1064022259863234536":{"error_kind":"fmtstring","length":101,"item_types":[{"kind":"integer","sign":"unsigned","width":32}]},"1998584279744703196":{"error_kind":"string","string":"attempt to subtract with overflow"},"5421095327929394772":{"error_kind":"string","string":"attempt to bit-shift with overflow"},"5449178635769758673":{"error_kind":"fmtstring","length":61,"item_types":[{"kind":"field"},{"kind":"field"}]},"9530675838293881722":{"error_kind":"string","string":"Writer did not write all data"},"9791669845391776238":{"error_kind":"string","string":"0 has a square root; you cannot claim it is not square"},"9885968605480832328":{"error_kind":"string","string":"Attempted to read past the length of a CapsuleArray"},"10791800398362570014":{"error_kind":"string","string":"extend_from_bounded_vec out of bounds"},"10835969307644359280":{"error_kind":"fmtstring","length":40,"item_types":[]},"11021520179822076911":{"error_kind":"string","string":"Attempted to delete past the length of a CapsuleArray"},"12820178569648940736":{"error_kind":"fmtstring","length":48,"item_types":[{"kind":"field"},{"kind":"field"}]},"12913276134398371456":{"error_kind":"string","string":"push out of bounds"},"14990209321349310352":{"error_kind":"string","string":"attempt to add with overflow"},"16431471497789672479":{"error_kind":"string","string":"Index out of bounds"},"17110599087403377004":{"error_kind":"fmtstring","length":98,"item_types":[]},"17655676068928457687":{"error_kind":"string","string":"Reader did not read all data"}}},"bytecode":"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","debug_symbols":"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"}],"outputs":{"structs":{"functions":[{"kind":"struct","path":"AuthorizeOnceBeforeExternal::foo_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::foo_parameters","fields":[{"name":"from","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"authwit_nonce","type":{"kind":"field"}}]}}]},{"kind":"struct","path":"AuthorizeOnceBeforeExternal::offchain_receive_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::offchain_receive_parameters","fields":[{"name":"messages","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::messages::processing::offchain::OffchainMessage","fields":[{"name":"ciphertext","type":{"kind":"struct","path":"std::collections::bounded_vec::BoundedVec","fields":[{"name":"storage","type":{"kind":"array","length":15,"type":{"kind":"field"}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"tx_hash","type":{"kind":"struct","path":"std::option::Option","fields":[{"name":"_is_some","type":{"kind":"boolean"}},{"name":"_value","type":{"kind":"field"}}]}},{"name":"anchor_block_timestamp","type":{"kind":"integer","sign":"unsigned","width":64}}]}}},{"name":"len","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]},{"kind":"struct","path":"AuthorizeOnceBeforeExternal::sync_state_abi","fields":[{"name":"parameters","type":{"kind":"struct","path":"AuthorizeOnceBeforeExternal::sync_state_parameters","fields":[{"name":"scope","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}]},"globals":{}},"file_map":{"3":{"source":"use crate::cmp::{Eq, Ord};\nuse crate::convert::From;\nuse crate::runtime::is_unconstrained;\n\nmod check_shuffle;\nmod quicksort;\n\nimpl [T; N] {\n /// Returns the length of this array.\n ///\n /// ```noir\n /// fn len(self) -> Field\n /// ```\n ///\n /// example\n ///\n /// ```noir\n /// fn main() {\n /// let array = [42, 42];\n /// assert(array.len() == 2);\n /// }\n /// ```\n #[builtin(array_len)]\n pub fn len(self) -> u32 {}\n\n /// Returns this array as a vector.\n ///\n /// ```noir\n /// let array = [1, 2];\n /// let vector = array.as_vector();\n /// assert_eq(vector, [1, 2].as_vector());\n /// ```\n #[builtin(as_vector)]\n pub fn as_vector(self) -> [T] {}\n\n /// Returns this array as a vector.\n /// This method is deprecated in favor of `as_vector`.\n ///\n /// ```noir\n /// let array = [1, 2];\n /// let vector = array.as_slice();\n /// assert_eq(vector, [1, 2].as_vector());\n /// ```\n #[builtin(as_vector)]\n #[deprecated(\"This method has been renamed to `as_vector`\")]\n pub fn as_slice(self) -> [T] {}\n\n /// Applies a function to each element of this array, returning a new array containing the mapped elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let b = a.map(|a| a * 2);\n /// assert_eq(b, [2, 4, 6]);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> [U; N] {\n let uninitialized = crate::mem::zeroed();\n let mut ret = [uninitialized; N];\n\n for i in 0..self.len() {\n ret[i] = f(self[i]);\n }\n\n ret\n }\n\n /// Applies a function to each element of this array along with its index,\n /// returning a new array containing the mapped elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let b = a.mapi(|i, a| i + a * 2);\n /// assert_eq(b, [2, 5, 8]);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> [U; N] {\n let uninitialized = crate::mem::zeroed();\n let mut ret = [uninitialized; N];\n\n for i in 0..self.len() {\n ret[i] = f(i, self[i]);\n }\n\n ret\n }\n\n /// Applies a function to each element of this array.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let mut b = [0; 3];\n /// let mut i = 0;\n /// a.for_each(|x| {\n /// b[i] = x;\n /// i += 1;\n /// });\n /// assert_eq(a, b);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n for i in 0..self.len() {\n f(self[i]);\n }\n }\n\n /// Applies a function to each element of this array along with its index.\n ///\n /// Example:\n ///\n /// ```rust\n /// let a = [1, 2, 3];\n /// let mut b = [0; 3];\n /// a.for_eachi(|i, x| {\n /// b[i] = x;\n /// });\n /// assert_eq(a, b);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n for i in 0..self.len() {\n f(i, self[i]);\n }\n }\n\n /// Applies a function to each element of the array, returning the final accumulated value. The first\n /// parameter is the initial value.\n ///\n /// This is a left fold, so the given function will be applied to the accumulator and first element of\n /// the array, then the second, and so on. For a given call the expected result would be equivalent to:\n ///\n /// ```rust\n /// let a1 = [1];\n /// let a2 = [1, 2];\n /// let a3 = [1, 2, 3];\n ///\n /// let f = |a, b| a - b;\n /// a1.fold(10, f); //=> f(10, 1)\n /// a2.fold(10, f); //=> f(f(10, 1), 2)\n /// a3.fold(10, f); //=> f(f(f(10, 1), 2), 3)\n ///\n /// assert_eq(a3.fold(10, f), 10 - 1 - 2 - 3);\n /// ```\n pub fn fold(&self, mut accumulator: U, f: fn[Env](U, T) -> U) -> U {\n for elem in self {\n accumulator = f(accumulator, elem);\n }\n accumulator\n }\n\n /// Same as fold, but uses the first element as the starting element.\n ///\n /// Requires the input array to be non-empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [1, 2, 3, 4];\n /// let reduced = arr.reduce(|a, b| a + b);\n /// assert(reduced == 10);\n /// }\n /// ```\n pub fn reduce(&self, f: fn[Env](T, T) -> T) -> T {\n let mut accumulator = self[0];\n for i in 1..self.len() {\n accumulator = f(accumulator, self[i]);\n }\n accumulator\n }\n\n /// Returns true if all the elements in this array satisfy the given predicate.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [2, 2, 2, 2, 2];\n /// let all = arr.all(|a| a == 2);\n /// assert(all);\n /// }\n /// ```\n pub fn all(&self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = true;\n for elem in self {\n ret &= predicate(elem);\n }\n ret\n }\n\n /// Returns true if any of the elements in this array satisfy the given predicate.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr = [2, 2, 2, 2, 5];\n /// let any = arr.any(|a| a == 5);\n /// assert(any);\n /// }\n /// ```\n pub fn any(&self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n for elem in self {\n ret |= predicate(elem);\n }\n ret\n }\n\n /// Concatenates this array with another array.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn main() {\n /// let arr1 = [1, 2, 3, 4];\n /// let arr2 = [6, 7, 8, 9, 10, 11];\n /// let concatenated_arr = arr1.concat(arr2);\n /// assert(concatenated_arr == [1, 2, 3, 4, 6, 7, 8, 9, 10, 11]);\n /// }\n /// ```\n pub fn concat(&self, array2: [T; M]) -> [T; N + M] {\n let mut result = [crate::mem::zeroed(); N + M];\n for i in 0..N {\n result[i] = self[i];\n }\n for i in 0..M {\n result[i + N] = array2[i];\n }\n result\n }\n}\n\nimpl [T; N]\nwhere\n T: Ord + Eq,\n{\n /// Returns a new sorted array. The original array remains untouched. Notice that this function will\n /// only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting\n /// logic it uses internally is optimized specifically for these values. If you need a sort function to\n /// sort any type, you should use the [`Self::sort_via`] function.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let arr = [42, 32];\n /// let sorted = arr.sort();\n /// assert(sorted == [32, 42]);\n /// }\n /// ```\n pub fn sort(&self) -> Self {\n self.sort_via(|a, b| a <= b)\n }\n}\n\nimpl [T; N]\nwhere\n T: Eq,\n{\n /// Returns a new sorted array by sorting it with a custom comparison function.\n /// The original array remains untouched.\n /// The ordering function must return true if the first argument should be sorted to be before the second argument or is equal to the second argument.\n ///\n /// Using this method with an operator like `<` that does not return `true` for equal values will result in an assertion failure for arrays with equal elements.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let arr = [42, 32]\n /// let sorted_ascending = arr.sort_via(|a, b| a <= b);\n /// assert(sorted_ascending == [32, 42]); // verifies\n ///\n /// let sorted_descending = arr.sort_via(|a, b| a >= b);\n /// assert(sorted_descending == [32, 42]); // does not verify\n /// }\n /// ```\n pub fn sort_via(&self, ordering: fn[Env](T, T) -> bool) -> Self {\n // Safety: `sorted` array is checked to be:\n // a. a permutation of `input`'s elements\n // b. satisfying the predicate `ordering`\n let sorted = unsafe { quicksort::quicksort(self, ordering) };\n\n if !is_unconstrained() {\n for i in 0..N - 1 {\n assert(\n ordering(sorted[i], sorted[i + 1]),\n \"Array has not been sorted correctly according to `ordering`.\",\n );\n }\n check_shuffle::check_shuffle(self, &sorted);\n }\n sorted\n }\n}\n\nimpl [u8; N] {\n /// Converts a byte array of type `[u8; N]` to a string. Note that this performs no UTF-8 validation -\n /// the given array is interpreted as-is as a string.\n ///\n /// Example:\n ///\n /// ```rust\n /// fn main() {\n /// let hi = [104, 105].as_str_unchecked();\n /// assert_eq(hi, \"hi\");\n /// }\n /// ```\n #[builtin(array_as_str_unchecked)]\n pub fn as_str_unchecked(self) -> str {}\n}\n\nimpl From> for [u8; N] {\n /// Returns an array of the string bytes.\n fn from(s: str) -> Self {\n s.as_bytes()\n }\n}\n\nmod test {\n #[test]\n fn map_empty() {\n assert_eq([].map(|x| x + 1), []);\n }\n\n global arr_with_100_values: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2, 54,\n 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41, 19, 98,\n 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21, 43, 86, 35,\n 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15, 127, 81, 30, 8,\n 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n global expected_with_100_values: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30, 32,\n 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58, 61, 62,\n 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82, 84, 84, 86,\n 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114, 114, 116, 118,\n 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n fn sort_u32(a: u32, b: u32) -> bool {\n a <= b\n }\n\n #[test]\n fn test_sort() {\n let arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = arr.sort();\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_100_values() {\n let arr: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2,\n 54, 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41,\n 19, 98, 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21,\n 43, 86, 35, 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15,\n 127, 81, 30, 8, 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n\n let sorted = arr.sort();\n\n let expected: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30,\n 32, 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58,\n 61, 62, 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82,\n 84, 84, 86, 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114,\n 114, 116, 118, 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_100_values_comptime() {\n let sorted = arr_with_100_values.sort();\n assert(sorted == expected_with_100_values);\n }\n\n #[test]\n fn test_sort_via() {\n let arr: [u32; 7] = [3, 6, 8, 10, 1, 2, 1];\n\n let sorted = arr.sort_via(sort_u32);\n\n let expected: [u32; 7] = [1, 1, 2, 3, 6, 8, 10];\n assert(sorted == expected);\n }\n\n #[test]\n fn test_sort_via_100_values() {\n let arr: [u32; 100] = [\n 42, 123, 87, 93, 48, 80, 50, 5, 104, 84, 70, 47, 119, 66, 71, 121, 3, 29, 42, 118, 2,\n 54, 89, 44, 81, 0, 26, 106, 68, 96, 84, 48, 95, 54, 45, 32, 89, 100, 109, 19, 37, 41,\n 19, 98, 53, 114, 107, 66, 6, 74, 13, 19, 105, 64, 123, 28, 44, 50, 89, 58, 123, 126, 21,\n 43, 86, 35, 21, 62, 82, 0, 108, 120, 72, 72, 62, 80, 12, 71, 70, 86, 116, 73, 38, 15,\n 127, 81, 30, 8, 125, 28, 26, 69, 114, 63, 27, 28, 61, 42, 13, 32,\n ];\n\n let sorted = arr.sort_via(sort_u32);\n\n let expected: [u32; 100] = [\n 0, 0, 2, 3, 5, 6, 8, 12, 13, 13, 15, 19, 19, 19, 21, 21, 26, 26, 27, 28, 28, 28, 29, 30,\n 32, 32, 35, 37, 38, 41, 42, 42, 42, 43, 44, 44, 45, 47, 48, 48, 50, 50, 53, 54, 54, 58,\n 61, 62, 62, 63, 64, 66, 66, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 80, 80, 81, 81, 82,\n 84, 84, 86, 86, 87, 89, 89, 89, 93, 95, 96, 98, 100, 104, 105, 106, 107, 108, 109, 114,\n 114, 116, 118, 119, 120, 121, 123, 123, 123, 125, 126, 127,\n ];\n assert(sorted == expected);\n }\n\n #[test]\n fn mapi_empty() {\n assert_eq([].mapi(|i, x| i * x + 1), []);\n }\n\n #[test]\n fn for_each_empty() {\n let empty_array: [Field; 0] = [];\n empty_array.for_each(|_x| assert(false));\n }\n\n #[test]\n fn for_eachi_empty() {\n let empty_array: [Field; 0] = [];\n empty_array.for_eachi(|_i, _x| assert(false));\n }\n\n #[test]\n fn map_example() {\n let a = [1, 2, 3];\n let b = a.map(|a| a * 2);\n assert_eq(b, [2, 4, 6]);\n }\n\n #[test]\n fn mapi_example() {\n let a = [1, 2, 3];\n let b = a.mapi(|i, a| i + a * 2);\n assert_eq(b, [2, 5, 8]);\n }\n\n #[test]\n fn for_each_example() {\n let a = [1, 2, 3];\n let mut b = [0, 0, 0];\n let b_ref = &mut b;\n let mut i = 0;\n let i_ref = &mut i;\n a.for_each(|x| {\n b_ref[*i_ref] = x * 2;\n *i_ref += 1;\n });\n assert_eq(b, [2, 4, 6]);\n assert_eq(i, 3);\n }\n\n #[test]\n fn for_eachi_example() {\n let a = [1, 2, 3];\n let mut b = [0, 0, 0];\n let b_ref = &mut b;\n a.for_eachi(|i, a| { b_ref[i] = i + a * 2; });\n assert_eq(b, [2, 5, 8]);\n }\n\n #[test]\n fn concat() {\n let arr1 = [1, 2, 3, 4];\n let arr2 = [6, 7, 8, 9, 10, 11];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1, 2, 3, 4, 6, 7, 8, 9, 10, 11]);\n }\n\n #[test]\n fn concat_zero_length_with_something() {\n let arr1 = [];\n let arr2 = [1];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1]);\n }\n\n #[test]\n fn concat_something_with_zero_length() {\n let arr1 = [1];\n let arr2 = [];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, [1]);\n }\n\n #[test]\n fn concat_zero_lengths() {\n let arr1: [Field; 0] = [];\n let arr2: [Field; 0] = [];\n let concatenated_arr = arr1.concat(arr2);\n assert_eq(concatenated_arr, []);\n }\n}\n","path":"std/array/mod.nr","function_locations":[{"start":480,"name":"[T; N]::len"},{"start":735,"name":"[T; N]::as_vector"},{"start":1112,"name":"[T; N]::as_slice"},{"start":1443,"name":"[T; N]::map"},{"start":2004,"name":"[T; N]::mapi"},{"start":2552,"name":"[T; N]::for_each"},{"start":2970,"name":"[T; N]::for_eachi"},{"start":3837,"name":"[T; N]::fold"},{"start":4355,"name":"[T; N]::reduce"},{"start":4865,"name":"[T; N]::all"},{"start":5338,"name":"[T; N]::any"},{"start":5881,"name":"[T; N]::concat"},{"start":6778,"name":"[T; N]::sort"},{"start":7794,"name":"[T; N]::sort_via"},{"start":8823,"name":"[u8; N]::as_str_unchecked"},{"start":8950,"name":"> for [u8; N]>::from"},{"start":9024,"name":"test::map_empty"},{"start":10134,"name":"test::sort_u32"},{"start":10189,"name":"test::test_sort"},{"start":10420,"name":"test::test_sort_100_values"},{"start":11588,"name":"test::test_sort_100_values_comptime"},{"start":11733,"name":"test::test_sort_via"},{"start":11980,"name":"test::test_sort_via_100_values"},{"start":13141,"name":"test::mapi_empty"},{"start":13236,"name":"test::for_each_empty"},{"start":13374,"name":"test::for_eachi_empty"},{"start":13513,"name":"test::map_example"},{"start":13650,"name":"test::mapi_example"},{"start":13799,"name":"test::for_each_example"},{"start":14139,"name":"test::for_eachi_example"},{"start":14350,"name":"test::concat"},{"start":14609,"name":"test::concat_zero_length_with_something"},{"start":14812,"name":"test::concat_something_with_zero_length"},{"start":15001,"name":"test::concat_zero_lengths"}]},"5":{"source":"use crate::meta::ctstring::AsCtString;\nuse crate::meta::derive_via;\n\n/// Compare two values for equality\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n if result {\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\ncomptime fn make_tuple_eq_body(n: u32) -> Quoted {\n let mut body = f\"self.0.eq(other.0)\".as_ctstring();\n for i in 1u32..n {\n body = body.append_fmtstr(f\" & self.{i}.eq(other.{i})\");\n }\n f\"{body}\".quoted_contents()\n}\n\nimpl Eq for (A, B) {\n fn eq(self, other: (A, B)) -> bool {\n make_tuple_eq_body!(2u32)\n }\n}\n\nimpl Eq for (A, B, C) {\n fn eq(self, other: (A, B, C)) -> bool {\n make_tuple_eq_body!(3u32)\n }\n}\n\nimpl Eq for (A, B, C, D) {\n fn eq(self, other: (A, B, C, D)) -> bool {\n make_tuple_eq_body!(4u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E) {\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n make_tuple_eq_body!(5u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F) {\n fn eq(self, other: (A, B, C, D, E, F)) -> bool {\n make_tuple_eq_body!(6u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G) {\n fn eq(self, other: (A, B, C, D, E, F, G)) -> bool {\n make_tuple_eq_body!(7u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H) {\n fn eq(self, other: (A, B, C, D, E, F, G, H)) -> bool {\n make_tuple_eq_body!(8u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I)) -> bool {\n make_tuple_eq_body!(9u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J)) -> bool {\n make_tuple_eq_body!(10u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J, K) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> bool {\n make_tuple_eq_body!(11u32)\n }\n}\n\nimpl Eq for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> bool {\n make_tuple_eq_body!(12u32)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\n/// A value with three states: `Ordering::less()`, `Ordering::equal()` or `Ordering::greater()`.\n/// Most often used to encode the result of a comparison operation.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n/// Compare one object to another, returning whether it is less-than, equal-to,\n/// or greater-than the other object.\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let self_len = self.len();\n let other_len = other.len();\n let min_len = if self_len < other_len {\n self_len\n } else {\n other_len\n };\n\n let mut result = Ordering::equal();\n for i in 0..min_len {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n\n if result != Ordering::equal() {\n result\n } else {\n self_len.cmp(other_len)\n }\n }\n}\n\ncomptime fn make_tuple_ord_body(n: u32) -> Quoted {\n let last = n - 1u32;\n let mut body = if last == 1 {\n f\"let result = self.0.cmp(other.0);\".as_ctstring()\n } else {\n f\"let mut result = self.0.cmp(other.0);\".as_ctstring()\n };\n for i in 1u32..last {\n body = body.append_fmtstr(\n f\" if result == Ordering::equal() {{ result = self.{i}.cmp(other.{i}); }}\",\n );\n }\n body = body.append_fmtstr(\n f\" if result != Ordering::equal() {{ result }} else {{ self.{last}.cmp(other.{last}) }}\",\n );\n f\"{body}\".quoted_contents()\n}\n\nimpl Ord for (A, B) {\n fn cmp(self, other: (A, B)) -> Ordering {\n make_tuple_ord_body!(2u32)\n }\n}\n\nimpl Ord for (A, B, C) {\n fn cmp(self, other: (A, B, C)) -> Ordering {\n make_tuple_ord_body!(3u32)\n }\n}\n\nimpl Ord for (A, B, C, D) {\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n make_tuple_ord_body!(4u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E) {\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n make_tuple_ord_body!(5u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F) {\n fn cmp(self, other: (A, B, C, D, E, F)) -> Ordering {\n make_tuple_ord_body!(6u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G) {\n fn cmp(self, other: (A, B, C, D, E, F, G)) -> Ordering {\n make_tuple_ord_body!(7u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H)) -> Ordering {\n make_tuple_ord_body!(8u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I)) -> Ordering {\n make_tuple_ord_body!(9u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J)) -> Ordering {\n make_tuple_ord_body!(10u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J, K) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> Ordering {\n make_tuple_ord_body!(11u32)\n }\n}\n\nimpl Ord for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> Ordering {\n make_tuple_ord_body!(12u32)\n }\n}\n\n/// Compares and returns the maximum of two values.\n///\n/// Returns the second argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::max(1, 2), 2);\n/// assert_eq(cmp::max(2, 2), 2);\n/// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n/// Compares and returns the minimum of two values.\n///\n/// Returns the first argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::min(1, 2), 1);\n/// assert_eq(cmp::min(2, 2), 2);\n/// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use super::{Eq, max, min, Ord};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n\n #[test]\n fn correctly_handles_unequal_length_vectors() {\n let vector_1 = [0, 1, 2, 3].as_vector();\n let vector_2 = [0, 1, 2].as_vector();\n assert(!vector_1.eq(vector_2));\n }\n\n #[test]\n fn lexicographic_ordering_for_vectors() {\n assert(\n [2_u32].as_vector().cmp([1_u32, 1_u32, 1_u32].as_vector())\n == super::Ordering::greater(),\n );\n assert(\n [1_u32, 2_u32].as_vector().cmp([1_u32, 2_u32, 3_u32].as_vector())\n == super::Ordering::less(),\n );\n }\n}\n","path":"std/cmp.nr","function_locations":[{"start":305,"name":"derive_eq"},{"start":851,"name":"::eq"},{"start":940,"name":"::eq"},{"start":1026,"name":"::eq"},{"start":1112,"name":"::eq"},{"start":1198,"name":"::eq"},{"start":1282,"name":"::eq"},{"start":1366,"name":"::eq"},{"start":1452,"name":"::eq"},{"start":1538,"name":"::eq"},{"start":1624,"name":"::eq"},{"start":1717,"name":"::eq"},{"start":1796,"name":"::eq"},{"start":1921,"name":"::eq"},{"start":2139,"name":"::eq"},{"start":2418,"name":">::eq"},{"start":2598,"name":"make_tuple_eq_body"},{"start":2859,"name":"::eq"},{"start":2991,"name":"::eq"},{"start":3136,"name":"::eq"},{"start":3294,"name":"::eq"},{"start":3465,"name":"::eq"},{"start":3649,"name":"::eq"},{"start":3846,"name":"::eq"},{"start":4056,"name":"::eq"},{"start":4279,"name":"::eq"},{"start":4516,"name":"::eq"},{"start":4766,"name":"::eq"},{"start":4876,"name":"::eq"},{"start":5477,"name":"Ordering::less"},{"start":5548,"name":"Ordering::equal"},{"start":5621,"name":"Ordering::greater"},{"start":5992,"name":"derive_ord"},{"start":6642,"name":"::cmp"},{"start":6889,"name":"::cmp"},{"start":7137,"name":"::cmp"},{"start":7385,"name":"::cmp"},{"start":7631,"name":"::cmp"},{"start":7877,"name":"::cmp"},{"start":8125,"name":"::cmp"},{"start":8373,"name":"::cmp"},{"start":8621,"name":"::cmp"},{"start":8875,"name":"::cmp"},{"start":8974,"name":"::cmp"},{"start":9444,"name":"::cmp"},{"start":9847,"name":"::cmp"},{"start":10415,"name":"make_tuple_ord_body"},{"start":11037,"name":"::cmp"},{"start":11179,"name":"::cmp"},{"start":11335,"name":"::cmp"},{"start":11505,"name":"::cmp"},{"start":11689,"name":"::cmp"},{"start":11887,"name":"::cmp"},{"start":12099,"name":"::cmp"},{"start":12325,"name":"::cmp"},{"start":12565,"name":"::cmp"},{"start":12820,"name":"::cmp"},{"start":13089,"name":"::cmp"},{"start":13451,"name":"max"},{"start":13828,"name":"min"},{"start":13982,"name":"cmp_tests::sanity_check_min"},{"start":14178,"name":"cmp_tests::sanity_check_max"},{"start":14400,"name":"cmp_tests::correctly_handles_unequal_length_vectors"},{"start":14600,"name":"cmp_tests::lexicographic_ordering_for_vectors"}]},"6":{"source":"use crate::{cmp::Eq, convert::From, runtime::is_unconstrained, static_assert};\n\n/// A `BoundedVec` is a growable storage similar to a built-in vector except that it\n/// is bounded with a maximum possible length. `BoundedVec` is also not\n/// subject to the same restrictions vectors are (notably, nested vectors are disallowed).\n///\n/// Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by\n/// pushing an additional element is also more efficient - the length only needs to be increased\n/// by one.\n///\n/// For these reasons `BoundedVec` should generally be preferred over vectors when there\n/// is a reasonable maximum bound that can be placed on the vector.\n///\n/// Example:\n///\n/// ```noir\n/// let mut vector: BoundedVec = BoundedVec::new();\n/// for i in 0..5 {\n/// vector.push(i);\n/// }\n/// assert(vector.len() == 5);\n/// assert(vector.max_len() == 10);\n/// ```\npub struct BoundedVec {\n storage: [T; MaxLen],\n len: u32,\n}\n\nimpl BoundedVec {\n /// Creates a new, empty vector of length zero.\n ///\n /// Since this container is backed by an array internally, it still needs an initial value\n /// to give each element. To resolve this, each element is zeroed internally. This value\n /// is guaranteed to be inaccessible unless `get_unchecked` is used.\n ///\n /// Example:\n ///\n /// ```noir\n /// let empty_vector: BoundedVec = BoundedVec::new();\n /// assert(empty_vector.len() == 0);\n /// ```\n ///\n /// Note that whenever calling `new` the maximum length of the vector should always be specified\n /// via a type signature:\n ///\n /// ```noir\n /// fn good() -> BoundedVec {\n /// // Ok! MaxLen is specified with a type annotation\n /// let v1: BoundedVec = BoundedVec::new();\n /// let v2 = BoundedVec::new();\n ///\n /// // Ok! MaxLen is known from the type of `good`'s return value\n /// v2\n /// }\n ///\n /// fn bad() {\n /// // Error: Type annotation needed\n /// // The compiler can't infer `MaxLen` from the following code:\n /// let mut v3 = BoundedVec::new();\n /// v3.push(5);\n /// }\n /// ```\n ///\n /// This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions\n /// but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a\n /// constraint failure at runtime when the vec is pushed to.\n pub fn new() -> Self {\n let zeroed = crate::mem::zeroed();\n BoundedVec { storage: [zeroed; MaxLen], len: 0 }\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this\n /// will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// let last = v.get(v.len() - 1);\n /// assert(first != last);\n /// }\n /// ```\n pub fn get(&self, index: u32) -> T {\n assert(index < self.len, \"Attempted to read past end of BoundedVec\");\n self.get_unchecked(index)\n }\n\n /// Retrieves an element from the vector at the given index, starting from zero, without\n /// performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element,\n /// it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn sum_of_first_three(v: BoundedVec) -> u32 {\n /// // Always ensure the length is larger than the largest\n /// // index passed to get_unchecked\n /// assert(v.len() > 2);\n /// let first = v.get_unchecked(0);\n /// let second = v.get_unchecked(1);\n /// let third = v.get_unchecked(2);\n /// first + second + third\n /// }\n /// ```\n pub fn get_unchecked(&self, index: u32) -> T {\n self.storage[index]\n }\n\n /// Writes an element to the vector at the given index, starting from zero.\n ///\n /// If the given index is equal to or greater than the length of the vector, this will issue a constraint failure.\n ///\n /// Example:\n ///\n /// ```noir\n /// fn foo(v: BoundedVec) {\n /// let first = v.get(0);\n /// assert(first != 42);\n /// v.set(0, 42);\n /// let new_first = v.get(0);\n /// assert(new_first == 42);\n /// }\n /// ```\n pub fn set(&mut self, index: u32, value: T) {\n assert(index < self.len, \"Attempted to write past end of BoundedVec\");\n self.set_unchecked(index, value)\n }\n\n /// Writes an element to the vector at the given index, starting from zero, without performing a bounds check.\n ///\n /// Since this function does not perform a bounds check on length before accessing the element, it is unsafe! Use at your own risk!\n ///\n /// Example:\n ///\n /// ```noir\n /// fn set_unchecked_example() {\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([1, 2]);\n ///\n /// // Here we're safely writing within the valid range of `vec`\n /// // `vec` now has the value [42, 2]\n /// vec.set_unchecked(0, 42);\n ///\n /// // We can then safely read this value back out of `vec`.\n /// // Notice that we use the checked version of `get` which would prevent reading unsafe values.\n /// assert_eq(vec.get(0), 42);\n ///\n /// // We've now written past the end of `vec`.\n /// // As this index is still within the maximum potential length of `v`,\n /// // it won't cause a constraint failure.\n /// vec.set_unchecked(2, 42);\n /// println(vec);\n ///\n /// // This will write past the end of the maximum potential length of `vec`,\n /// // it will then trigger a constraint failure.\n /// vec.set_unchecked(5, 42);\n /// println(vec);\n /// }\n /// ```\n pub fn set_unchecked(&mut self, index: u32, value: T) {\n self.storage[index] = value;\n }\n\n /// Pushes an element to the end of the vector. This increases the length\n /// of the vector by one.\n ///\n /// Panics if the new length of the vector will be greater than the max length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// v.push(1);\n /// v.push(2);\n ///\n /// // Panics with failed assertion \"push out of bounds\"\n /// v.push(3);\n /// ```\n pub fn push(&mut self, elem: T) {\n assert(self.len < MaxLen, \"push out of bounds\");\n\n self.storage[self.len] = elem;\n self.len += 1;\n }\n\n /// Returns the current length of this vector\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// assert(v.len() == 0);\n ///\n /// v.push(100);\n /// assert(v.len() == 1);\n ///\n /// v.push(200);\n /// v.push(300);\n /// v.push(400);\n /// assert(v.len() == 4);\n ///\n /// let _ = v.pop();\n /// let _ = v.pop();\n /// assert(v.len() == 2);\n /// ```\n pub fn len(&self) -> u32 {\n self.len\n }\n\n /// Returns the maximum length of this vector. This is always\n /// equal to the `MaxLen` parameter this vector was initialized with.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.max_len() == 5);\n /// v.push(10);\n /// assert(v.max_len() == 5);\n /// ```\n pub fn max_len(_self: &BoundedVec) -> u32 {\n MaxLen\n }\n\n /// Returns the internal array within this vector.\n ///\n /// Since arrays in Noir are immutable, mutating the returned storage array will not mutate\n /// the storage held internally by this vector.\n ///\n /// Note that uninitialized elements may be zeroed out!\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n ///\n /// assert(v.storage() == [0, 0, 0, 0, 0]);\n ///\n /// v.push(57);\n /// assert(v.storage() == [57, 0, 0, 0, 0]);\n /// ```\n pub fn storage(&self) -> [T; MaxLen] {\n self.storage\n }\n\n /// Pushes each element from the given array to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_array([2, 4]);\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_array(&mut self, array: [T; Len]) {\n let new_len = self.len + array.len();\n assert(new_len <= MaxLen, \"extend_from_array out of bounds\");\n for i in 0..array.len() {\n self.storage[self.len + i] = array[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the given vector to this vector.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut vec: BoundedVec = BoundedVec::new();\n /// vec.extend_from_vector([2, 4].as_vector());\n ///\n /// assert(vec.len == 2);\n /// assert(vec.get(0) == 2);\n /// assert(vec.get(1) == 4);\n /// ```\n pub fn extend_from_vector(&mut self, vector: [T]) {\n let new_len = self.len + vector.len();\n assert(new_len <= MaxLen, \"extend_from_vector out of bounds\");\n for i in 0..vector.len() {\n self.storage[self.len + i] = vector[i];\n }\n self.len = new_len;\n }\n\n /// Pushes each element from the other vector to this vector. The length of\n /// the other vector is left unchanged.\n ///\n /// Panics if pushing each element would cause the length of this vector\n /// to exceed the maximum length.\n ///\n /// ```noir\n /// let mut v1: BoundedVec = BoundedVec::new();\n /// let mut v2: BoundedVec = BoundedVec::new();\n ///\n /// v2.extend_from_array([1, 2, 3]);\n /// v1.extend_from_bounded_vec(v2);\n ///\n /// assert(v1.storage() == [1, 2, 3, 0, 0]);\n /// assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]);\n /// ```\n pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) {\n let append_len = vec.len();\n let new_len = self.len + append_len;\n assert(new_len <= MaxLen, \"extend_from_bounded_vec out of bounds\");\n\n if is_unconstrained() {\n for i in 0..append_len {\n self.storage[self.len + i] = vec.get_unchecked(i);\n }\n } else {\n // The source vector can be longer than the destination, or vice versa;\n // regardless we will only ever be able to read or write whichever is\n // the shorter max length of the two. We asserted that the actual content fits,\n // but the capacity of the source vector could be higher.\n let max = crate::cmp::min(Len, MaxLen);\n\n // Save the last item in case we have to do a fixup on an already full array.\n let last = if MaxLen > 0 {\n self.storage[MaxLen - 1]\n } else {\n crate::mem::zeroed()\n };\n\n for src in 0..max {\n // Since we are iterating to the static capacity of the arrays,\n // the destination could be out of bounds. If that's the case,\n // overwrite the last item, which we'll fixup in the end.\n // NB using cmp::min resulted in more opcodes here.\n let mut dst = self.len + src;\n if dst >= MaxLen { dst = MaxLen - 1; };\n // Assigning the source or zeroed to avoid having to merge arrays in SSA.\n self.storage[dst] = if src < append_len {\n vec.get_unchecked(src)\n } else {\n last\n }\n }\n\n // Fixup the last item if we have to.\n if MaxLen > 0 {\n self.storage[MaxLen - 1] = if (self.len + append_len == MaxLen) & (append_len > 0) {\n vec.get_unchecked(append_len - 1)\n } else {\n last\n }\n }\n }\n self.len = new_len;\n }\n\n /// Creates a new vector, populating it with values derived from an array input.\n /// The maximum length of the vector is determined based on the type signature.\n ///\n /// Example:\n ///\n /// ```noir\n /// let bounded_vec: BoundedVec = BoundedVec::from_array([1, 2, 3])\n /// ```\n pub fn from_array(array: [T; Len]) -> Self {\n static_assert(Len <= MaxLen, \"from array out of bounds\");\n let mut vec: BoundedVec = BoundedVec::new();\n vec.extend_from_array(array);\n vec\n }\n\n /// Pops the element at the end of the vector. This will decrease the length\n /// of the vector by one.\n ///\n /// Panics if the vector is empty.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.push(1);\n /// v.push(2);\n ///\n /// let two = v.pop();\n /// let one = v.pop();\n ///\n /// assert(two == 2);\n /// assert(one == 1);\n ///\n /// // error: cannot pop from an empty vector\n /// let _ = v.pop();\n /// ```\n pub fn pop(&mut self) -> T {\n assert(self.len > 0, \"cannot pop from an empty vector\");\n self.len -= 1;\n\n let elem = self.storage[self.len];\n self.storage[self.len] = crate::mem::zeroed();\n elem\n }\n\n /// Returns true if the given predicate returns true for any element\n /// in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let mut v: BoundedVec = BoundedVec::new();\n /// v.extend_from_array([2, 4, 6]);\n ///\n /// let all_even = !v.any(|elem: u32| elem % 2 != 0);\n /// assert(all_even);\n /// ```\n pub fn any(self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n if is_unconstrained() {\n for i in 0..self.len {\n ret |= predicate(self.storage[i]);\n }\n } else {\n let mut exceeded_len = false;\n for i in 0..MaxLen {\n exceeded_len |= i == self.len;\n if !exceeded_len {\n ret |= predicate(self.storage[i]);\n }\n }\n }\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.map(|value| value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn map(&self, f: fn[Env](T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Creates a new vector of equal size by calling a closure on each element\n /// in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let result = vec.mapi(|i, value| i + value * 2);\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn mapi(&self, f: fn[Env](u32, T) -> U) -> BoundedVec {\n let mut ret = BoundedVec::new();\n ret.len = self.len();\n\n if is_unconstrained() {\n for i in 0..self.len() {\n ret.storage[i] = f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n ret.storage[i] = if i < self.len() {\n f(i, self.get_unchecked(i))\n } else {\n crate::mem::zeroed()\n }\n }\n }\n\n ret\n }\n\n /// Calls a closure on each element in this vector.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_each(|value| result.push(value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 4, 6, 8]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_each(&self, f: fn[Env](T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Calls a closure on each element in this vector, along with its index.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n /// let mut result = BoundedVec::::new();\n /// vec.for_eachi(|i, value| result.push(i + value * 2));\n ///\n /// let expected = BoundedVec::from_array([2, 5, 8, 11]);\n /// assert_eq(result, expected);\n /// ```\n pub fn for_eachi(&self, f: fn[Env](u32, T) -> ()) {\n if is_unconstrained() {\n for i in 0..self.len() {\n f(i, self.get_unchecked(i));\n }\n } else {\n for i in 0..MaxLen {\n if i < self.len() {\n f(i, self.get_unchecked(i));\n }\n }\n }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function will zero out any elements at or past index `len` of `array`.\n /// This incurs an extra runtime cost of O(MaxLen). If you are sure your array is\n /// zeroed after that index, you can use [`from_parts_unchecked`][Self::from_parts_unchecked] to remove the extra loop.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n /// ```\n pub fn from_parts(mut array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n let zeroed = crate::mem::zeroed();\n\n if is_unconstrained() {\n for i in len..MaxLen {\n array[i] = zeroed;\n }\n } else {\n for i in 0..MaxLen {\n if i >= len {\n array[i] = zeroed;\n }\n }\n }\n\n BoundedVec { storage: array, len }\n }\n\n /// Creates a new BoundedVec from the given array and length.\n /// The given length must be less than or equal to the length of the array.\n ///\n /// This function is unsafe because it expects all elements past the `len` index\n /// of `array` to be zeroed, but does not check for this internally. Use `from_parts`\n /// for a safe version of this function which does zero out any indices past the\n /// given length. Invalidating this assumption can notably cause `BoundedVec::eq`\n /// to give incorrect results since it will check even elements past `len`.\n ///\n /// Example:\n ///\n /// ```noir\n /// let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n /// assert_eq(vec.len(), 3);\n ///\n /// // invalid use!\n /// let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n /// let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n ///\n /// // both vecs have length 3 so we'd expect them to be equal, but this\n /// // fails because elements past the length are still checked in eq\n /// assert_eq(vec1, vec2); // fails\n /// ```\n pub fn from_parts_unchecked(array: [T; MaxLen], len: u32) -> Self {\n assert(len <= MaxLen);\n BoundedVec { storage: array, len }\n }\n}\n\nimpl Eq for BoundedVec\nwhere\n T: Eq,\n{\n fn eq(self, other: BoundedVec) -> bool {\n // TODO: https://github.com/noir-lang/noir/issues/4837\n //\n // We make the assumption that the user has used the proper interface for working with `BoundedVec`s\n // rather than directly manipulating the internal fields as this can result in an inconsistent internal state.\n if self.len == other.len {\n self.storage == other.storage\n } else {\n false\n }\n }\n}\n\nimpl From<[T; Len]> for BoundedVec {\n fn from(array: [T; Len]) -> BoundedVec {\n BoundedVec::from_array(array)\n }\n}\n\nmod bounded_vec_tests {\n\n mod get {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_elements_past_end_of_vec() {\n let vec: BoundedVec = BoundedVec::new();\n\n let _ = vec.get(0);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn panics_when_reading_beyond_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let _ = vec.get(3);\n }\n\n #[test]\n fn get_works_within_bounds() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(2), 3);\n assert_eq(vec.get(4), 5);\n }\n\n #[test]\n fn get_unchecked_works() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(0), 1);\n assert_eq(vec.get_unchecked(2), 3);\n }\n\n #[test]\n fn get_unchecked_works_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n assert_eq(vec.get_unchecked(4), 0);\n }\n }\n\n mod set {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn set_updates_values_properly() {\n let mut vec = BoundedVec::from_array([0, 0, 0, 0, 0]);\n\n vec.set(0, 42);\n assert_eq(vec.storage, [42, 0, 0, 0, 0]);\n\n vec.set(1, 43);\n assert_eq(vec.storage, [42, 43, 0, 0, 0]);\n\n vec.set(2, 44);\n assert_eq(vec.storage, [42, 43, 44, 0, 0]);\n\n vec.set(1, 10);\n assert_eq(vec.storage, [42, 10, 44, 0, 0]);\n\n vec.set(0, 0);\n assert_eq(vec.storage, [0, 10, 44, 0, 0]);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_writing_elements_past_end_of_vec() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.set(0, 42);\n }\n\n #[test(should_fail_with = \"Attempted to write past end of BoundedVec\")]\n fn panics_when_setting_beyond_length() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.set(3, 4);\n }\n\n #[test]\n fn set_unchecked_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(0, 10);\n assert_eq(vec.get(0), 10);\n }\n\n #[test(should_fail_with = \"Attempted to read past end of BoundedVec\")]\n fn set_unchecked_operations_past_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n vec.set_unchecked(3, 40);\n assert_eq(vec.get(3), 40);\n }\n\n #[test]\n fn set_preserves_other_elements() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n vec.set(2, 30);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 30);\n assert_eq(vec.get(3), 4);\n assert_eq(vec.get(4), 5);\n }\n }\n\n mod any {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn returns_false_if_predicate_not_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, false, false]);\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn returns_true_if_predicate_satisfied() {\n let vec: BoundedVec = BoundedVec::from_array([false, false, true, true]);\n let result = vec.any(|value| value);\n\n assert(result);\n }\n\n #[test]\n fn returns_false_on_empty_boundedvec() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.any(|value| value);\n\n assert(!result);\n }\n\n #[test]\n fn any_with_complex_predicates() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n\n assert(vec.any(|x| x > 3));\n assert(!vec.any(|x| x > 10));\n assert(vec.any(|x| x % 2 == 0)); // has a even number\n assert(vec.any(|x| x == 3)); // has a specific value\n }\n\n #[test]\n fn any_with_partial_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n\n assert(vec.any(|x| x == 1));\n assert(vec.any(|x| x == 2));\n assert(!vec.any(|x| x == 3));\n }\n }\n\n mod map {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-map-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| value * 2);\n // docs:end:bounded-vec-map-example\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.map(|value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn map_with_conditional_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.map(|x| if x % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([1, 4, 3, 8]);\n assert_eq(result, expected);\n }\n\n #[test]\n fn map_preserves_length() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.map(|x| x * 2);\n\n assert_eq(result.len(), vec.len());\n assert_eq(result.max_len(), vec.max_len());\n }\n\n #[test]\n fn map_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let result = vec.map(|x| x * 2);\n assert_eq(result, vec);\n assert_eq(result.len(), 0);\n assert_eq(result.max_len(), 5);\n }\n }\n\n mod mapi {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn applies_function_correctly() {\n // docs:start:bounded-vec-mapi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| i + value * 2);\n // docs:end:bounded-vec-mapi-example\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = vec.mapi(|i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = vec.mapi(|_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn mapi_with_index_branching_logic() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n\n let result = vec.mapi(|i, x| if i % 2 == 0 { x * 2 } else { x });\n let expected = BoundedVec::from_array([2, 2, 6, 4]);\n assert_eq(result, expected);\n }\n }\n\n mod for_each {\n use crate::collections::bounded_vec::BoundedVec;\n\n // map in terms of for_each\n fn for_each_map(\n input: BoundedVec,\n f: fn[Env](T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_each(|x| output_ref.push(f(x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-each-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_each(|value| { *acc_ref += value; });\n // docs:end:bounded-vec-for-each-example\n assert_eq(acc, 6);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| value * 2);\n let expected = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_each_map(vec, |value| (value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 4, 6, 8]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_each_map(vec, |value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_each_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_each(|_| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_each_with_side_effects() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let mut seen = BoundedVec::::new();\n let seen_ref = &mut seen;\n vec.for_each(|x| seen_ref.push(x));\n assert_eq(seen, vec);\n }\n }\n\n mod for_eachi {\n use crate::collections::bounded_vec::BoundedVec;\n\n // mapi in terms of for_eachi\n fn for_eachi_mapi(\n input: BoundedVec,\n f: fn[Env](u32, T) -> U,\n ) -> BoundedVec {\n let mut output = BoundedVec::::new();\n let output_ref = &mut output;\n input.for_eachi(|i, x| output_ref.push(f(i, x)));\n output\n }\n\n #[test]\n fn smoke_test() {\n let mut acc = 0;\n let acc_ref = &mut acc;\n // docs:start:bounded-vec-for-eachi-example\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n vec.for_eachi(|i, value| { *acc_ref += i * value; });\n // docs:end:bounded-vec-for-eachi-example\n\n // 0 * 1 + 1 * 2 + 2 * 3\n assert_eq(acc, 8);\n }\n\n #[test]\n fn applies_function_correctly() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| i + value * 2);\n let expected = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn applies_function_that_changes_return_type() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3, 4]);\n let result = for_eachi_mapi(vec, |i, value| (i + value * 2) as Field);\n let expected: BoundedVec = BoundedVec::from_array([2, 5, 8, 11]);\n\n assert_eq(result, expected);\n }\n\n #[test]\n fn does_not_apply_function_past_len() {\n let vec: BoundedVec = BoundedVec::from_array([0, 1]);\n let result = for_eachi_mapi(vec, |_, value| if value == 0 { 5 } else { value });\n let expected = BoundedVec::from_array([5, 1]);\n\n assert_eq(result, expected);\n assert_eq(result.get_unchecked(2), 0);\n }\n\n #[test]\n fn for_eachi_on_empty_vector() {\n let vec: BoundedVec = BoundedVec::new();\n let mut count = 0;\n let count_ref = &mut count;\n vec.for_eachi(|_, _| { *count_ref += 1; });\n assert_eq(count, 0);\n }\n\n #[test]\n fn for_eachi_with_index_tracking() {\n let vec: BoundedVec = BoundedVec::from_array([10, 20, 30]);\n let mut indices = BoundedVec::::new();\n let indices_ref = &mut indices;\n vec.for_eachi(|i, _| indices_ref.push(i));\n\n let expected = BoundedVec::from_array([0, 1, 2]);\n assert_eq(indices, expected);\n }\n\n }\n\n mod from_array {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty() {\n let empty_array: [Field; 0] = [];\n let bounded_vec = BoundedVec::from_array([]);\n\n assert_eq(bounded_vec.max_len(), 0);\n assert_eq(bounded_vec.len(), 0);\n assert_eq(bounded_vec.storage(), empty_array);\n }\n\n #[test]\n fn equal_len() {\n let array = [1, 2, 3];\n let bounded_vec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 3);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.storage(), array);\n }\n\n #[test]\n fn max_len_greater_then_array_len() {\n let array = [1, 2, 3];\n let bounded_vec: BoundedVec = BoundedVec::from_array(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 3);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n assert_eq(bounded_vec.get(2), 3);\n }\n\n #[test(should_fail_with = \"from array out of bounds\")]\n fn max_len_lower_then_array_len() {\n let _: BoundedVec = BoundedVec::from_array([0; 3]);\n }\n\n #[test]\n fn from_array_preserves_order() {\n let array = [5, 3, 1, 4, 2];\n let vec: BoundedVec = BoundedVec::from_array(array);\n for i in 0..array.len() {\n assert_eq(vec.get(i), array[i]);\n }\n }\n\n #[test]\n fn from_array_with_different_types() {\n let bool_array = [true, false, true];\n let bool_vec: BoundedVec = BoundedVec::from_array(bool_array);\n assert_eq(bool_vec.len(), 3);\n assert_eq(bool_vec.get(0), true);\n assert_eq(bool_vec.get(1), false);\n }\n }\n\n mod trait_from {\n use crate::collections::bounded_vec::BoundedVec;\n use crate::convert::From;\n\n #[test]\n fn simple() {\n let array = [1, 2];\n let bounded_vec: BoundedVec = BoundedVec::from(array);\n\n assert_eq(bounded_vec.max_len(), 10);\n assert_eq(bounded_vec.len(), 2);\n assert_eq(bounded_vec.get(0), 1);\n assert_eq(bounded_vec.get(1), 2);\n }\n }\n\n mod trait_eq {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn empty_equality() {\n let bounded_vec1: BoundedVec = BoundedVec::new();\n let bounded_vec2: BoundedVec = BoundedVec::new();\n\n assert_eq(bounded_vec1, bounded_vec2);\n }\n\n #[test]\n fn inequality() {\n let mut bounded_vec1: BoundedVec = BoundedVec::new();\n let mut bounded_vec2: BoundedVec = BoundedVec::new();\n bounded_vec1.push(1);\n bounded_vec2.push(2);\n\n assert(bounded_vec1 != bounded_vec2);\n }\n }\n\n mod from_parts {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn from_parts() {\n // docs:start:from-parts\n let vec: BoundedVec = BoundedVec::from_parts([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // Any elements past the given length are zeroed out, so these\n // two BoundedVecs will be completely equal\n let vec1: BoundedVec = BoundedVec::from_parts([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts([1, 2, 3, 2], 3);\n assert_eq(vec1, vec2);\n // docs:end:from-parts\n }\n\n #[test]\n fn from_parts_unchecked() {\n // docs:start:from-parts-unchecked\n let vec: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 0], 3);\n assert_eq(vec.len(), 3);\n\n // invalid use!\n let vec1: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 1], 3);\n let vec2: BoundedVec = BoundedVec::from_parts_unchecked([1, 2, 3, 2], 3);\n\n // both vecs have length 3 so we'd expect them to be equal, but this\n // fails because elements past the length are still checked in eq\n assert(vec1 != vec2);\n // docs:end:from-parts-unchecked\n }\n }\n\n mod push_pop {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn push_and_pop_operations() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n assert_eq(vec.len(), 0);\n\n vec.push(1);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 1);\n\n vec.push(2);\n assert_eq(vec.len(), 2);\n assert_eq(vec.get(1), 2);\n\n let popped = vec.pop();\n assert_eq(popped, 2);\n assert_eq(vec.len(), 1);\n\n let popped2 = vec.pop();\n assert_eq(popped2, 1);\n assert_eq(vec.len(), 0);\n }\n\n #[test(should_fail_with = \"push out of bounds\")]\n fn push_to_full_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.push(2);\n vec.push(3); // should panic\n }\n\n #[test(should_fail_with = \"cannot pop from an empty vector\")]\n fn pop_from_empty_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n let _ = vec.pop(); // should panic\n }\n\n #[test]\n fn push_pop_cycle() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // push to full\n vec.push(1);\n vec.push(2);\n vec.push(3);\n assert_eq(vec.len(), 3);\n\n // pop all\n assert_eq(vec.pop(), 3);\n assert_eq(vec.pop(), 2);\n assert_eq(vec.pop(), 1);\n assert_eq(vec.len(), 0);\n\n // push again\n vec.push(4);\n assert_eq(vec.len(), 1);\n assert_eq(vec.get(0), 4);\n }\n }\n\n mod extend {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn extend_from_array() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3]);\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_vector() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3].as_vector());\n\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec() {\n // The source deliberately has a higher capacity,\n // to make sure we are not trying to assign out-of-bounds.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_limit() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec2.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_full_and_empty() {\n // Capacity and contents chosen so the last item must be assigned to.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 2);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n }\n\n #[test]\n fn extend_from_bounded_vec_zero_len() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::new();\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_last_zeroed() {\n let mut vec1: BoundedVec = BoundedVec::new();\n let mut vec2: BoundedVec = BoundedVec::new();\n\n vec1.push(1);\n vec1.push(2);\n vec2.push(3);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get_unchecked(3), 0);\n }\n\n #[test]\n fn extend_from_bounded_vec_empty_self() {\n // self.len == 0 with Len > MaxLen: the loop doesn't reach\n // the last storage slot, so the fixup must write it.\n let mut vec1: BoundedVec = BoundedVec::new();\n let vec2: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 3);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n }\n\n #[test]\n fn extend_from_bounded_vec_equal_capacity() {\n // Len == MaxLen, fills to capacity.\n let mut vec1: BoundedVec = BoundedVec::new();\n vec1.push(1);\n let vec2: BoundedVec = BoundedVec::from_array([2, 3, 4]);\n\n vec1.extend_from_bounded_vec(vec2);\n\n assert_eq(vec1.len(), 4);\n assert_eq(vec1.get(0), 1);\n assert_eq(vec1.get(1), 2);\n assert_eq(vec1.get(2), 3);\n assert_eq(vec1.get(3), 4);\n }\n\n #[test(should_fail_with = \"extend_from_array out of bounds\")]\n fn extend_array_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_array([2, 3, 4]); // should panic\n }\n\n #[test(should_fail_with = \"extend_from_vector out of bounds\")]\n fn extend_vector_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n vec.push(1);\n vec.extend_from_vector([2, 3, 4].as_vector()); // S]should panic\n }\n\n #[test(should_fail_with = \"extend_from_bounded_vec out of bounds\")]\n fn extend_bounded_vec_beyond_max_len() {\n let mut vec: BoundedVec = BoundedVec::new();\n let other: BoundedVec = BoundedVec::from_array([1, 2, 3, 4, 5]);\n vec.extend_from_bounded_vec(other); // should panic\n }\n\n #[test]\n fn extend_with_empty_collections() {\n let mut vec: BoundedVec = BoundedVec::new();\n let original_len = vec.len();\n\n vec.extend_from_array([]);\n assert_eq(vec.len(), original_len);\n\n vec.extend_from_vector([].as_vector());\n assert_eq(vec.len(), original_len);\n\n let empty: BoundedVec = BoundedVec::new();\n vec.extend_from_bounded_vec(empty);\n assert_eq(vec.len(), original_len);\n }\n }\n\n mod storage {\n use crate::collections::bounded_vec::BoundedVec;\n\n #[test]\n fn storage_consistency() {\n let mut vec: BoundedVec = BoundedVec::new();\n\n // test initial storage state\n assert_eq(vec.storage(), [0, 0, 0, 0, 0]);\n\n vec.push(1);\n vec.push(2);\n\n // test storage after modifications\n assert_eq(vec.storage(), [1, 2, 0, 0, 0]);\n\n // storage doesn't change length\n assert_eq(vec.len(), 2);\n assert_eq(vec.max_len(), 5);\n }\n\n #[test]\n fn storage_after_pop() {\n let mut vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n\n let _ = vec.pop();\n // after pop, the last element should be zeroed\n assert_eq(vec.storage(), [1, 2, 0]);\n assert_eq(vec.len(), 2);\n }\n\n #[test]\n fn vector_immutable() {\n let vec: BoundedVec = BoundedVec::from_array([1, 2, 3]);\n let storage = vec.storage();\n\n assert_eq(storage, [1, 2, 3]);\n\n // Verify that the original vector is unchanged\n assert_eq(vec.len(), 3);\n assert_eq(vec.get(0), 1);\n assert_eq(vec.get(1), 2);\n assert_eq(vec.get(2), 3);\n }\n }\n}\n","path":"std/collections/bounded_vec.nr","function_locations":[{"start":2599,"name":"BoundedVec::new"},{"start":3202,"name":"BoundedVec::get"},{"start":4110,"name":"BoundedVec::get_unchecked"},{"start":4693,"name":"BoundedVec::set"},{"start":6221,"name":"BoundedVec::set_unchecked"},{"start":6759,"name":"BoundedVec::push"},{"start":7367,"name":"BoundedVec::len"},{"start":7808,"name":"BoundedVec::max_len"},{"start":8407,"name":"BoundedVec::storage"},{"start":8963,"name":"BoundedVec::extend_from_array"},{"start":9734,"name":"BoundedVec::extend_from_vector"},{"start":10679,"name":"BoundedVec::extend_from_bounded_vec"},{"start":13074,"name":"BoundedVec::from_array"},{"start":13817,"name":"BoundedVec::pop"},{"start":14440,"name":"BoundedVec::any"},{"start":15356,"name":"BoundedVec::map"},{"start":16356,"name":"BoundedVec::mapi"},{"start":17314,"name":"BoundedVec::for_each"},{"start":18119,"name":"BoundedVec::for_eachi"},{"start":19118,"name":"BoundedVec::from_parts"},{"start":20767,"name":"BoundedVec::from_parts_unchecked"},{"start":20979,"name":">::eq"},{"start":21550,"name":" for BoundedVec>::from"},{"start":21833,"name":"bounded_vec_tests::get::panics_when_reading_elements_past_end_of_vec"},{"start":22068,"name":"bounded_vec_tests::get::panics_when_reading_beyond_length"},{"start":22243,"name":"bounded_vec_tests::get::get_works_within_bounds"},{"start":22502,"name":"bounded_vec_tests::get::get_unchecked_works"},{"start":22746,"name":"bounded_vec_tests::get::get_unchecked_works_past_len"},{"start":23019,"name":"bounded_vec_tests::set::set_updates_values_properly"},{"start":23657,"name":"bounded_vec_tests::set::panics_when_writing_elements_past_end_of_vec"},{"start":23892,"name":"bounded_vec_tests::set::panics_when_setting_beyond_length"},{"start":24067,"name":"bounded_vec_tests::set::set_unchecked_operations"},{"start":24399,"name":"bounded_vec_tests::set::set_unchecked_operations_past_len"},{"start":24663,"name":"bounded_vec_tests::set::set_preserves_other_elements"},{"start":25131,"name":"bounded_vec_tests::any::returns_false_if_predicate_not_satisfied"},{"start":25385,"name":"bounded_vec_tests::any::returns_true_if_predicate_satisfied"},{"start":25634,"name":"bounded_vec_tests::any::returns_false_on_empty_boundedvec"},{"start":25845,"name":"bounded_vec_tests::any::any_with_complex_predicates"},{"start":26208,"name":"bounded_vec_tests::any::any_with_partial_vector"},{"start":26595,"name":"bounded_vec_tests::map::applies_function_correctly"},{"start":27017,"name":"bounded_vec_tests::map::applies_function_that_changes_return_type"},{"start":27365,"name":"bounded_vec_tests::map::does_not_apply_function_past_len"},{"start":27738,"name":"bounded_vec_tests::map::map_with_conditional_logic"},{"start":28062,"name":"bounded_vec_tests::map::map_preserves_length"},{"start":28354,"name":"bounded_vec_tests::map::map_on_empty_vector"},{"start":28728,"name":"bounded_vec_tests::mapi::applies_function_correctly"},{"start":29161,"name":"bounded_vec_tests::mapi::applies_function_that_changes_return_type"},{"start":29518,"name":"bounded_vec_tests::mapi::does_not_apply_function_past_len"},{"start":29900,"name":"bounded_vec_tests::mapi::mapi_with_index_branching_logic"},{"start":30459,"name":"bounded_vec_tests::for_each::for_each_map"},{"start":30689,"name":"bounded_vec_tests::for_each::smoke_test"},{"start":31097,"name":"bounded_vec_tests::for_each::applies_function_correctly"},{"start":31431,"name":"bounded_vec_tests::for_each::applies_function_that_changes_return_type"},{"start":31789,"name":"bounded_vec_tests::for_each::does_not_apply_function_past_len"},{"start":32170,"name":"bounded_vec_tests::for_each::for_each_on_empty_vector"},{"start":32456,"name":"bounded_vec_tests::for_each::for_each_with_side_effects"},{"start":33013,"name":"bounded_vec_tests::for_eachi::for_eachi_mapi"},{"start":33250,"name":"bounded_vec_tests::for_eachi::smoke_test"},{"start":33706,"name":"bounded_vec_tests::for_eachi::applies_function_correctly"},{"start":34050,"name":"bounded_vec_tests::for_eachi::applies_function_that_changes_return_type"},{"start":34418,"name":"bounded_vec_tests::for_eachi::does_not_apply_function_past_len"},{"start":34805,"name":"bounded_vec_tests::for_eachi::for_eachi_on_empty_vector"},{"start":35098,"name":"bounded_vec_tests::for_eachi::for_eachi_with_index_tracking"},{"start":35575,"name":"bounded_vec_tests::from_array::empty"},{"start":35885,"name":"bounded_vec_tests::from_array::equal_len"},{"start":36202,"name":"bounded_vec_tests::from_array::max_len_greater_then_array_len"},{"start":36673,"name":"bounded_vec_tests::from_array::max_len_lower_then_array_len"},{"start":36816,"name":"bounded_vec_tests::from_array::from_array_preserves_order"},{"start":37105,"name":"bounded_vec_tests::from_array::from_array_with_different_types"},{"start":37542,"name":"bounded_vec_tests::trait_from::simple"},{"start":37980,"name":"bounded_vec_tests::trait_eq::empty_equality"},{"start":38229,"name":"bounded_vec_tests::trait_eq::inequality"},{"start":38638,"name":"bounded_vec_tests::from_parts::from_parts"},{"start":39228,"name":"bounded_vec_tests::from_parts::from_parts_unchecked"},{"start":40010,"name":"bounded_vec_tests::push_pop::push_and_pop_operations"},{"start":40636,"name":"bounded_vec_tests::push_pop::push_to_full_vector"},{"start":40910,"name":"bounded_vec_tests::push_pop::pop_from_empty_vector"},{"start":41079,"name":"bounded_vec_tests::push_pop::push_pop_cycle"},{"start":41725,"name":"bounded_vec_tests::extend::extend_from_array"},{"start":42071,"name":"bounded_vec_tests::extend::extend_from_vector"},{"start":42435,"name":"bounded_vec_tests::extend::extend_from_bounded_vec"},{"start":43056,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_limit"},{"start":43570,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_full_and_empty"},{"start":44074,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_zero_len"},{"start":44368,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_last_zeroed"},{"start":44793,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_empty_self"},{"start":45360,"name":"bounded_vec_tests::extend::extend_from_bounded_vec_equal_capacity"},{"start":45947,"name":"bounded_vec_tests::extend::extend_array_beyond_max_len"},{"start":46225,"name":"bounded_vec_tests::extend::extend_vector_beyond_max_len"},{"start":46528,"name":"bounded_vec_tests::extend::extend_bounded_vec_beyond_max_len"},{"start":46814,"name":"bounded_vec_tests::extend::extend_with_empty_collections"},{"start":47414,"name":"bounded_vec_tests::storage::storage_consistency"},{"start":47916,"name":"bounded_vec_tests::storage::storage_after_pop"},{"start":48234,"name":"bounded_vec_tests::storage::vector_immutable"}]},"16":{"source":"use crate::field::field_less_than;\nuse crate::runtime::is_unconstrained;\n\n// The low and high decomposition of the field modulus\npub(crate) global PLO: Field = 53438638232309528389504892708671455233;\npub(crate) global PHI: Field = 64323764613183177041862057485226039389;\n\npub(crate) global TWO_POW_128: Field = 0x100000000000000000000000000000000;\n\n// Decomposes a single field into two 16 byte fields.\nfn compute_decomposition(x: Field) -> (Field, Field) {\n // Here's we're taking advantage of truncating 128 bit limbs from the input field\n // and then subtracting them from the input such the field division is equivalent to integer division.\n let low = (x as u128) as Field;\n let high = (x - low) / TWO_POW_128;\n\n (low, high)\n}\n\npub(crate) unconstrained fn decompose_hint(x: Field) -> (Field, Field) {\n compute_decomposition(x)\n}\n\nunconstrained fn lte_hint(x: Field, y: Field) -> bool {\n if x == y {\n true\n } else {\n field_less_than(x, y)\n }\n}\n\n// Assert that (alo > blo && ahi >= bhi) || (alo <= blo && ahi > bhi)\nfn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) {\n let (alo, ahi) = a;\n let (blo, bhi) = b;\n // Safety: borrow is enforced to be boolean due to its type.\n // if borrow is 0, it asserts that (alo > blo && ahi >= bhi)\n // if borrow is 1, it asserts that (alo <= blo && ahi > bhi)\n unsafe {\n let borrow = lte_hint(alo, blo);\n\n let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128;\n let rhi = ahi - bhi - (borrow as Field);\n\n rlo.assert_max_bit_size::<128>();\n rhi.assert_max_bit_size::<128>();\n }\n}\n\n/// Decompose a single field into two 16 byte fields.\npub fn decompose(x: Field) -> (Field, Field) {\n if is_unconstrained() {\n compute_decomposition(x)\n } else {\n // Safety: decomposition is properly checked below\n unsafe {\n // Take hints of the decomposition\n let (xlo, xhi) = decompose_hint(x);\n\n // Range check the limbs\n xlo.assert_max_bit_size::<128>();\n xhi.assert_max_bit_size::<128>();\n\n // Check that the decomposition is correct\n assert_eq(x, xlo + TWO_POW_128 * xhi);\n\n // Assert that the decomposition of P is greater than the decomposition of x\n assert_gt_limbs((PLO, PHI), (xlo, xhi));\n (xlo, xhi)\n }\n }\n}\n\npub fn assert_gt(a: Field, b: Field) {\n if is_unconstrained() {\n assert(\n // Safety: already unconstrained\n unsafe { field_less_than(b, a) },\n );\n } else {\n // Decompose a and b\n let a_limbs = decompose(a);\n let b_limbs = decompose(b);\n\n // Assert that a_limbs is greater than b_limbs\n assert_gt_limbs(a_limbs, b_limbs)\n }\n}\n\npub fn assert_lt(a: Field, b: Field) {\n assert_gt(b, a);\n}\n\npub fn gt(a: Field, b: Field) -> bool {\n if is_unconstrained() {\n // Safety: unsafe in unconstrained\n unsafe {\n field_less_than(b, a)\n }\n } else if a == b {\n false\n } else {\n // Safety: Take a hint of the comparison and verify it\n unsafe {\n if field_less_than(a, b) {\n assert_gt(b, a);\n false\n } else {\n assert_gt(a, b);\n true\n }\n }\n }\n}\n\npub fn lt(a: Field, b: Field) -> bool {\n gt(b, a)\n}\n\nmod tests {\n // TODO: Allow imports from \"super\"\n use crate::field::bn254::{assert_gt, decompose, gt, lt, lte_hint, PHI, PLO, TWO_POW_128};\n\n #[test]\n fn check_decompose() {\n assert_eq(decompose(TWO_POW_128), (0, 1));\n assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1));\n assert_eq(decompose(0x1234567890), (0x1234567890, 0));\n }\n\n #[test]\n unconstrained fn check_lte_hint() {\n assert(lte_hint(0, 1));\n assert(lte_hint(0, 0x100));\n assert(lte_hint(0x100, TWO_POW_128 - 1));\n assert(!lte_hint(0 - 1, 0));\n\n assert(lte_hint(0, 0));\n assert(lte_hint(0x100, 0x100));\n assert(lte_hint(0 - 1, 0 - 1));\n }\n\n #[test]\n fn check_gt() {\n assert(gt(1, 0));\n assert(gt(0x100, 0));\n assert(gt((0 - 1), (0 - 2)));\n assert(gt(TWO_POW_128, 0));\n assert(!gt(0, 0));\n assert(!gt(0, 0x100));\n assert(gt(0 - 1, 0 - 2));\n assert(!gt(0 - 2, 0 - 1));\n assert_gt(0 - 1, 0);\n }\n\n #[test]\n fn check_plo_phi() {\n assert_eq(PLO + PHI * TWO_POW_128, 0);\n let p_bytes = crate::field::modulus_le_bytes();\n let mut p_low: Field = 0;\n let mut p_high: Field = 0;\n\n let mut offset = 1;\n for i in 0..16 {\n p_low += (p_bytes[i] as Field) * offset;\n p_high += (p_bytes[i + 16] as Field) * offset;\n offset *= 256;\n }\n assert_eq(p_low, PLO);\n assert_eq(p_high, PHI);\n }\n\n #[test]\n fn check_decompose_edge_cases() {\n assert_eq(decompose(0), (0, 0));\n assert_eq(decompose(TWO_POW_128 - 1), (TWO_POW_128 - 1, 0));\n assert_eq(decompose(TWO_POW_128 + 1), (1, 1));\n assert_eq(decompose(TWO_POW_128 * 2), (0, 2));\n assert_eq(decompose(TWO_POW_128 * 2 + 0x1234567890), (0x1234567890, 2));\n }\n\n #[test]\n fn check_decompose_large_values() {\n let large_field = 0xffffffffffffffff;\n let (lo, hi) = decompose(large_field);\n assert_eq(large_field, lo + TWO_POW_128 * hi);\n\n let large_value = large_field - TWO_POW_128;\n let (lo2, hi2) = decompose(large_value);\n assert_eq(large_value, lo2 + TWO_POW_128 * hi2);\n }\n\n #[test]\n fn check_lt_comprehensive() {\n assert(lt(0, 1));\n assert(!lt(1, 0));\n assert(!lt(0, 0));\n assert(!lt(42, 42));\n\n assert(lt(TWO_POW_128 - 1, TWO_POW_128));\n assert(!lt(TWO_POW_128, TWO_POW_128 - 1));\n }\n}\n","path":"std/field/bn254.nr","function_locations":[{"start":456,"name":"compute_decomposition"},{"start":818,"name":"decompose_hint"},{"start":906,"name":"lte_hint"},{"start":1116,"name":"assert_gt_limbs"},{"start":1725,"name":"decompose"},{"start":2431,"name":"assert_gt"},{"start":2837,"name":"assert_lt"},{"start":2901,"name":"gt"},{"start":3405,"name":"lt"},{"start":3607,"name":"tests::check_decompose"},{"start":3857,"name":"tests::check_lte_hint"},{"start":4164,"name":"tests::check_gt"},{"start":4494,"name":"tests::check_plo_phi"},{"start":4989,"name":"tests::check_decompose_edge_cases"},{"start":5349,"name":"tests::check_decompose_large_values"},{"start":5710,"name":"tests::check_lt_comprehensive"}]},"17":{"source":"pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits(self: Self) -> [bool; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits(self: Self) -> [bool; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [bool; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = false if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = true.\n pub fn sgn0(self) -> bool {\n (self as u8) % 2 == 1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits(value: Field) -> [bool; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits(value: Field) -> [bool; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [bool] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [bool] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_be_bits();\n assert_eq(bits, [false, false, false, false, false, false, true, false]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_le_bits();\n assert_eq(bits, [false, true, false, false, false, false, false, false]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_field.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_val.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [bool; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [false; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [bool; 8] = 1.to_le_bits();\n let expected: [bool; 8] = [true, false, false, false, false, false, false, false];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [bool; 8] = 4.to_le_bits();\n let expected: [bool; 8] = [false, false, true, false, false, false, false, false];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), false);\n assert_eq(2.sgn0(), false);\n assert_eq(4.sgn0(), false);\n assert_eq(100.sgn0(), false);\n\n assert_eq(1.sgn0(), true);\n assert_eq(3.sgn0(), true);\n assert_eq(5.sgn0(), true);\n assert_eq(101.sgn0(), true);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [bool; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits(bits: [bool; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits(bits: [bool; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1]);\n p_minus_1_bits[254 - 1] = false;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(!p_plus_4_bits[254 - 3]);\n p_plus_4_bits[254 - 3] = true;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_be_bits();\n assert(p_plus_4_converted_bits[254 - 3]);\n p_plus_4_converted_bits[254 - 3] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_be_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0]);\n p_minus_1_bits[0] = false;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(!p_plus_4_bits[2]);\n p_plus_4_bits[2] = true;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_le_bits();\n assert(p_plus_4_converted_bits[2]);\n p_plus_4_converted_bits[2] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_le_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n}\n","path":"std/field/mod.nr","function_locations":[{"start":380,"name":"Field::assert_max_bit_size"},{"start":1196,"name":"Field::to_le_bits"},{"start":2387,"name":"Field::to_be_bits"},{"start":3562,"name":"Field::to_le_bytes"},{"start":5033,"name":"Field::to_be_bytes"},{"start":5904,"name":"Field::to_le_radix"},{"start":6362,"name":"Field::to_be_radix"},{"start":7053,"name":"Field::pow_32"},{"start":7455,"name":"Field::sgn0"},{"start":7538,"name":"Field::lt"},{"start":7918,"name":"Field::from_le_bytes"},{"start":8476,"name":"Field::from_be_bytes"},{"start":8757,"name":"__assert_max_bit_size"},{"start":8885,"name":"__to_le_radix"},{"start":9013,"name":"__to_be_radix"},{"start":9734,"name":"__to_le_bits"},{"start":10452,"name":"__to_be_bits"},{"start":10527,"name":"modulus_num_bits"},{"start":10603,"name":"modulus_be_bits"},{"start":10679,"name":"modulus_le_bits"},{"start":10755,"name":"modulus_be_bytes"},{"start":10831,"name":"modulus_le_bytes"},{"start":10992,"name":"__field_less_than"},{"start":11068,"name":"field_less_than"},{"start":11210,"name":"bytes32_to_field"},{"start":11617,"name":"lt_fallback"},{"start":12579,"name":"tests::test_to_be_bits"},{"start":12852,"name":"tests::test_to_le_bits"},{"start":13127,"name":"tests::test_to_be_bytes"},{"start":13433,"name":"tests::test_to_le_bytes"},{"start":13739,"name":"tests::test_to_be_radix"},{"start":14321,"name":"tests::test_to_le_radix"},{"start":14921,"name":"tests::test_to_le_radix_1"},{"start":15374,"name":"tests::test_to_le_radix_brillig_1"},{"start":15728,"name":"tests::test_to_le_radix_3"},{"start":16039,"name":"tests::test_to_le_radix_brillig_3"},{"start":16467,"name":"tests::test_to_le_radix_512"},{"start":16876,"name":"tests::not_enough_limbs_brillig"},{"start":17072,"name":"tests::not_enough_limbs"},{"start":17214,"name":"tests::test_field_less_than"},{"start":17469,"name":"tests::test_large_field_values_unconstrained"},{"start":17922,"name":"tests::test_large_field_values"},{"start":18369,"name":"tests::test_decomposition_edge_cases"},{"start":18959,"name":"tests::test_pow_32"},{"start":19288,"name":"tests::test_sgn0"},{"start":19710,"name":"tests::test_bit_decomposition_overflow"},{"start":19992,"name":"tests::test_byte_decomposition_overflow"},{"start":20209,"name":"tests::test_to_from_be_bytes_bn254_edge_cases"},{"start":22160,"name":"tests::test_to_from_le_bytes_bn254_edge_cases"},{"start":24245,"name":"tests::from_le_bits"},{"start":24792,"name":"tests::from_be_bits"},{"start":25038,"name":"tests::test_to_from_be_bits_bn254_edge_cases"},{"start":26971,"name":"tests::test_to_from_le_bits_bn254_edge_cases"}]},"18":{"source":"// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\nuse crate::static_assert;\n\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated(\"This function has been moved to std::hash::keccakf1600\")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you're working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n \"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n // we use the unsafe version because the multi_scalar_mul will constrain the scalars.\n points[i] = from_field_unsafe(input[i]);\n }\n let generators = derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n crate::assert_constant(separator);\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = from_field_unsafe(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators(\"pedersen_hash_length\".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n crate::assert_constant(starting_index);\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\n#[field(bn254)]\n// Decompose the input 'bn254 scalar' into two 128 bits limbs.\n// It is called 'unsafe' because it does not assert the limbs are 128 bits\n// Assuming the limbs are 128 bits:\n// Assert the decomposition does not overflow the field size.\nfn from_field_unsafe(scalar: Field) -> EmbeddedCurveScalar {\n // Safety: xlo and xhi decomposition is checked below\n let (xlo, xhi) = unsafe { crate::field::bn254::decompose_hint(scalar) };\n // Check that the decomposition is correct\n assert_eq(scalar, xlo + crate::field::bn254::TWO_POW_128 * xhi);\n // Check that the decomposition does not overflow the field size\n let (a, b) = if xhi == crate::field::bn254::PHI {\n (xlo, crate::field::bn254::PLO)\n } else {\n (xhi, crate::field::bn254::PHI)\n };\n crate::field::bn254::assert_lt(a, b);\n\n EmbeddedCurveScalar { lo: xlo, hi: xhi }\n}\n\npub fn poseidon2_permutation(input: [Field; N]) -> [Field; N] {\n static_assert(\n N == POSEIDON2_CONFIG_STATE_SIZE,\n f\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\",\n );\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal(input: [Field; N]) -> [Field; N] {}\n\n#[foreign(poseidon2_config_state_size)]\ncomptime fn poseidon2_config_state_size() -> u32 {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n /// Returns the hash value without consuming the hasher.\n /// Override this for more efficient implementations that avoid copying.\n /// TODO: deprecate finish() and replace it\n fn finish_ref(&self) -> Field {\n (*self).finish()\n }\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault;\n\nimpl BuildHasher for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl Default for BuildHasherDefault\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for [T]\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n },\n );\n}\n","path":"std/hash/mod.nr","function_locations":[{"start":572,"name":"sha256_compression"},{"start":707,"name":"keccakf1600"},{"start":882,"name":"keccak::keccakf1600"},{"start":1044,"name":"blake2s"},{"start":1142,"name":"blake3"},{"start":1629,"name":"__blake3"},{"start":1747,"name":"pedersen_commitment"},{"start":1976,"name":"pedersen_commitment_with_separator"},{"start":2460,"name":"pedersen_hash"},{"start":2617,"name":"pedersen_hash_with_separator"},{"start":3597,"name":"derive_generators"},{"start":3956,"name":"__derive_generators"},{"start":4271,"name":"from_field_unsafe"},{"start":4912,"name":"poseidon2_permutation"},{"start":5268,"name":"poseidon2_permutation_internal"},{"start":5361,"name":"poseidon2_config_state_size"},{"start":5672,"name":"derive_hash"},{"start":6897,"name":">::build_hasher"},{"start":7029,"name":">::default"},{"start":7161,"name":"::hash"},{"start":7291,"name":"::hash"},{"start":7431,"name":"::hash"},{"start":7571,"name":"::hash"},{"start":7711,"name":"::hash"},{"start":7852,"name":"::hash"},{"start":7991,"name":"::hash"},{"start":8137,"name":"::hash"},{"start":8284,"name":"::hash"},{"start":8431,"name":"::hash"},{"start":8579,"name":"::hash"},{"start":8726,"name":"::hash"},{"start":8858,"name":"::hash"},{"start":9047,"name":"::hash"},{"start":9287,"name":"::hash"},{"start":9503,"name":"::hash"},{"start":9766,"name":"::hash"},{"start":10076,"name":"::hash"},{"start":10472,"name":"assert_pedersen"}]},"41":{"source":"use crate::cmp::{Eq, Ord, Ordering};\nuse crate::default::Default;\nuse crate::hash::{Hash, Hasher};\n\n/// Represents a value of type T or its absence.\n/// Use `Option::some(value)` to construct a value or `Option::none()` to record the absence of one.\npub struct Option {\n _is_some: bool,\n _value: T,\n}\n\nimpl Option {\n /// Constructs a None value\n pub fn none() -> Self {\n Self { _is_some: false, _value: crate::mem::zeroed() }\n }\n\n /// Constructs a Some wrapper around the given value\n pub fn some(_value: T) -> Self {\n Self { _is_some: true, _value }\n }\n\n /// True if this Option is None\n pub fn is_none(&self) -> bool {\n !self._is_some\n }\n\n /// True if this Option is Some\n pub fn is_some(&self) -> bool {\n self._is_some\n }\n\n /// Asserts `self.is_some()` and returns the wrapped value.\n pub fn unwrap(self) -> T {\n assert(self._is_some);\n self._value\n }\n\n /// Returns the inner value without asserting `self.is_some()`\n /// Note that if `self` is `None`, there is no guarantee what value will be returned,\n /// only that it will be of type `T`.\n pub fn unwrap_unchecked(self) -> T {\n self._value\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.\n pub fn unwrap_or(self, default: T) -> T {\n if self._is_some {\n self._value\n } else {\n default\n }\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return\n /// a default value.\n pub fn unwrap_or_else(self, default: fn[Env]() -> T) -> T {\n if self._is_some {\n self._value\n } else {\n default()\n }\n }\n\n /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value\n pub fn expect(self, message: fmtstr) -> T {\n assert(self.is_some(), message);\n self._value\n }\n\n /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.\n pub fn map(self, f: fn[Env](T) -> U) -> Option {\n if self._is_some {\n Option::some(f(self._value))\n } else {\n Option::none()\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.\n pub fn map_or(self, default: U, f: fn[Env](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.\n pub fn map_or_else(self, default: fn[Env1]() -> U, f: fn[Env2](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default()\n }\n }\n\n /// Returns None if self is None. Otherwise, this returns `other`.\n pub fn and(self, other: Self) -> Self {\n if self.is_none() {\n Option::none()\n } else {\n other\n }\n }\n\n /// If self is None, this returns None. Otherwise, this calls the given function\n /// with the Some value contained within self, and returns the result of that call.\n ///\n /// In some languages this function is called `flat_map` or `bind`.\n pub fn and_then(self, f: fn[Env](T) -> Option) -> Option {\n if self._is_some {\n f(self._value)\n } else {\n Option::none()\n }\n }\n\n /// If self is Some, return self. Otherwise, return `other`.\n pub fn or(self, other: Self) -> Self {\n if self._is_some {\n self\n } else {\n other\n }\n }\n\n /// If self is Some, return self. Otherwise, return `default()`.\n pub fn or_else(self, default: fn[Env]() -> Self) -> Self {\n if self._is_some {\n self\n } else {\n default()\n }\n }\n\n // If only one of the two Options is Some, return that option.\n // Otherwise, if both options are Some or both are None, None is returned.\n pub fn xor(self, other: Self) -> Self {\n if self._is_some {\n if other._is_some {\n Option::none()\n } else {\n self\n }\n } else if other._is_some {\n other\n } else {\n Option::none()\n }\n }\n\n /// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.\n /// Otherwise, this returns `None`\n pub fn filter(self, predicate: fn[Env](T) -> bool) -> Self {\n if self._is_some {\n if predicate(self._value) {\n self\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n }\n\n /// Flattens an Option> into a Option.\n /// This returns None if the outer Option is None. Otherwise, this returns the inner Option.\n pub fn flatten(option: Option>) -> Option {\n if option._is_some {\n option._value\n } else {\n Option::none()\n }\n }\n}\n\nimpl Default for Option {\n fn default() -> Self {\n Option::none()\n }\n}\n\nimpl Eq for Option\nwhere\n T: Eq,\n{\n fn eq(self, other: Self) -> bool {\n if self._is_some == other._is_some {\n if self._is_some {\n self._value == other._value\n } else {\n true\n }\n } else {\n false\n }\n }\n}\n\nimpl Hash for Option\nwhere\n T: Hash,\n{\n fn hash(self, state: &mut H)\n where\n H: Hasher,\n {\n self._is_some.hash(state);\n if self._is_some {\n self._value.hash(state);\n }\n }\n}\n\n// For this impl we're declaring Option::none < Option::some\nimpl Ord for Option\nwhere\n T: Ord,\n{\n fn cmp(self, other: Self) -> Ordering {\n if self._is_some {\n if other._is_some {\n self._value.cmp(other._value)\n } else {\n Ordering::greater()\n }\n } else if other._is_some {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n","path":"std/option.nr","function_locations":[{"start":389,"name":"Option::none"},{"start":553,"name":"Option::some"},{"start":672,"name":"Option::is_none"},{"start":774,"name":"Option::is_some"},{"start":898,"name":"Option::unwrap"},{"start":1196,"name":"Option::unwrap_unchecked"},{"start":1368,"name":"Option::unwrap_or"},{"start":1668,"name":"Option::unwrap_or_else"},{"start":1969,"name":"Option::expect"},{"start":2190,"name":"Option::map"},{"start":2490,"name":"Option::map_or"},{"start":2784,"name":"Option::map_or_else"},{"start":3009,"name":"Option::and"},{"start":3446,"name":"Option::and_then"},{"start":3669,"name":"Option::or"},{"start":3902,"name":"Option::or_else"},{"start":4192,"name":"Option::xor"},{"start":4636,"name":"Option::filter"},{"start":5065,"name":"Option::flatten"},{"start":5242,"name":">::default"},{"start":5357,"name":">::eq"},{"start":5706,"name":">::hash"},{"start":5975,"name":">::cmp"}]},"42":{"source":"/// Halt the program at runtime with the given error message.\n///\n/// The provided error message must be either a `str` or a `fmtstr`.\npub fn panic(message: T) -> U\nwhere\n T: StringLike,\n{\n assert(false, message);\n crate::mem::zeroed()\n}\n\ntrait StringLike {}\n\nimpl StringLike for str {}\nimpl StringLike for fmtstr {}\n","path":"std/panic.nr","function_locations":[{"start":196,"name":"panic"}]},"52":{"source":"use crate::{\n authwit::{authorization_interface::AuthorizationInterface, AuthorizationSelector},\n context::{gas::GasOpts, PrivateContext, PublicContext},\n hash::hash_args,\n macros::authorization::authorization,\n oracle::{execution_cache::load, offchain_effect::emit_offchain_effect},\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::AztecAddress,\n constants::{\n CANONICAL_AUTH_REGISTRY_ADDRESS, DOM_SEP__AUTHWIT_INNER, DOM_SEP__AUTHWIT_NULLIFIER, DOM_SEP__AUTHWIT_OUTER,\n },\n hash::poseidon2_hash_with_separator,\n traits::{Serialize, ToField},\n};\n\n/// Authentication witness helper library\n///\n/// Authentication Witness is a scheme for authenticating actions on Aztec, so users can allow third-parties (e.g.\n/// protocols or other users) to execute an action on their behalf.\n///\n/// This library provides helper functions to manage such witnesses. The authentication witness, is some \"witness\"\n/// (data) that authenticates a `message_hash`. The simplest example of an authentication witness, is a signature. The\n/// signature is the \"evidence\", that the signer has seen the message, agrees with it, and has allowed it. It does not\n/// need to be a signature. It could be any kind of \"proof\" that the message is allowed. Another proof could be knowing\n/// some kind of secret, or having some kind of \"token\" that allows the message.\n///\n/// The `message_hash` is a hash of the following structure: hash(consumer, chain_id, version, inner_hash)\n/// - consumer: the address of the contract that is \"consuming\" the message,\n/// - chain_id: the chain id of the chain that the message is being consumed on,\n/// - version: the version of the chain that the message is being consumed on,\n/// - inner_hash: the hash of the \"inner\" message that is being consumed, this is the \"actual\" message or action.\n///\n/// While the `inner_hash` could be anything, such as showing you signed a specific message, it will often be a hash of\n/// the \"action\" to approve, along with who made the call. As part of this library, we provide a few helper functions\n/// to deal with such messages.\n///\n/// For example, we provide helper function that is used for checking that the message is an encoding of the current\n/// call. This can be used to let some contract \"allow\" another contract to act on its behalf, as long as it can show\n/// that it is acting on behalf of the contract.\n///\n/// If we take a case of allowing a contract to transfer tokens on behalf of an account, the `inner_hash` can be\n/// derived as: inner_hash = hash(caller, \"transfer\", hash(to, amount))\n///\n/// Where the `caller` would be the address of the contract that is trying to transfer the tokens, and `to` and\n/// `amount` the arguments for the transfer.\n///\n/// Note that we have both a `caller` and a `consumer`, the `consumer` will be the contract that is consuming the\n/// message, in the case of the transfer, it would be the `Token` contract itself, while the caller, will be the actor\n/// that is allowed to transfer the tokens.\n///\n///\n/// The authentication mechanism works differently in public and private contexts. In private, we recall that\n/// everything is executed on the user's device, so we can use `oracles` to \"ask\" the user (not contract) for\n/// information. In public we cannot do this, since it is executed by the sequencer (someone else). Therefore we can\n/// instead use a \"registry\" to store the messages that we have approved.\n///\n/// A simple example would be a \"token\" that is being \"pulled\" from one account into another. We will first outline how\n/// this would look in private, and then in public later.\n///\n/// Say that a user `Alice` wants to deposit some tokens into a DeFi protocol (say a DEX). `Alice` would make a\n/// `deposit` transaction, that she is executing using her account contract. The account would call the `DeFi` contract\n/// to execute `deposit`, which would try to pull funds from the `Token` contract. Since the `DeFi` contract is trying\n/// to pull funds from an account that is not its own, it needs to convince the `Token` contract that it is allowed to\n/// do so.\n///\n/// This is where the authentication witness comes in The `Token` contract computes a `message_hash` from the\n/// `transfer` call, and then asks `Alice Account` contract to verify that the `DeFi` contract is allowed to execute\n/// that call.\n///\n/// `Alice Account` contract can then ask `Alice` if she wants to allow the `DeFi` contract to pull funds from her\n/// account. If she does, she will sign the `message_hash` and return the signature to the `Alice Account` which will\n/// validate it and return success to the `Token` contract which will then allow the `DeFi` contract to pull funds from\n/// `Alice`.\n///\n/// To ensure that the same \"approval\" cannot be used multiple times, we also compute a `nullifier` for the\n/// authentication witness, and emit it from the `Token` contract (consumer).\n///\n/// Note that we can do this flow as we are in private were we can do oracle calls out from contracts.\n///\n///\n/// Person Contract Contract Contract\n/// Alice Alice Account Token DeFi\n/// | | | |\n/// | Defi.deposit(Token, 1000) | |\n/// |----------------->| | |\n/// | | deposit(Token, 1000) |\n/// | |---------------------------------------->|\n/// | | | |\n/// | | | transfer(Alice, Defi, 1000)\n/// | | |<---------------------|\n/// | | | |\n/// | | Check if Defi may call transfer(Alice, Defi, 1000)\n/// | |<-----------------| |\n/// | | | |\n/// | Please give me AuthWit for DeFi | |\n/// | calling transfer(Alice, Defi, 1000) | |\n/// |<-----------------| | |\n/// | | | |\n/// | | | |\n/// | AuthWit for transfer(Alice, Defi, 1000) |\n/// |----------------->| | |\n/// | | AuthWit validity | |\n/// | |----------------->| |\n/// | | | |\n/// | | throw if invalid AuthWit |\n/// | | | |\n/// | | emit AuthWit nullifier |\n/// | | | |\n/// | | transfer(Alice, Defi, 1000) |\n/// | | | |\n/// | | | |\n/// | | | success |\n/// | | |--------------------->|\n/// | | | |\n/// | | | |\n/// | | | deposit(Token, 1000)\n/// | | | |\n/// | | | |\n///\n///\n/// If we instead were in public, we cannot do the same flow. Instead we would use an authentication registry to store\n/// the messages that we have approved.\n///\n/// To approve a message, `Alice Account` can make a `set_authorized` call to the registry, to set a `message_hash` as\n/// authorized. This is essentially a mapping from `message_hash` to `true` for `Alice Contract`. Every account has its\n/// own map in the registry, so `Alice` cannot approve a message for `Bob`.\n///\n/// The `Token` contract can then try to \"spend\" the approval by calling `consume` on the registry. If the message was\n/// approved, the value is updated to `false`, and we return the success flag. For more information on the registry,\n/// see `main.nr` in `auth_registry_contract`.\n///\n/// Person Contract Contract Contract Contract\n/// Alice Alice Account Registry Token DeFi\n/// | | | | |\n/// | Registry.set_authorized(..., true) | | |\n/// |----------------->| | | |\n/// | | set_authorized(..., true) | |\n/// | |------------------->| | |\n/// | | | | |\n/// | | set authorized to true | |\n/// | | | | |\n/// | | | | |\n/// | Defi.deposit(Token, 1000) | | |\n/// |----------------->| | | |\n/// | | deposit(Token, 1000) | |\n/// | |-------------------------------------------------------------->|\n/// | | | | |\n/// | | | transfer(Alice, Defi, 1000) |\n/// | | | |<---------------------|\n/// | | | | |\n/// | | | Check if Defi may call transfer(Alice, Defi, 1000)\n/// | | |<------------------| |\n/// | | | | |\n/// | | throw if invalid AuthWit | |\n/// | | | | |\n/// | | | | |\n/// | | set authorized to false | |\n/// | | | | |\n/// | | | | |\n/// | | | AuthWit validity | |\n/// | | |------------------>| |\n/// | | | | |\n/// | | | | transfer(Alice, Defi, 1000)\n/// | | | |<-------------------->|\n/// | | | | |\n/// | | | | success |\n/// | | | |--------------------->|\n/// | | | | |\n/// | | | | deposit(Token, 1000)\n/// | | | | |\n///\n///\n/// --- FAQ ---\n/// Q: Why are we using a success flag of `poseidon2_hash_bytes(\"IS_VALID()\")` instead of just returning a boolean?\n/// A: We want to make sure that we don't accidentally return `true` if there is a collision in the function\n/// selector. By returning a hash of `IS_VALID()`, it becomes very unlikely that there is both a collision and we\n/// return a success flag.\n///\n/// Q: Why are we using static calls?\n/// A: We are using static calls to ensure that the account contract cannot re-enter. If it was a normal call, it\n/// could make a new call and do a re-entry attack. Using a static ensures that it cannot update any state.\n///\n/// Q: Would it not be cheaper to use a nullifier instead of updating state in public?\n/// A: At a quick glance, a public state update + nullifier is 96 bytes, but two state updates are 128, so it would\n/// be cheaper to use a nullifier, if this is the way it would always be done. However, if both the approval and the\n/// consumption is done in the same transaction, then we will be able to squash the updates (only final tx state diff\n/// is posted to DA), and now it is cheaper.\n///\n/// Q: Why is the chain id and the version part of the message hash?\n/// A: The chain id and the version is part of the message hash to ensure that the message is only valid on a\n/// specific chain to avoid a case where the same message could be used across multiple chains.\n\npub global IS_VALID_SELECTOR: Field = 0x47dacd73; // 4 last bytes of\n// poseidon2_hash_bytes(\"IS_VALID()\")\n\n/// A struct that represents a contract call the user can authorize. It's associated identifier is generated by\n/// serializing and hashing it. The user is expected to sign this hash to signal the contract call can be performed on\n/// their behalf\n#[authorization]\nstruct CallAuthorization {\n msg_sender: AztecAddress,\n selector: FunctionSelector,\n args_hash: Field,\n}\n\n/// A struct that represents a request to authorize a call, which is used to emit an offchain effect so the user/wallet\n/// can understand what they are being asked to sign. It is generated from a CallAuthorization by adding metadata to\n/// it, such as the selector for the authorization, the inner hash, and the actual arguments that are being passed to\n/// the function call.\n#[derive(Serialize)]\nstruct CallAuthorizationRequest {\n selector: AuthorizationSelector,\n inner_hash: Field,\n on_behalf_of: AztecAddress,\n msg_sender: AztecAddress,\n fn_selector: FunctionSelector,\n args_hash: Field,\n}\n\nunconstrained fn emit_authorization_as_offchain_effect(\n authorization: CallAuthorization,\n inner_hash: Field,\n on_behalf_of: AztecAddress,\n) {\n let args: [Field; N] = load(authorization.args_hash);\n let authorization_request = CallAuthorizationRequest {\n selector: authorization.get_authorization_selector(),\n inner_hash: inner_hash,\n on_behalf_of: on_behalf_of,\n msg_sender: authorization.msg_sender,\n fn_selector: authorization.selector,\n args_hash: authorization.args_hash,\n };\n emit_offchain_effect(authorization_request.serialize().concat(args))\n}\n\n/// Assert that `on_behalf_of` has authorized the current call with a valid authentication witness\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Additionally, this function emits the identifying information of the call as an offchain effect so PXE can rely the\n/// information to the user/wallet in a readable way. To that effect, it is generic over N, where N is the number of\n/// arguments the authorized functions takes. This is used to load the arguments from the execution cache. This\n/// function is intended to be called via a macro, which will use the turbofish operator to specify the number of\n/// arguments.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call\npub fn assert_current_call_valid_authwit(context: &mut PrivateContext, on_behalf_of: AztecAddress) {\n let args_hash: Field = context.get_args_hash();\n\n let authorization =\n CallAuthorization { msg_sender: context.maybe_msg_sender().unwrap(), selector: context.selector(), args_hash };\n let inner_hash = compute_inner_authwit_hash(authorization.serialize());\n // Safety: Offchain effects are by definition unconstrained. They are emitted via an oracle which we don't use for\n // anything besides its side effects, therefore this is safe to call.\n unsafe { emit_authorization_as_offchain_effect::(authorization, inner_hash, on_behalf_of) };\n\n assert_inner_hash_valid_authwit(context, on_behalf_of, inner_hash);\n}\n\n/// Assert that a specific `inner_hash` is valid for the `on_behalf_of` address\n///\n/// Used as an internal function for `assert_current_call_valid_authwit` and can be used as a standalone function when\n/// the `inner_hash` is from a different source, e.g., say a block of text etc.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call @param inner_hash The hash of the\n/// message to authorize\npub fn assert_inner_hash_valid_authwit(context: &mut PrivateContext, on_behalf_of: AztecAddress, inner_hash: Field) {\n // We perform a static call here and not a standard one to ensure that the account contract cannot re-enter.\n let result: Field = context\n .static_call_private_function(\n on_behalf_of,\n comptime { FunctionSelector::from_signature(\"verify_private_authwit(Field)\") },\n [inner_hash],\n )\n .get_preimage();\n assert(result == IS_VALID_SELECTOR, \"Message not authorized by account\");\n // Compute the nullifier, similar computation to the outer hash, but without the chain_id and version. Those should\n // already be handled in the verification, so we just need something to nullify, that allows the same inner_hash\n // for multiple actors.\n let nullifier = compute_authwit_nullifier(on_behalf_of, inner_hash);\n context.push_nullifier(nullifier);\n}\n\n/// Assert that `on_behalf_of` has authorized the current call in the authentication registry\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Note that the authentication registry will take the `msg_sender` into account as the consumer, so this will only\n/// work if the `msg_sender` is the same as the `consumer` when the `message_hash` was inserted into the registry.\n///\n/// @param on_behalf_of The address that has allegedly authorized the current call\npub unconstrained fn assert_current_call_valid_authwit_public(context: PublicContext, on_behalf_of: AztecAddress) {\n let inner_hash = compute_inner_authwit_hash([\n context.maybe_msg_sender().unwrap().to_field(),\n context.selector().to_field(),\n context.get_args_hash(),\n ]);\n assert_inner_hash_valid_authwit_public(context, on_behalf_of, inner_hash);\n}\n\n/// Assert that `on_behalf_of` has authorized a specific `inner_hash` in the authentication registry\n///\n/// Compute the `inner_hash` using the `msg_sender`, `selector` and `args_hash` and then make a call out to the\n/// `on_behalf_of` contract to verify that the `inner_hash` is valid.\n///\n/// Note that the authentication registry will take the `msg_sender` into account as the consumer, so this will only\n/// work if the `msg_sender` is the same as the `consumer` when the `message_hash` was inserted into the registry.\n///\n/// @param on_behalf_of The address that has allegedly authorized the `inner_hash`\npub unconstrained fn assert_inner_hash_valid_authwit_public(\n context: PublicContext,\n on_behalf_of: AztecAddress,\n inner_hash: Field,\n) {\n let results: [Field] = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"consume((Field),Field)\") },\n [on_behalf_of.to_field(), inner_hash],\n GasOpts::default(),\n );\n assert(results.len() == 1, \"Invalid response from registry\");\n assert(results[0] == IS_VALID_SELECTOR, \"Message not authorized by account\");\n}\n\n/// Compute the `message_hash` from a function call to be used by an authentication witness\n///\n/// Useful for when you need a non-account contract to approve during execution. For example if you need a contract to\n/// make a call to nested contract, e.g., contract A wants to exit token T to L1 using bridge B, so it needs to allow B\n/// to transfer T on its behalf.\n///\n/// @param caller The address of the contract that is calling the function, in the example above, this would be B\n/// @param consumer The address of the contract that is consuming the message, in the example above, this would be T\n/// @param chain_id The chain id of the chain that the message is being consumed on @param version The version of the\n/// chain that the message is being consumed on @param selector The function selector of the function that is being\n/// called @param args The arguments of the function that is being called\npub fn compute_authwit_message_hash_from_call(\n caller: AztecAddress,\n consumer: AztecAddress,\n chain_id: Field,\n version: Field,\n selector: FunctionSelector,\n args: [Field; N],\n) -> Field {\n let args_hash = hash_args(args);\n let inner_hash = compute_inner_authwit_hash([caller.to_field(), selector.to_field(), args_hash]);\n compute_authwit_message_hash(consumer, chain_id, version, inner_hash)\n}\n\n/// Computes the `inner_hash` of the authentication witness\n///\n/// This is used internally, but also useful in cases where you want to compute the `inner_hash` for a specific message\n/// that is not necessarily a call, but just some \"bytes\" or text.\n///\n/// @param args The arguments to hash\npub fn compute_inner_authwit_hash(args: [Field; N]) -> Field {\n poseidon2_hash_with_separator(args, DOM_SEP__AUTHWIT_INNER)\n}\n\n/// Computes the `authwit_nullifier` for a specific `on_behalf_of` and `inner_hash`\n///\n/// Using the `on_behalf_of` and the `inner_hash` to ensure that the nullifier is siloed for a specific `on_behalf_of`.\n///\n/// @param on_behalf_of The address that has authorized the `inner_hash` @param inner_hash The hash of the message to\n/// authorize\npub fn compute_authwit_nullifier(on_behalf_of: AztecAddress, inner_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [on_behalf_of.to_field(), inner_hash],\n DOM_SEP__AUTHWIT_NULLIFIER,\n )\n}\n\n/// Computes the `message_hash` for the authentication witness\n///\n/// @param consumer The address of the contract that is consuming the message @param chain_id The chain id of the chain\n/// that the message is being consumed on @param version The version of the chain that the message is being consumed on\n/// @param inner_hash The hash of the \"inner\" message that is being consumed\npub fn compute_authwit_message_hash(\n consumer: AztecAddress,\n chain_id: Field,\n version: Field,\n inner_hash: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [consumer.to_field(), chain_id, version, inner_hash],\n DOM_SEP__AUTHWIT_OUTER,\n )\n}\n\n/// Helper function to set the authorization status of a message hash\n///\n/// Wraps a public call to the authentication registry to set the authorization status of a `message_hash`\n///\n/// @param message_hash The hash of the message to authorize @param authorize True if the message should be authorized,\n/// false if it should be revoked\npub unconstrained fn set_authorized(context: PublicContext, message_hash: Field, authorize: bool) {\n let res = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"set_authorized(Field,bool)\") },\n [message_hash, authorize as Field],\n GasOpts::default(),\n );\n assert(res.len() == 0);\n}\n\n/// Helper function to reject all authwits\n///\n/// Wraps a public call to the authentication registry to set the `reject_all` flag\n///\n/// @param reject True if all authwits should be rejected, false otherwise\npub unconstrained fn set_reject_all(context: PublicContext, reject: bool) {\n let res = context.call_public_function(\n CANONICAL_AUTH_REGISTRY_ADDRESS,\n comptime { FunctionSelector::from_signature(\"set_reject_all(bool)\") },\n [reject as Field],\n GasOpts::default(),\n );\n assert(res.len() == 0);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/authwit/auth.nr","function_locations":[{"start":14768,"name":"emit_authorization_as_offchain_effect"},{"start":16200,"name":"assert_current_call_valid_authwit"},{"start":17389,"name":"assert_inner_hash_valid_authwit"},{"start":18929,"name":"assert_current_call_valid_authwit_public"},{"start":19955,"name":"assert_inner_hash_valid_authwit_public"},{"start":21499,"name":"compute_authwit_message_hash_from_call"},{"start":22083,"name":"compute_inner_authwit_hash"},{"start":22585,"name":"compute_authwit_nullifier"},{"start":23238,"name":"compute_authwit_message_hash"},{"start":23815,"name":"set_authorized"},{"start":24381,"name":"set_reject_all"}]},"59":{"source":"use crate::oracle::capsules;\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// A dynamically sized array backed by PXE's non-volatile database (called capsules). Values are persisted until\n/// deleted, so they can be e.g. stored during simulation of a transaction and later retrieved during witness\n/// generation. All values are scoped per contract address, so external contracts cannot access them.\npub struct CapsuleArray {\n contract_address: AztecAddress,\n /// The base slot is where the array length is stored in capsules. Array elements are stored in consecutive slots\n /// after the base slot. For example, with base slot 5: the length is at slot 5, the first element (index 0) is at\n /// slot 6, the second element (index 1) is at slot 7, and so on.\n base_slot: Field,\n /// Scope for capsule isolation. Capsule operations are scoped to the given address, allowing multiple independent\n /// namespaces within the same contract.\n scope: AztecAddress,\n}\n\nimpl CapsuleArray {\n /// Returns a CapsuleArray scoped to a specific address.\n ///\n /// Array elements are stored in contiguous slots\n /// following the base slot, so there should be sufficient space between array base slots to accommodate elements.\n /// A reasonable strategy is to make the base slot a hash of a unique value.\n pub unconstrained fn at(contract_address: AztecAddress, base_slot: Field, scope: AztecAddress) -> Self {\n Self { contract_address, base_slot, scope }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n // An uninitialized array defaults to a length of 0.\n capsules::load(self.contract_address, self.base_slot, self.scope).unwrap_or(0) as u32\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let current_length = self.len();\n\n // The slot corresponding to the index `current_length` is the first slot immediately after the end of the\n // array, which is where we want to place the new value.\n capsules::store(\n self.contract_address,\n self.slot_at(current_length),\n value,\n self.scope,\n );\n\n // Then we simply update the length.\n let new_length = current_length + 1;\n capsules::store(\n self.contract_address,\n self.base_slot,\n new_length,\n self.scope,\n );\n }\n\n /// Retrieves the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n assert(index < self.len(), \"Attempted to read past the length of a CapsuleArray\");\n\n capsules::load(self.contract_address, self.slot_at(index), self.scope).unwrap()\n }\n\n /// Deletes the value stored in the array at `index`. Throws if the index is out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n let current_length = self.len();\n assert(index < current_length, \"Attempted to delete past the length of a CapsuleArray\");\n\n // In order to be able to remove elements at arbitrary indices, we need to shift the entire contents of the\n // array past the removed element one slot backward so that we don't end up with a gap and preserve the\n // contiguous slots. We can skip this when deleting the last element however.\n if index != current_length - 1 {\n // The source and destination regions overlap, but `copy` supports this.\n capsules::copy(\n self.contract_address,\n self.slot_at(index + 1),\n self.slot_at(index),\n current_length - index - 1,\n self.scope,\n );\n }\n\n // We can now delete the last element (which has either been copied to the slot immediately before it, or was\n // the element we meant to delete in the first place) and update the length.\n capsules::delete(\n self.contract_address,\n self.slot_at(current_length - 1),\n self.scope,\n );\n capsules::store(\n self.contract_address,\n self.base_slot,\n current_length - 1,\n self.scope,\n );\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. The order in which values\n /// are processed is arbitrary.\n ///\n /// ## Array Mutation\n ///\n /// It is safe to delete the current element (and only the current element) from inside the callback via `remove`:\n /// ```noir\n /// array.for_each(|index, value| {\n /// if some_condition(value) {\n /// array.remove(index); // safe only for this index\n /// }\n /// }\n /// ```\n ///\n /// If all elements in the array need to iterated over and then removed, then using `for_each` results in optimal\n /// efficiency.\n ///\n /// It is **not** safe to push new elements into the array from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n // Iterating over all elements is simple, but we want to do it in such a way that a) deleting the current\n // element is safe to do, and b) deleting *all* elements is optimally efficient. This is because CapsuleArrays\n // are typically used to hold pending tasks, so iterating them while clearing completed tasks (sometimes\n // unconditionally, resulting in a full clear) is a very common access pattern.\n //\n // The way we achieve this is by iterating backwards: each element can always be deleted since it won't change\n // any preceding (lower) indices, and if every element is deleted then every element will (in turn) be the last\n // element. This results in an optimal full clear since `remove` will be able to skip the `capsules::copy` call\n // to shift any elements past the deleted one (because there will be none).\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n\n unconstrained fn slot_at(self, index: u32) -> Field {\n // Elements are stored immediately after the base slot, so we add 1 to it to compute the slot for the first\n // element.\n self.base_slot + 1 + index as Field\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::CapsuleArray;\n\n global SLOT: Field = 1230;\n\n #[test]\n unconstrained fn empty_array() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array: CapsuleArray = CapsuleArray::at(contract_address, SLOT, scope);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn empty_array_read() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n let _: Field = array.get(0);\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"Attempted to read past the length of a CapsuleArray\")]\n unconstrained fn read_past_len() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(5);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 8);\n assert_eq(array.get(2), 9);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We store all values that we were called with and check that all (value, index) tuples are present. Note\n // that we do not care about the order in which each tuple was passed to the closure.\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all_no_copy() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let array = CapsuleArray::at(contract_address, SLOT, scope);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n // We test that the aztec_utl_copyCapsule was never called, which is the expensive operation we want to\n // avoid.\n let mock = std::test::OracleMock::mock(\"aztec_utl_copyCapsule\");\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(mock.times_called(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_scopes_are_isolated() {\n let mut env = TestEnvironment::new();\n let scope_a = env.create_light_account();\n let scope_b = env.create_light_account();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let array_a = CapsuleArray::at(contract_address, SLOT, scope_a);\n let array_b = CapsuleArray::at(contract_address, SLOT, scope_b);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/capsules/mod.nr","function_locations":[{"start":1478,"name":"CapsuleArray::at"},{"start":1641,"name":"CapsuleArray::len"},{"start":1935,"name":"CapsuleArray::push"},{"start":2748,"name":"CapsuleArray::get"},{"start":3083,"name":"CapsuleArray::remove"},{"start":5345,"name":"CapsuleArray::for_each"},{"start":6413,"name":"CapsuleArray::slot_at"},{"start":6789,"name":"test::empty_array"},{"start":7263,"name":"test::empty_array_read"},{"start":7638,"name":"test::array_push"},{"start":8156,"name":"test::read_past_len"},{"start":8559,"name":"test::array_remove_last"},{"start":8997,"name":"test::array_remove_some"},{"start":9729,"name":"test::array_remove_all"},{"start":10296,"name":"test::for_each_called_with_all_elements"},{"start":11389,"name":"test::for_each_remove_some"},{"start":12081,"name":"test::for_each_remove_all"},{"start":12619,"name":"test::for_each_remove_all_no_copy"},{"start":13383,"name":"test::different_scopes_are_isolated"}]},"68":{"source":"use crate::{\n context::gas::GasOpts,\n hash::{\n compute_l1_to_l2_message_hash, compute_l1_to_l2_message_nullifier, compute_secret_hash,\n compute_siloed_nullifier,\n },\n oracle::avm,\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::{AztecAddress, EthAddress},\n constants::{MAX_U32_VALUE, NULL_MSG_SENDER_CONTRACT_ADDRESS},\n traits::{Empty, FromField, Packable, Serialize, ToField},\n utils::writer::Writer,\n};\n\n/// # PublicContext\n///\n/// The **main interface** between an #[external(\"public\")] function and the Aztec blockchain.\n///\n/// An instance of the PublicContext is initialized automatically at the outset of every public function, within the\n/// #[external(\"public\")] macro, so you'll never need to consciously instantiate this yourself.\n///\n/// The instance is always named `context`, and it will always be available within the body of every\n/// #[external(\"public\")] function in your smart contract.\n///\n/// Typical usage for a smart contract developer will be to call getter methods of the PublicContext.\n///\n/// _Pushing_ data and requests to the context is mostly handled within aztec-nr's own functions, so typically a smart\n/// contract developer won't need to call any setter methods directly.\n///\n/// ## Responsibilities\n/// - Exposes contextual data to a public function:\n/// - Data relating to how this public function was called:\n/// - msg_sender, this_address\n/// - Data relating to the current blockchain state:\n/// - timestamp, block_number, chain_id, version\n/// - Gas and fee information\n/// - Provides state access:\n/// - Read/write public storage (key-value mapping)\n/// - Check existence of notes and nullifiers (Some patterns use notes & nullifiers to store public (not private)\n/// information)\n/// - Enables consumption of L1->L2 messages.\n/// - Enables calls to other public smart contract functions:\n/// - Writes data to the blockchain:\n/// - Updates to public state variables\n/// - New public logs (for events)\n/// - New L2->L1 messages\n/// - New notes & nullifiers (E.g. pushing public info to notes/nullifiers, or for completing \"partial notes\")\n///\n/// ## Key Differences from Private Execution\n///\n/// Unlike private functions -- which are executed on the user's device and which can only reference historic state --\n/// public functions are executed by a block proposer and are executed \"live\" on the _current_ tip of the chain. This\n/// means public functions can:\n/// - Read and write _current_ public state\n/// - Immediately see the effects of earlier transactions in the same block\n///\n/// Also, public functions are executed within a zkVM (the \"AVM\"), so that they can _revert_ whilst still ensuring\n/// payment to the proposer and prover. (Private functions cannot revert: they either succeed, or they cannot be\n/// included).\n///\n/// ## Optimising Public Functions\n///\n/// Using the AVM to execute public functions means they compile down to \"AVM bytecode\" instead of the ACIR that\n/// private functions (standalone circuits) compile to. Therefore the approach to optimising a public function is\n/// fundamentally different from optimising a public function.\n///\npub struct PublicContext {\n pub args_hash: Option,\n pub compute_args_hash: fn() -> Field,\n}\n\nimpl Eq for PublicContext {\n fn eq(self, other: Self) -> bool {\n (self.args_hash == other.args_hash)\n // Can't compare the function compute_args_hash\n }\n}\n\nimpl PublicContext {\n /// Creates a new PublicContext instance.\n ///\n /// Low-level function: This is called automatically by the #[external(\"public\")] macro, so you shouldn't need to\n /// be called directly by smart contract developers.\n ///\n /// # Arguments\n /// * `compute_args_hash` - Function to compute the args_hash\n ///\n /// # Returns\n /// * A new PublicContext instance\n ///\n pub fn new(compute_args_hash: fn() -> Field) -> Self {\n PublicContext { args_hash: Option::none(), compute_args_hash }\n }\n\n /// Emits a _public_ log that will be visible onchain to everyone.\n ///\n /// # Arguments\n /// * `tag` - A tag placed at `fields[0]` of the emitted log. Nodes index logs by this value, allowing\n /// clients to efficiently query for matching logs without scanning all of them.\n /// * `log` - The data to log, must implement Serialize trait.\n ///\n /// ## Safety\n ///\n /// The `tag` should be domain-separated (e.g. via [`crate::protocol::hash::compute_log_tag`]) to prevent\n /// collisions between logs from different sources. Without domain separation, two unrelated log types that\n /// happen to share a raw tag value become indistinguishable. Prefer `self.emit(event)` for events, which\n /// handles tagging automatically.\n pub fn emit_public_log_unsafe(_self: Self, tag: Field, log: T)\n where\n T: Serialize,\n {\n // We use a Writer to serialize the log directly after the tag, avoiding an extra O(n) copy that would\n // result from serializing first and then prepending the tag.\n let mut writer: Writer<1 + ::N> = Writer::new();\n writer.write(tag);\n Serialize::stream_serialize(log, &mut writer);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_public_log(writer.finish().as_vector()) };\n }\n\n /// Checks if a given note hash exists in the note hash tree at a particular leaf_index.\n ///\n /// # Arguments\n /// * `note_hash` - The note hash to check for existence\n /// * `leaf_index` - The index where the note hash should be located\n ///\n /// # Returns\n /// * `bool` - True if the note hash exists at the specified index\n ///\n pub fn note_hash_exists(_self: Self, note_hash: Field, leaf_index: u64) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::note_hash_exists(note_hash, leaf_index)\n }\n }\n\n /// Checks if a specific L1-to-L2 message exists in the L1-to-L2 message tree at a particular leaf index.\n ///\n /// Common use cases include token bridging, cross-chain governance, and triggering L2 actions based on L1 events.\n ///\n /// This function should be called before attempting to consume an L1-to-L2 message.\n ///\n /// # Arguments\n /// * `msg_hash` - Hash of the L1-to-L2 message to check\n /// * `msg_leaf_index` - The index where the message should be located\n ///\n /// # Returns\n /// * `bool` - True if the message exists at the specified index\n ///\n /// # Advanced\n /// * Uses the AVM l1_to_l2_msg_exists opcode for tree lookup\n /// * Messages are copied from L1 Inbox to L2 by block proposers\n ///\n pub fn l1_to_l2_msg_exists(_self: Self, msg_hash: Field, msg_leaf_index: Field) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself TODO(alvaro): Make l1l2msg leaf index a u64 upstream\n unsafe {\n avm::l1_to_l2_msg_exists(msg_hash, msg_leaf_index as u64)\n }\n }\n\n /// Returns `true` if an `unsiloed_nullifier` has been emitted by `contract_address`.\n ///\n /// Note that unsiloed nullifiers are not the actual values stored in the nullifier tree: they are first siloed via\n /// [`crate::hash::compute_siloed_nullifier`] with the emitting contract's address.\n ///\n /// ## Use Cases\n ///\n /// Nullifiers are typically used as a _privacy-preserving_ record of a one-time action, but they can also be used\n /// to efficiently record _public_ one-time actions as well. This is cheaper than using public storage, and has the\n /// added benefit of the nullifier being emittable from a private function.\n ///\n /// An example is to check whether a contract has been published: we emit a nullifier that is deterministic and\n /// which has a _public_ preimage.\n ///\n /// ## Public vs Private\n ///\n /// In general, one should not attempt to prove nullifier non-existence in private, as that will not consider the\n /// possibility of the nullifier having been emitted in any transaction between the anchor block and the inclusion\n /// block. Private functions instead prove existence via\n /// [`crate::context::PrivateContext::assert_nullifier_exists`]\n /// and 'prove' non-existence by _emitting_ the nullifer, which would cause the transaction to fail if the\n /// nullifier existed.\n ///\n /// This is not the case in public functions, which **do** have access to the tip of the blockchain and so can\n /// reliably prove whether a nullifier exists or not.\n ///\n /// ## Safety\n ///\n /// While it is safe to rely on this function's return value to determine if a nullifier exists or not, it is often\n /// **not** safe to infer additional information from that. In particular, it is **unsafe** to infer that the\n /// existence of a nullifier emitted from a private function implies that all other side-effects of said private\n /// execution have been completed, more concretely that any enqueued public calls have been executed.\n ///\n /// For example, if a function in contract `A` privately emits nullifier `X` and then enqueues public function `Y`,\n /// then it is **unsafe** for a contract `B` to infer that `Y` has alredy executed simply because `X` exists.\n ///\n /// This is because **all** private transaction effects are committed _before_ enqueued public functions are run\n /// (in\n /// order to not reveal detailed timing information about the transaction), so it is possible to observe a\n /// nullifier that was emitted alongside the enqueuing of a public call **before** said call has been completed.\n ///\n /// ## Cost\n ///\n /// This emits the `CHECKNULLIFIEREXISTS` opcode, which conceptually performs a merkle inclusion proof on the\n /// nullifier tree (both when the nullifier exists and when it doesn't).\n pub fn nullifier_exists_unsafe(_self: Self, unsiloed_nullifier: Field, contract_address: AztecAddress) -> bool {\n let siloed_nullifier = compute_siloed_nullifier(contract_address, unsiloed_nullifier);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::nullifier_exists(siloed_nullifier)\n }\n }\n\n /// Consumes a message sent from Ethereum (L1) to Aztec (L2) -- effectively marking it as \"read\".\n ///\n /// Use this function if you only want the message to ever be \"referred to\" once. Once consumed using this method,\n /// the message cannot be consumed again, because a nullifier is emitted. If your use case wants for the message to\n /// be read unlimited times, then you can always read any historic message from the L1-to-L2 messages tree, using\n /// the `l1_to_l2_msg_exists` method. Messages never technically get deleted from that tree.\n ///\n /// The message will first be inserted into an Aztec \"Inbox\" smart contract on L1. It will not be available for\n /// consumption immediately. Messages get copied-over from the L1 Inbox to L2 by the next Proposer in batches. So\n /// you will need to wait until the messages are copied before you can consume them.\n ///\n /// # Arguments\n /// * `content` - The message content that was sent from L1\n /// * `secret` - Secret value used for message privacy (if needed)\n /// * `sender` - Ethereum address that sent the message\n /// * `leaf_index` - Index of the message in the L1-to-L2 message tree\n ///\n /// # Advanced\n /// * Validates message existence in the L1-to-L2 message tree\n /// * Prevents double-consumption by emitting a nullifier\n /// * Message hash is computed from all parameters + chain context\n /// * Will revert if message doesn't exist or was already consumed\n ///\n pub fn consume_l1_to_l2_message(self: Self, content: Field, secret: Field, sender: EthAddress, leaf_index: Field) {\n let secret_hash = compute_secret_hash(secret);\n let message_hash = compute_l1_to_l2_message_hash(\n sender,\n self.chain_id(),\n /*recipient=*/\n self.this_address(),\n self.version(),\n content,\n secret_hash,\n leaf_index,\n );\n let nullifier = compute_l1_to_l2_message_nullifier(message_hash, secret);\n\n assert(!self.nullifier_exists_unsafe(nullifier, self.this_address()), \"L1-to-L2 message is already nullified\");\n assert(self.l1_to_l2_msg_exists(message_hash, leaf_index), \"Tried to consume nonexistent L1-to-L2 message\");\n\n self.push_nullifier(nullifier);\n }\n\n /// Sends an \"L2 -> L1 message\" from this function (Aztec, L2) to a smart contract on Ethereum (L1). L1 contracts\n /// which are designed to send/receive messages to/from Aztec are called \"Portal Contracts\".\n ///\n /// Common use cases include withdrawals, cross-chain asset transfers, and triggering L1 actions based on L2 state\n /// changes.\n ///\n /// The message will be inserted into an Aztec \"Outbox\" contract on L1, when this transaction's block is proposed\n /// to L1. Sending the message will not result in any immediate state changes in the target portal contract. The\n /// message will need to be manually consumed from the Outbox through a separate Ethereum transaction: a user will\n /// need to call a function of the portal contract -- a function specifically designed to make a call to the Outbox\n /// to consume the message. The message will only be available for consumption once the _epoch_ proof has been\n /// submitted. Given that there are multiple Aztec blocks within an epoch, it might take some time for this epoch\n /// proof to be submitted -- especially if the block was near the start of an epoch.\n ///\n /// # Arguments\n /// * `recipient` - Ethereum address that will receive the message\n /// * `content` - Message content (32 bytes as a Field element)\n ///\n pub fn message_portal(_self: Self, recipient: EthAddress, content: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::send_l2_to_l1_msg(recipient, content) };\n }\n\n /// Calls a public function on another contract.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Arguments to pass to the function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn call_public_function(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Makes a read-only call to a public function on another contract.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be staticcalls.\n ///\n /// Useful for querying data from other contracts safely.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Array of arguments to pass to the called function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn static_call_public_function(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call_static(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Adds a new note hash to the Aztec blockchain's global Note Hash Tree.\n ///\n /// Notes are ordinarily constructed and emitted by _private_ functions, to ensure that both the content of the\n /// note, and the contract that emitted the note, stay private.\n ///\n /// There are however some useful patterns whereby a note needs to contain _public_ data. The ability to push a new\n /// note_hash from a _public_ function means that notes can be injected with public data immediately -- as soon as\n /// the public value is known. The slower alternative would be to submit a follow-up transaction so that a private\n /// function can inject the data. Both are possible on Aztec.\n ///\n /// Search \"Partial Note\" for a very common pattern which enables a note to be \"partially\" populated with some data\n /// in a _private_ function, and then later \"completed\" with some data in a public function.\n ///\n /// # Arguments\n /// * `note_hash` - The hash of the note to add to the tree\n ///\n /// # Advanced\n /// * The note hash will be siloed with the contract address by the protocol\n ///\n pub fn push_note_hash(_self: Self, note_hash: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_note_hash(note_hash) };\n }\n\n /// Creates a new [nullifier](crate::nullifier).\n ///\n /// While nullifiers are primarily intended as a _privacy-preserving_ record of a one-time action, they can also\n /// be used to efficiently record _public_ one-time actions. This function allows creating nullifiers from public\n /// contract functions, which behave just like those created from private functions.\n ///\n /// ## Safety\n ///\n /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state.\n ///\n /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that\n /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a\n /// variable as initialized). Note nullifiers should only be created via\n /// [`crate::context::PrivateContext::push_nullifier_for_note_hash`].\n ///\n /// ## Advanced\n ///\n /// The raw `nullifier` is not what is inserted into the Aztec state tree: it will be first siloed by contract\n /// address via [`crate::protocol::hash::compute_siloed_nullifier`] in order to prevent accidental or malicious\n /// interference of nullifiers from different contracts.\n pub fn push_nullifier(_self: Self, nullifier: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_nullifier(nullifier) };\n }\n\n /// Returns the address of the current contract being executed.\n ///\n /// This is equivalent to `address(this)` in Solidity (hence the name). Use this to identify the current contract's\n /// address, commonly needed for access control or when interacting with other contracts.\n ///\n /// # Returns\n /// * `AztecAddress` - The contract address of the current function being executed.\n ///\n pub fn this_address(_self: Self) -> AztecAddress {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::address()\n }\n }\n\n /// Returns the contract address that initiated this function call.\n ///\n /// This is similar to `msg.sender` in Solidity (hence the name).\n ///\n /// Important Note: If the calling function is a _private_ function, then it had the option of hiding its address\n /// when enqueuing this public function call. In such cases, this method will return `Option::none`.\n /// If the calling function is a _public_ function, it will always return an `Option::some` (i.e. a\n /// non-null value).\n ///\n /// # Returns\n /// * `Option` - The address of the smart contract that called this function (be it an app contract\n /// or a user's account contract).\n ///\n /// # Advanced\n /// * Value is provided by the AVM sender opcode\n /// * In nested calls, this is the immediate caller, not the original transaction sender\n ///\n pub fn maybe_msg_sender(_self: Self) -> Option {\n // Safety: AVM opcodes are constrained by the AVM itself\n let maybe_msg_sender = unsafe { avm::sender() };\n if maybe_msg_sender == NULL_MSG_SENDER_CONTRACT_ADDRESS {\n Option::none()\n } else {\n Option::some(maybe_msg_sender)\n }\n }\n\n /// Returns the function selector of the currently-executing function.\n ///\n /// This is similar to `msg.sig` in Solidity, returning the first 4 bytes of the function signature.\n ///\n /// # Returns\n /// * `FunctionSelector` - The 4-byte function identifier\n ///\n /// # Advanced\n /// * Extracted from the first element of calldata\n /// * Used internally for function dispatch in the AVM\n ///\n pub fn selector(_self: Self) -> FunctionSelector {\n // The selector is the first element of the calldata when calling a public function through dispatch.\n // Safety: AVM opcodes are constrained by the AVM itself.\n let raw_selector: [Field; 1] = unsafe { avm::calldata_copy(0, 1) };\n FunctionSelector::from_field(raw_selector[0])\n }\n\n /// Returns the hash of the arguments passed to the current function.\n ///\n /// Very low-level function: The #[external(\"public\")] macro uses this internally. Smart contract developers\n /// typically won't need to access this directly as arguments are automatically made available.\n ///\n /// # Returns\n /// * `Field` - Hash of the function arguments\n ///\n pub fn get_args_hash(mut self) -> Field {\n if !self.args_hash.is_some() {\n self.args_hash = Option::some((self.compute_args_hash)());\n }\n\n self.args_hash.unwrap_unchecked()\n }\n\n /// Returns the \"transaction fee\" for the current transaction. This is the final tx fee that will be deducted from\n /// the fee_payer's \"fee-juice\" balance (in the protocol's Base Rollup circuit).\n ///\n /// # Returns\n /// * `Field` - The actual, final cost of the transaction, taking into account: the actual gas used during the\n /// setup and app-logic phases, and the fixed amount of gas that's been allocated by the user for the teardown\n /// phase. I.e. effectiveL2FeePerGas * l2GasUsed + effectiveDAFeePerGas * daGasUsed\n ///\n /// This will return `0` during the \"setup\" and \"app-logic\" phases of tx execution (because the final tx fee is not\n /// known at that time). This will only return a nonzero value during the \"teardown\" phase of execution, where the\n /// final tx fee can actually be computed.\n ///\n /// Regardless of _when_ this function is called during the teardown phase, it will always return the same final tx\n /// fee value. The teardown phase does not consume a variable amount of gas: it always consumes a pre-allocated\n /// amount of gas, as specified by the user when they generate their tx.\n ///\n pub fn transaction_fee(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::transaction_fee()\n }\n }\n\n /// Returns the chain ID of the current network.\n ///\n /// This is similar to `block.chainid` in Solidity. Returns the unique identifier for the blockchain network this\n /// transaction is executing on.\n ///\n /// Helps prevent cross-chain replay attacks. Useful if implementing multi-chain contract logic.\n ///\n /// # Returns\n /// * `Field` - The chain ID as a field element\n ///\n pub fn chain_id(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::chain_id()\n }\n }\n\n /// Returns the Aztec protocol version that this transaction is executing under. Different versions may have\n /// different rules, opcodes, or cryptographic primitives.\n ///\n /// This is similar to how Ethereum has different EVM versions.\n ///\n /// Useful for forward/backward compatibility checks\n ///\n /// Not to be confused with contract versions; this is the protocol version.\n ///\n /// # Returns\n /// * `Field` - The protocol version as a field element\n ///\n pub fn version(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::version()\n }\n }\n /// Returns the current block number.\n ///\n /// This is similar to `block.number` in Solidity.\n ///\n /// Note: the current block number is only available within a public function (as opposed to a private function).\n ///\n /// Note: the time intervals between blocks should not be relied upon as being consistent:\n /// - Timestamps of blocks fall within a range, rather than at exact regular intervals.\n /// - Slots can be missed.\n /// - Protocol upgrades can completely change the intervals between blocks (and indeed the current roadmap plans to\n /// reduce the time between blocks, eventually). Use `context.timestamp()` for more-reliable time-based logic.\n ///\n /// # Returns\n /// * `u32` - The current block number\n ///\n pub fn block_number(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::block_number()\n }\n }\n\n /// Returns the timestamp of the current block.\n ///\n /// This is similar to `block.timestamp` in Solidity.\n ///\n /// All functions of all transactions in a block share the exact same timestamp (even though technically each\n /// transaction is executed one-after-the-other).\n ///\n /// Important note: Timestamps of Aztec blocks are not at reliably-fixed intervals. The proposer of the block has\n /// some flexibility to choose a timestamp which is in a valid _range_: Obviously the timestamp of this block must\n /// be strictly greater than that of the previous block, and must must be less than the timestamp of whichever\n /// ethereum block the aztec block is proposed to. Furthermore, if the timestamp is not deemed close enough to the\n /// actual current time, the committee of validators will not attest to the block.\n ///\n /// # Returns\n /// * `u64` - Unix timestamp in seconds\n ///\n pub fn timestamp(_self: Self) -> u64 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::timestamp()\n }\n }\n\n /// Returns the fee per unit of L2 gas for this transaction (aka the \"L2 gas price\"), as chosen by the user.\n ///\n /// L2 gas covers the cost of executing public functions and handling side-effects within the AVM.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of L2 gas\n ///\n /// Wallet developers should be mindful that the choice of gas price (which is publicly visible) can leak\n /// information about the user, e.g.:\n /// - which wallet software the user is using;\n /// - the amount of time which has elapsed from the time the user's wallet chose a gas price (at the going rate),\n /// to the time of tx submission. This can give clues about the proving time, and hence the nature of the tx.\n /// - the urgency of the transaction (which is kind of unavoidable, if the tx is indeed urgent).\n /// - the wealth of the user.\n /// - the exact user (if the gas price is explicitly chosen by the user to be some unique number like 0.123456789,\n /// or their favorite number). Wallet devs might wish to consider fuzzing the choice of gas price.\n ///\n pub fn min_fee_per_l2_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_l2_gas()\n }\n }\n\n /// Returns the fee per unit of DA (Data Availability) gas (aka the \"DA gas price\").\n ///\n /// DA gas covers the cost of making transaction data available on L1.\n ///\n /// See the warning in `min_fee_per_l2_gas` for how gas prices can be leaky.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of DA gas\n ///\n pub fn min_fee_per_da_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_da_gas()\n }\n }\n\n /// Returns the remaining L2 gas available for this transaction.\n ///\n /// Different AVM opcodes consume different amounts of gas.\n ///\n /// # Returns\n /// * `u32` - Remaining L2 gas units\n ///\n pub fn l2_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::l2_gas_left()\n }\n }\n\n /// Returns the remaining DA (Data Availability) gas available for this transaction.\n ///\n /// DA gas is consumed when emitting data that needs to be made available on L1, such as public logs or state\n /// updates. All of the side-effects from the private part of the tx also consume DA gas before execution of any\n /// public functions even begins.\n ///\n /// # Returns\n /// * `u32` - Remaining DA gas units\n ///\n pub fn da_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::da_gas_left()\n }\n }\n\n /// Checks if the current execution is within a staticcall context, where no state changes or logs are allowed to\n /// be emitted (by this function or any nested function calls).\n ///\n /// # Returns\n /// * `bool` - True if in staticcall context, false otherwise\n ///\n pub fn is_static_call(_self: Self) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::is_static_call()\n }\n }\n\n /// Reads raw field values from public storage. Reads N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to read from\n ///\n /// # Returns\n /// * `[Field; N]` - Array of N field values from consecutive storage slots\n ///\n /// # Generic Parameters\n /// * `N` - the number of consecutive slots to return, starting from the `storage_slot`.\n ///\n pub fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n let mut out = [0; N];\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n out[i] = unsafe { avm::storage_read(storage_slot + i as Field, self.this_address().to_field()) };\n }\n out\n }\n\n /// Reads a typed value from public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to read from\n ///\n /// # Returns\n /// * `T` - The deserialized value from storage\n ///\n /// # Generic Parameters\n /// * `T` - The type that the caller expects to read from the `storage_slot`.\n ///\n pub fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n\n /// Writes raw field values to public storage. Writes to N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// Public storage writes take effect immediately.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to write to\n /// * `values` - Array of N Fields to write to storage\n ///\n pub fn raw_storage_write(_self: Self, storage_slot: Field, values: [Field; N]) {\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::storage_write(storage_slot + i as Field, values[i]) };\n }\n }\n\n /// Writes a typed value to public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to write to\n /// * `value` - The typed value to write to storage\n ///\n /// # Generic Parameters\n /// * `T` - The type to write to storage.\n ///\n pub fn storage_write(self, storage_slot: Field, value: T)\n where\n T: Packable,\n {\n self.raw_storage_write(storage_slot, value.pack());\n }\n}\n\nimpl Empty for PublicContext {\n fn empty() -> Self {\n PublicContext::new(|| 0)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/public_context.nr","function_locations":[{"start":3353,"name":"::eq"},{"start":3938,"name":"PublicContext::new"},{"start":4887,"name":"PublicContext::emit_public_log_unsafe"},{"start":5811,"name":"PublicContext::note_hash_exists"},{"start":6824,"name":"PublicContext::l1_to_l2_msg_exists"},{"start":10039,"name":"PublicContext::nullifier_exists_unsafe"},{"start":11904,"name":"PublicContext::consume_l1_to_l2_message"},{"start":14021,"name":"PublicContext::message_portal"},{"start":14911,"name":"PublicContext::call_public_function"},{"start":16543,"name":"PublicContext::static_call_public_function"},{"start":18327,"name":"PublicContext::push_note_hash"},{"start":19766,"name":"PublicContext::push_nullifier"},{"start":20356,"name":"PublicContext::this_address"},{"start":21451,"name":"PublicContext::maybe_msg_sender"},{"start":22223,"name":"PublicContext::selector"},{"start":22962,"name":"PublicContext::get_args_hash"},{"start":24354,"name":"PublicContext::transaction_fee"},{"start":24943,"name":"PublicContext::chain_id"},{"start":25613,"name":"PublicContext::version"},{"start":26553,"name":"PublicContext::block_number"},{"start":27665,"name":"PublicContext::timestamp"},{"start":28946,"name":"PublicContext::min_fee_per_l2_gas"},{"start":29473,"name":"PublicContext::min_fee_per_da_gas"},{"start":29871,"name":"PublicContext::l2_gas_left"},{"start":30487,"name":"PublicContext::da_gas_left"},{"start":30952,"name":"PublicContext::is_static_call"},{"start":31794,"name":"PublicContext::raw_storage_read"},{"start":32652,"name":"PublicContext::storage_read"},{"start":33320,"name":"PublicContext::raw_storage_write"},{"start":34054,"name":"PublicContext::storage_write"},{"start":34179,"name":"::empty"}]},"70":{"source":"use crate::oracle::{execution::get_utility_context, storage::storage_read};\nuse crate::protocol::{abis::block_header::BlockHeader, address::AztecAddress, traits::Packable};\n\n// If you'll modify this struct don't forget to update utility_context.ts as well.\npub struct UtilityContext {\n block_header: BlockHeader,\n contract_address: AztecAddress,\n}\n\nimpl UtilityContext {\n pub unconstrained fn new() -> Self {\n get_utility_context()\n }\n\n pub unconstrained fn at(contract_address: AztecAddress) -> Self {\n // We get a context with default contract address, and then we construct the final context with the provided\n // contract address.\n let default_context = get_utility_context();\n\n Self { block_header: default_context.block_header, contract_address }\n }\n\n pub fn block_header(self) -> BlockHeader {\n self.block_header\n }\n\n pub fn block_number(self) -> u32 {\n self.block_header.block_number()\n }\n\n pub fn timestamp(self) -> u64 {\n self.block_header.timestamp()\n }\n\n pub fn this_address(self) -> AztecAddress {\n self.contract_address\n }\n\n pub fn version(self) -> Field {\n self.block_header.version()\n }\n\n pub fn chain_id(self) -> Field {\n self.block_header.chain_id()\n }\n\n pub unconstrained fn raw_storage_read(self: Self, storage_slot: Field) -> [Field; N] {\n storage_read(self.block_header, self.this_address(), storage_slot)\n }\n\n pub unconstrained fn storage_read(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/context/utility_context.nr","function_locations":[{"start":416,"name":"UtilityContext::new"},{"start":523,"name":"UtilityContext::at"},{"start":855,"name":"UtilityContext::block_header"},{"start":927,"name":"UtilityContext::block_number"},{"start":1011,"name":"UtilityContext::timestamp"},{"start":1104,"name":"UtilityContext::this_address"},{"start":1177,"name":"UtilityContext::version"},{"start":1257,"name":"UtilityContext::chain_id"},{"start":1404,"name":"UtilityContext::raw_storage_read"},{"start":1596,"name":"UtilityContext::storage_read"}]},"72":{"source":"//! The `self` contract value for public execution contexts.\n\nuse crate::{\n context::{calls::{PublicCall, PublicStaticCall}, PublicContext},\n event::{event_emission::emit_event_in_public, event_interface::EventInterface},\n};\nuse crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Core interface for interacting with aztec-nr contract features in public execution contexts.\n///\n/// This struct is automatically injected into every [`external`](crate::macros::functions::external) and\n/// [`internal`](crate::macros::functions::internal) contract function marked with `\"public\"` by the Aztec macro\n/// system and is accessible through the `self` variable.\n///\n/// ## Type Parameters\n///\n/// - `Storage`: The contract's storage struct (defined with [`storage`](crate::macros::storage::storage), or `()` if\n/// the contract has no storage\n/// - `CallSelf`: Macro-generated type for calling contract's own non-view functions\n/// - `CallSelfStatic`: Macro-generated type for calling contract's own view functions\n/// - `CallInternal`: Macro-generated type for calling internal functions\npub struct ContractSelfPublic {\n /// The address of this contract\n pub address: AztecAddress,\n\n /// The contract's storage instance, representing the struct to which the\n /// [`storage`](crate::macros::storage::storage) macro was applied in your contract. If the contract has no\n /// storage, the type of this will be `()`.\n ///\n /// This storage instance is specialized for the current execution context (public) and\n /// provides access to the contract's state variables.\n ///\n /// ## Developer Note\n ///\n /// If you've arrived here while trying to access your contract's storage while the `Storage` generic type is set\n /// to unit type `()`, it means you haven't yet defined a Storage struct using the\n /// [`storage`](crate::macros::storage::storage) macro in your contract. For guidance on setting this up, please\n /// refer to our docs: https://docs.aztec.network/developers/docs/guides/smart_contracts/storage\n pub storage: Storage,\n\n /// The public execution context.\n pub context: PublicContext,\n\n /// Provides type-safe methods for calling this contract's own non-view functions.\n ///\n /// Example API:\n /// ```noir\n /// self.call_self.some_public_function(args)\n /// ```\n pub call_self: CallSelf,\n\n /// Provides type-safe methods for calling this contract's own view functions.\n ///\n /// Example API:\n /// ```noir\n /// self.call_self_static.some_view_function(args)\n /// ```\n pub call_self_static: CallSelfStatic,\n\n /// Provides type-safe methods for calling internal functions.\n ///\n /// Example API:\n /// ```noir\n /// self.internal.some_internal_function(args)\n /// ```\n pub internal: CallInternal,\n}\n\nimpl ContractSelfPublic {\n /// Creates a new `ContractSelfPublic` instance for a public function.\n ///\n /// This constructor is called automatically by the macro system and should not be called directly.\n pub fn new(\n context: PublicContext,\n storage: Storage,\n call_self: CallSelf,\n call_self_static: CallSelfStatic,\n internal: CallInternal,\n ) -> Self {\n Self { context, storage, address: context.this_address(), call_self, call_self_static, internal }\n }\n\n /// The address of the contract address that made this function call.\n ///\n /// This is similar to Solidity's `msg.sender` value.\n ///\n /// ## Incognito Calls\n ///\n /// Contracts can call public functions from private ones hiding their identity (see\n ///\n /// [`ContractSelfPrivate::enqueue_incognito`](crate::contract_self::ContractSelfPrivate::enqueue_incognito)).\n /// This function reverts when executed in such a context.\n ///\n /// If you need to handle these cases, use [`PublicContext::maybe_msg_sender`].\n pub fn msg_sender(self: Self) -> AztecAddress {\n self.context.maybe_msg_sender().unwrap()\n }\n\n /// Emits an event publicly.\n ///\n /// Public events are emitted as plaintext and are therefore visible to everyone. This is is the same as Solidity\n /// events on EVM chains.\n ///\n /// Unlike private events, they don't require delivery of an event message.\n ///\n /// # Example\n /// ```noir\n /// #[event]\n /// struct Update { value: Field }\n ///\n /// #[external(\"public\")]\n /// fn publish_update(value: Field) {\n /// self.emit(Update { value });\n /// }\n /// ```\n ///\n /// # Cost\n ///\n /// Public event emission is achieved by emitting public transaction logs. A total of `N+1` fields are emitted,\n /// where `N` is the serialization length of the event.\n pub fn emit(&mut self, event: Event)\n where\n Event: EventInterface + Serialize,\n {\n emit_event_in_public(self.context, event);\n }\n\n /// Makes a public contract call.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `call` - The object representing the public function to invoke.\n ///\n /// # Returns\n /// * `T` - Whatever data the called function has returned.\n ///\n /// # Example\n /// ```noir\n /// self.call(Token::at(address).transfer_in_public(recipient, amount));\n /// ```\n ///\n pub unconstrained fn call(self, call: PublicCall) -> T\n where\n T: Deserialize,\n {\n call.call(self.context)\n }\n\n /// Makes a public read-only contract call.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be static calls.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `call` - The object representing the read-only public function to invoke.\n ///\n /// # Returns\n /// * `T` - Whatever data the called function has returned.\n ///\n /// # Example\n /// ```noir\n /// self.view(Token::at(address).balance_of_public(recipient));\n /// ```\n ///\n pub unconstrained fn view(self, call: PublicStaticCall) -> T\n where\n T: Deserialize,\n {\n call.view(self.context)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/contract_self/contract_self_public.nr","function_locations":[{"start":3401,"name":"ContractSelfPublic::new"},{"start":4116,"name":"ContractSelfPublic::msg_sender"},{"start":5004,"name":"ContractSelfPublic::emit"},{"start":5645,"name":"ContractSelfPublic::call"},{"start":6466,"name":"ContractSelfPublic::view"}]},"75":{"source":"use crate::oracle::ephemeral;\nuse crate::protocol::traits::{Deserialize, Serialize};\n\n/// A dynamically sized array that exists only during a single contract call frame.\n///\n/// Ephemeral arrays are backed by in-memory storage on the PXE side rather than a persistent database. Each contract\n/// call frame gets its own isolated slot space of ephemeral arrays. Child simulations cannot see the parent's\n/// ephemeral arrays, and vice versa.\n///\n/// Each logical array operation (push, pop, get, etc.) is a single oracle call, making ephemeral arrays significantly\n/// cheaper than capsule arrays.\n///\n/// ## Use Cases\n///\n/// Ephemeral arrays are designed for passing data between PXE (TypeScript) and contracts (Noir) during simulation,\n/// for example, note validation requests or event validation responses. This data type is appropriate for data that\n/// is not supposed to be persisted.\n///\n/// For data that needs to persist across simulations, contract calls, etc, use\n/// [`CapsuleArray`](crate::capsules::CapsuleArray) instead.\npub struct EphemeralArray {\n pub slot: Field,\n}\n\nimpl EphemeralArray {\n /// Returns a handle to an ephemeral array at the given slot, which may already contain data (e.g. populated\n /// by an oracle).\n pub unconstrained fn at(slot: Field) -> Self {\n Self { slot }\n }\n\n /// Returns the number of elements stored in the array.\n pub unconstrained fn len(self) -> u32 {\n ephemeral::len_oracle(self.slot)\n }\n\n /// Stores a value at the end of the array.\n pub unconstrained fn push(self, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n let _ = ephemeral::push_oracle(self.slot, serialized);\n }\n\n /// Removes and returns the last element. Panics if the array is empty.\n pub unconstrained fn pop(self) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::pop_oracle(self.slot);\n Deserialize::deserialize(serialized)\n }\n\n /// Retrieves the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn get(self, index: u32) -> T\n where\n T: Deserialize,\n {\n let serialized = ephemeral::get_oracle(self.slot, index);\n Deserialize::deserialize(serialized)\n }\n\n /// Overwrites the value stored at `index`. Panics if the index is out of bounds.\n pub unconstrained fn set(self, index: u32, value: T)\n where\n T: Serialize,\n {\n let serialized = value.serialize();\n ephemeral::set_oracle(self.slot, index, serialized);\n }\n\n /// Removes the element at `index`, shifting subsequent elements backward. Panics if out of bounds.\n pub unconstrained fn remove(self, index: u32) {\n ephemeral::remove_oracle(self.slot, index);\n }\n\n /// Removes all elements from the array and returns self for chaining (e.g. `EphemeralArray::at(slot).clear()`\n /// to get a guaranteed-empty array at a given slot).\n pub unconstrained fn clear(self) -> Self {\n ephemeral::clear_oracle(self.slot);\n self\n }\n\n /// Calls a function on each element of the array.\n ///\n /// The function `f` is called once with each array value and its corresponding index. Iteration proceeds\n /// backwards so that it is safe to remove the current element (and only the current element) inside the\n /// callback.\n ///\n /// It is **not** safe to push new elements from inside the callback.\n pub unconstrained fn for_each(self, f: unconstrained fn[Env](u32, T) -> ())\n where\n T: Deserialize,\n {\n let mut i = self.len();\n while i > 0 {\n i -= 1;\n f(i, self.get(i));\n }\n }\n}\n\nmod test {\n use crate::test::helpers::test_environment::TestEnvironment;\n use crate::test::mocks::MockStruct;\n use super::EphemeralArray;\n\n global SLOT: Field = 1230;\n global OTHER_SLOT: Field = 5670;\n\n #[test]\n unconstrained fn empty_array() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn empty_array_read() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.get(0);\n });\n }\n\n #[test(should_fail_with = \"is empty\")]\n unconstrained fn empty_array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n let _: Field = array.pop();\n });\n }\n\n #[test]\n unconstrained fn array_push() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn read_past_len() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n\n let _ = array.get(1);\n });\n }\n\n #[test]\n unconstrained fn array_pop() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.push(10);\n\n let popped: Field = array.pop();\n assert_eq(popped, 10);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 5);\n });\n }\n\n #[test]\n unconstrained fn array_set() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.set(0, 99);\n assert_eq(array.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn array_remove_last() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n array.push(5);\n array.remove(0);\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn array_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n assert_eq(array.len(), 3);\n\n array.remove(1);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 7);\n assert_eq(array.get(1), 9);\n });\n }\n\n #[test]\n unconstrained fn array_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(7);\n array.push(8);\n array.push(9);\n\n array.remove(1);\n array.remove(1);\n array.remove(0);\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn for_each_called_with_all_elements() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n let called_with = &mut BoundedVec::<(u32, Field), 3>::new();\n array.for_each(|index, value| { called_with.push((index, value)); });\n\n assert_eq(called_with.len(), 3);\n assert(called_with.any(|(index, value)| (index == 0) & (value == 4)));\n assert(called_with.any(|(index, value)| (index == 1) & (value == 5)));\n assert(called_with.any(|(index, value)| (index == 2) & (value == 6)));\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_some() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| {\n if index == 1 {\n array.remove(index);\n }\n });\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), 4);\n assert_eq(array.get(1), 6);\n });\n }\n\n #[test]\n unconstrained fn for_each_remove_all() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array = EphemeralArray::at(SLOT);\n\n array.push(4);\n array.push(5);\n array.push(6);\n\n array.for_each(|index, _| { array.remove(index); });\n\n assert_eq(array.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn different_slots_are_isolated() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array_a = EphemeralArray::at(SLOT);\n let array_b = EphemeralArray::at(OTHER_SLOT);\n\n array_a.push(10);\n array_a.push(20);\n array_b.push(99);\n\n assert_eq(array_a.len(), 2);\n assert_eq(array_a.get(0), 10);\n assert_eq(array_a.get(1), 20);\n\n assert_eq(array_b.len(), 1);\n assert_eq(array_b.get(0), 99);\n });\n }\n\n #[test]\n unconstrained fn works_with_multi_field_type() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n\n let a = MockStruct::new(5, 6);\n let b = MockStruct::new(7, 8);\n array.push(a);\n array.push(b);\n\n assert_eq(array.len(), 2);\n assert_eq(array.get(0), a);\n assert_eq(array.get(1), b);\n\n let popped: MockStruct = array.pop();\n assert_eq(popped, b);\n assert_eq(array.len(), 1);\n });\n }\n\n #[test]\n unconstrained fn clear_returns_self() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(array.len(), 0);\n\n array.push(42);\n assert_eq(array.len(), 1);\n assert_eq(array.get(0), 42);\n });\n }\n\n #[test]\n unconstrained fn clear_wipes_previous_data() {\n let env = TestEnvironment::new();\n env.utility_context(|_| {\n let array: EphemeralArray = EphemeralArray::at(SLOT);\n array.push(1);\n array.push(2);\n array.push(3);\n assert_eq(array.len(), 3);\n\n // Clear the same slot, previous data should be gone.\n let fresh: EphemeralArray = EphemeralArray::at(SLOT).clear();\n assert_eq(fresh.len(), 0);\n fresh.push(4);\n assert_eq(fresh.get(0), 4);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/ephemeral/mod.nr","function_locations":[{"start":1305,"name":"EphemeralArray::at"},{"start":1438,"name":"EphemeralArray::len"},{"start":1618,"name":"EphemeralArray::push"},{"start":1888,"name":"EphemeralArray::pop"},{"start":2176,"name":"EphemeralArray::get"},{"start":2475,"name":"EphemeralArray::set"},{"start":2743,"name":"EphemeralArray::remove"},{"start":3022,"name":"EphemeralArray::clear"},{"start":3593,"name":"EphemeralArray::for_each"},{"start":3983,"name":"test::empty_array"},{"start":4280,"name":"test::empty_array_read"},{"start":4550,"name":"test::empty_array_pop"},{"start":4783,"name":"test::array_push"},{"start":5122,"name":"test::read_past_len"},{"start":5376,"name":"test::array_pop"},{"start":5783,"name":"test::array_set"},{"start":6081,"name":"test::array_remove_last"},{"start":6376,"name":"test::array_remove_some"},{"start":6847,"name":"test::array_remove_all"},{"start":7273,"name":"test::for_each_called_with_all_elements"},{"start":8009,"name":"test::for_each_remove_some"},{"start":8561,"name":"test::for_each_remove_all"},{"start":8960,"name":"test::different_slots_are_isolated"},{"start":9534,"name":"test::works_with_multi_field_type"},{"start":10148,"name":"test::clear_returns_self"},{"start":10535,"name":"test::clear_wipes_previous_data"}]},"77":{"source":"use crate::{event::EventSelector, messages::logs::event::MAX_EVENT_SERIALIZED_LEN};\nuse crate::protocol::{\n constants::DOM_SEP__EVENT_COMMITMENT,\n hash::{poseidon2_hash_with_separator, poseidon2_hash_with_separator_bounded_vec},\n traits::{Serialize, ToField},\n};\n\npub trait EventInterface {\n fn get_event_type_id() -> EventSelector;\n}\n\n/// A private event's commitment is a value stored on-chain which is used to verify that the event was indeed emitted.\n///\n/// It requires a `randomness` value that must be produced alongside the event in order to perform said validation.\n/// This random value prevents attacks in which someone guesses plausible events (e.g. 'Alice transfers to Bob an\n/// amount of 10'), since they will not be able to test for existence of their guessed events without brute-forcing the\n/// entire `Field` space by guessing `randomness` values.\npub fn compute_private_event_commitment(event: Event, randomness: Field) -> Field\nwhere\n Event: EventInterface + Serialize,\n{\n poseidon2_hash_with_separator(\n [randomness, Event::get_event_type_id().to_field()].concat(event.serialize()),\n DOM_SEP__EVENT_COMMITMENT,\n )\n}\n\n/// Unconstrained variant of [`compute_private_event_commitment`] which takes the event in serialized form.\n///\n/// This function is unconstrained as the mechanism it uses to compute the commitment would be very inefficient in a\n/// constrained environment (due to the hashing of a dynamically sized array). This is not an issue as it is typically\n/// invoked when processing event messages, which is an unconstrained operation.\npub unconstrained fn compute_private_serialized_event_commitment(\n serialized_event: BoundedVec,\n randomness: Field,\n event_type_id: Field,\n) -> Field {\n let mut commitment_preimage =\n BoundedVec::<_, 2 + MAX_EVENT_SERIALIZED_LEN>::from_array([randomness, event_type_id]);\n commitment_preimage.extend_from_bounded_vec(serialized_event);\n\n poseidon2_hash_with_separator_bounded_vec(commitment_preimage, DOM_SEP__EVENT_COMMITMENT)\n}\n\nmod test {\n use crate::event::event_interface::{\n compute_private_event_commitment, compute_private_serialized_event_commitment, EventInterface,\n };\n use crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN;\n use crate::protocol::traits::{Serialize, ToField};\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn max_size_serialized_event_commitment() {\n let serialized_event = BoundedVec::from_array([0; MAX_EVENT_SERIALIZED_LEN]);\n let _ = compute_private_serialized_event_commitment(serialized_event, 0, 0);\n }\n\n #[test]\n unconstrained fn event_commitment_equivalence() {\n let event = MockEvent::new(VALUE).build_event();\n\n assert_eq(\n compute_private_event_commitment(event, RANDOMNESS),\n compute_private_serialized_event_commitment(\n BoundedVec::from_array(event.serialize()),\n RANDOMNESS,\n MockEvent::get_event_type_id().to_field(),\n ),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_interface.nr","function_locations":[{"start":1013,"name":"compute_private_event_commitment"},{"start":1803,"name":"compute_private_serialized_event_commitment"},{"start":2570,"name":"test::max_size_serialized_event_commitment"},{"start":2814,"name":"test::event_commitment_equivalence"}]},"79":{"source":"use crate::protocol::{hash::poseidon2_hash_bytes, traits::{Deserialize, Empty, FromField, Serialize, ToField}};\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct EventSelector {\n // Low 32 bits of the poseidon2 hash of the event signature.\n inner: u32,\n}\n\nimpl FromField for EventSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for EventSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for EventSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl EventSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n EventSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/event/event_selector.nr","function_locations":[{"start":337,"name":"::from_field"},{"start":449,"name":"::to_field"},{"start":542,"name":"::empty"},{"start":647,"name":"EventSelector::from_u32"},{"start":751,"name":"EventSelector::from_signature"},{"start":985,"name":"EventSelector::zero"}]},"81":{"source":"//! Aztec hash functions.\n\nuse crate::protocol::{\n address::{AztecAddress, EthAddress},\n constants::{\n DOM_SEP__FUNCTION_ARGS, DOM_SEP__MESSAGE_NULLIFIER, DOM_SEP__PUBLIC_BYTECODE, DOM_SEP__PUBLIC_CALLDATA,\n DOM_SEP__SECRET_HASH, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS,\n },\n hash::{poseidon2_hash_subarray, poseidon2_hash_with_separator, sha256_to_field},\n traits::ToField,\n};\n\npub use crate::protocol::hash::compute_siloed_nullifier;\n\npub fn compute_secret_hash(secret: Field) -> Field {\n poseidon2_hash_with_separator([secret], DOM_SEP__SECRET_HASH)\n}\n\npub fn compute_l1_to_l2_message_hash(\n sender: EthAddress,\n chain_id: Field,\n recipient: AztecAddress,\n version: Field,\n content: Field,\n secret_hash: Field,\n leaf_index: Field,\n) -> Field {\n let mut hash_bytes = [0 as u8; 224];\n let sender_bytes: [u8; 32] = sender.to_field().to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n let recipient_bytes: [u8; 32] = recipient.to_field().to_be_bytes();\n let version_bytes: [u8; 32] = version.to_be_bytes();\n let content_bytes: [u8; 32] = content.to_be_bytes();\n let secret_hash_bytes: [u8; 32] = secret_hash.to_be_bytes();\n let leaf_index_bytes: [u8; 32] = leaf_index.to_be_bytes();\n\n for i in 0..32 {\n hash_bytes[i] = sender_bytes[i];\n hash_bytes[i + 32] = chain_id_bytes[i];\n hash_bytes[i + 64] = recipient_bytes[i];\n hash_bytes[i + 96] = version_bytes[i];\n hash_bytes[i + 128] = content_bytes[i];\n hash_bytes[i + 160] = secret_hash_bytes[i];\n hash_bytes[i + 192] = leaf_index_bytes[i];\n }\n\n sha256_to_field(hash_bytes)\n}\n\n// The nullifier of a l1 to l2 message is the hash of the message salted with the secret\npub fn compute_l1_to_l2_message_nullifier(message_hash: Field, secret: Field) -> Field {\n poseidon2_hash_with_separator([message_hash, secret], DOM_SEP__MESSAGE_NULLIFIER)\n}\n\n// Computes the hash of input arguments or return values for private functions, or for authwit creation.\npub fn hash_args(args: [Field; N]) -> Field {\n if args.len() == 0 {\n 0\n } else {\n poseidon2_hash_with_separator(args, DOM_SEP__FUNCTION_ARGS)\n }\n}\n\n// Computes the hash of calldata for public functions.\npub fn hash_calldata_array(calldata: [Field; N]) -> Field {\n poseidon2_hash_with_separator(calldata, DOM_SEP__PUBLIC_CALLDATA)\n}\n\n/// Computes the public bytecode commitment for a contract class. The commitment is `hash([(length | separator),\n/// ...bytecode])`.\n///\n/// @param packed_bytecode - The packed bytecode of the contract class. 0th word is the length in bytes.\n/// packed_bytecode is mutable so that we can avoid copying the array to construct one starting with first_field\n/// instead of length. @returns The public bytecode commitment.\npub fn compute_public_bytecode_commitment(\n mut packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],\n) -> Field {\n // First field element contains the length of the bytecode\n let bytecode_length_in_bytes: u32 = packed_public_bytecode[0] as u32;\n let bytecode_length_in_fields: u32 = (bytecode_length_in_bytes / 31) + (bytecode_length_in_bytes % 31 != 0) as u32;\n // Don't allow empty public bytecode. AVM doesn't handle execution of contracts that exist with empty bytecode.\n assert(bytecode_length_in_fields != 0);\n assert(bytecode_length_in_fields < MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS);\n\n // Packed_bytecode's 0th entry is the length. Append it to the separator before hashing.\n let first_field = DOM_SEP__PUBLIC_BYTECODE.to_field() + (packed_public_bytecode[0] as u64 << 32) as Field;\n packed_public_bytecode[0] = first_field;\n\n // `fields_to_hash` is the number of fields from the start of `packed_public_bytecode` that should be included in\n // the hash. Fields after this length are ignored. +1 to account for the prepended field.\n let num_fields_to_hash = bytecode_length_in_fields + 1;\n\n poseidon2_hash_subarray(packed_public_bytecode, num_fields_to_hash)\n}\n\n#[test]\nunconstrained fn secret_hash_matches_typescript() {\n let secret = 8;\n let hash = compute_secret_hash(secret);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let secret_hash_from_ts = 0x1848b066724ab0ffb50ecb0ee3398eb839f162823d262bad959721a9c13d1e96;\n\n assert_eq(hash, secret_hash_from_ts);\n}\n\n#[test]\nunconstrained fn var_args_hash_matches_typescript() {\n let mut input = [0; 100];\n for i in 0..100 {\n input[i] = i as Field;\n }\n let hash = hash_args(input);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let var_args_hash_from_ts = 0x262e5e121a8efc0382566ab42f0ae2a78bd85db88484f83018fe07fc2552ba0c;\n\n assert_eq(hash, var_args_hash_from_ts);\n}\n\n#[test]\nunconstrained fn compute_calldata_hash() {\n let mut input = [0; 100];\n for i in 0..input.len() {\n input[i] = i as Field;\n }\n let hash = hash_calldata_array(input);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let calldata_hash_from_ts = 0x14a1539bdb1d26e03097cf4d40c87e02ca03f0bb50a3e617ace5a7bfd3943944;\n\n // Used in cpp vm2 tests:\n assert_eq(hash, calldata_hash_from_ts);\n}\n\n#[test]\nunconstrained fn public_bytecode_commitment() {\n let mut input = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS];\n let len = 99;\n for i in 1..len + 1 {\n input[i] = i as Field;\n }\n input[0] = (len as Field) * 31;\n let hash = compute_public_bytecode_commitment(input);\n // Used in cpp vm2 tests:\n assert_eq(hash, 0x09348974e76c3602893d7a4b4bb52c2ec746f1ade5004ac471d0fbb4587a81a6);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/hash.nr","function_locations":[{"start":519,"name":"compute_secret_hash"},{"start":800,"name":"compute_l1_to_l2_message_hash"},{"start":1858,"name":"compute_l1_to_l2_message_nullifier"},{"start":2110,"name":"hash_args"},{"start":2362,"name":"hash_calldata_array"},{"start":2994,"name":"compute_public_bytecode_commitment"},{"start":4153,"name":"secret_hash_matches_typescript"},{"start":4512,"name":"var_args_hash_matches_typescript"},{"start":4922,"name":"compute_calldata_hash"},{"start":5385,"name":"public_bytecode_commitment"}]},"92":{"source":"use crate::protocol::{\n address::aztec_address::AztecAddress,\n constants::{DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, DOM_SEP__ECDH_FIELD_MASK, DOM_SEP__ECDH_SUBKEY},\n hash::poseidon2_hash_with_separator,\n point::Point,\n scalar::Scalar,\n traits::{FromField, ToField},\n};\nuse std::{embedded_curve_ops::multi_scalar_mul, ops::Neg};\n\n/// Computes a standard ECDH shared secret: secret * public_key = shared_secret.\n///\n/// The input secret is known only to one party. The output shared secret can be derived given knowledge of\n/// `public_key`'s key-pair and the public ephemeral secret, using this same function (with reversed inputs).\n///\n/// E.g.: Epk = esk * G // ephemeral key-pair\n/// Pk = sk * G // recipient key-pair\n/// Shared secret S = esk * Pk = sk * Epk\n///\n/// See also: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman\npub fn derive_ecdh_shared_secret(secret: Scalar, public_key: Point) -> Point {\n // TODO(F-553): Drop the `.to_embedded()` / `.into()` round-trip once the custom `Point` wrapper is removed and we\n // use `EmbeddedCurvePoint` directly.\n multi_scalar_mul([public_key.to_embedded()], [secret]).into()\n}\n\n/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.\n///\n/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`\npub(crate) fn compute_app_siloed_shared_secret(shared_secret: Point, contract_address: AztecAddress) -> Field {\n poseidon2_hash_with_separator(\n [shared_secret.x, shared_secret.y, contract_address.to_field()],\n DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET,\n )\n}\n\n/// Derives an indexed subkey from an app-siloed shared secret, used for AES key/IV derivation.\n///\n/// `s_i = h(DOM_SEP__ECDH_SUBKEY + i, s_app)`\npub(crate) fn derive_shared_secret_subkey(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_SUBKEY + index)\n}\n\n/// Derives an indexed field mask from an app-siloed shared secret, used for masking ciphertext fields.\n///\n/// `m_i = h(DOM_SEP__ECDH_FIELD_MASK + i, s_app)`\npub(crate) fn derive_shared_secret_field_mask(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_FIELD_MASK + index)\n}\n\n#[test]\nunconstrained fn test_consistency_with_typescript() {\n let secret = Scalar {\n lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,\n hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,\n };\n let point = Point {\n x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,\n y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,\n is_infinite: false,\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret, point);\n\n // This is just pasted from a test run. The original typescript code from which this could be generated seems to\n // have been deleted by someone, and soon the typescript code for encryption and decryption won't be needed, so\n // this will have to do.\n let hard_coded_shared_secret = Point {\n x: 0x15d55a5b3b2caa6a6207f313f05c5113deba5da9927d6421bcaa164822b911bc,\n y: 0x0974c3d0825031ae933243d653ebb1a0b08b90ee7f228f94c5c74739ea3c871e,\n is_infinite: false,\n };\n assert_eq(shared_secret, hard_coded_shared_secret);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_from_address_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let mut pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let mut pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let address_b = AztecAddress::from_field(pk_b.x);\n\n // We were lazy in deriving the secret keys, and didn't check the resulting y-coordinates of the pk_a or pk_b to be\n // less than half the field modulus. If needed, we negate the pk's so that they yield valid address points. (We\n // could also have negated the secrets, but there's no negate method for EmbeddedCurvesScalar).\n pk_a = if (AztecAddress::from_field(pk_a.x).to_address_point().unwrap().inner == pk_a) {\n pk_a\n } else {\n pk_a.neg()\n };\n pk_b = if (address_b.to_address_point().unwrap().inner == pk_b) {\n pk_b\n } else {\n pk_b.neg()\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, address_b.to_address_point().unwrap().inner);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_app_siloed_shared_secret_differs_per_contract() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(Scalar { lo: 0x3456, hi: 0x4567 }).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n\n let contract_a = AztecAddress::from_field(0xAAAA);\n let contract_b = AztecAddress::from_field(0xBBBB);\n\n let s_app_a = compute_app_siloed_shared_secret(shared_secret, contract_a);\n let s_app_b = compute_app_siloed_shared_secret(shared_secret, contract_b);\n\n assert(s_app_a != s_app_b, \"app-siloed secrets must differ for different contracts\");\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/keys/ecdh_shared_secret.nr","function_locations":[{"start":954,"name":"derive_ecdh_shared_secret"},{"start":1485,"name":"compute_app_siloed_shared_secret"},{"start":1876,"name":"derive_shared_secret_subkey"},{"start":2194,"name":"derive_shared_secret_field_mask"},{"start":2336,"name":"test_consistency_with_typescript"},{"start":3450,"name":"test_shared_secret_computation_in_both_directions"},{"start":4017,"name":"test_shared_secret_computation_from_address_in_both_directions"},{"start":5278,"name":"test_app_siloed_shared_secret_differs_per_contract"}]},"97":{"source":"// Not all log levels are currently used, but we provide the full set so that new call sites can use any level. Because\n// of that we tag all with `#[allow(dead_code)]` to prevent warnings.\n//\n// All wrappers resolve function paths at comptime via `resolve_fn` so that the emitted `Quoted` code works both inside\n// aztec-nr (where `crate::` = aztec) and inside macro-generated contract code (where `crate::` = the contract).\n\nuse std::meta::ctstring::AsCtString;\n\ncomptime fn log_prefix(msg: str) -> CtString {\n \"[aztec-nr] \".as_ctstring().append_str(msg)\n}\n\n// --- No-args variants (direct call) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log });\n quote { $f($msg) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log });\n quote { $f($msg) }\n}\n\n// --- Format variants (return lambda for runtime args) ---\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_fatal_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::fatal_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_error_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::error_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_warn_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::warn_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_info_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::info_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_verbose_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::verbose_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_debug_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::debug_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n#[allow(dead_code)]\npub(crate) comptime fn aztecnr_trace_log_format(msg: str) -> Quoted {\n let msg = log_prefix(msg);\n let f = resolve_fn(quote { crate::protocol::logging::trace_log_format });\n quote { (|args| $f($msg, args)) }\n}\n\n// See module-level comment for why this is needed.\ncomptime fn resolve_fn(path: Quoted) -> TypedExpr {\n path.as_expr().unwrap().resolve(Option::none())\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/logging.nr","function_locations":[{"start":525,"name":"log_prefix"},{"start":717,"name":"aztecnr_fatal_log"},{"start":943,"name":"aztecnr_error_log"},{"start":1168,"name":"aztecnr_warn_log"},{"start":1392,"name":"aztecnr_info_log"},{"start":1619,"name":"aztecnr_verbose_log"},{"start":1847,"name":"aztecnr_debug_log"},{"start":2073,"name":"aztecnr_trace_log"},{"start":2367,"name":"aztecnr_fatal_log_format"},{"start":2622,"name":"aztecnr_error_log_format"},{"start":2876,"name":"aztecnr_warn_log_format"},{"start":3129,"name":"aztecnr_info_log_format"},{"start":3385,"name":"aztecnr_verbose_log_format"},{"start":3642,"name":"aztecnr_debug_log_format"},{"start":3897,"name":"aztecnr_trace_log_format"},{"start":4151,"name":"resolve_fn"}]},"99":{"source":"use crate::logging;\nuse crate::macros::{notes::NOTES, utils::get_trait_impl_method};\n\n/// Generates two contract library methods called `_compute_note_hash` and `_compute_note_nullifier`, plus a\n/// (deprecated) wrapper called `_compute_note_hash_and_nullifier`, which are used for note discovery (i.e. these are\n/// of the `aztec::messages::discovery::ComputeNoteHash` and `aztec::messages::discovery::ComputeNoteNullifier` types).\npub(crate) comptime fn generate_contract_library_methods_compute_note_hash_and_nullifier() -> Quoted {\n let compute_note_hash = generate_contract_library_method_compute_note_hash();\n let compute_note_nullifier = generate_contract_library_method_compute_note_nullifier();\n\n quote {\n $compute_note_hash\n $compute_note_nullifier\n\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n #[allow(dead_code)]\n unconstrained fn _compute_note_hash_and_nullifier(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n note_nonce: Field,\n ) -> Option {\n _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash| {\n\n let siloed_note_hash = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash);\n let unique_note_hash = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash);\n \n let inner_nullifier = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness);\n\n aztec::messages::discovery::NoteHashAndNullifier {\n note_hash,\n inner_nullifier,\n }\n })\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_hash() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the note hash (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_note_hash = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_note_hash },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n Option::some($compute_note_hash(note, owner, storage_slot, randomness))\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed).\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_nullifier() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the inner nullifier (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_nullifier_unconstrained = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_nullifier_unconstrained },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n // The message discovery process finds settled notes, that is, notes that were created in\n // prior transactions and are therefore already part of the note hash tree. The note hash\n // for nullification is hence the unique note hash.\n $compute_nullifier_unconstrained(note, owner, unique_note_hash)\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data.\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec/compute_note_hash_and_nullifier.nr","function_locations":[{"start":534,"name":"generate_contract_library_methods_compute_note_hash_and_nullifier"},{"start":2449,"name":"generate_contract_library_method_compute_note_hash"},{"start":7674,"name":"generate_contract_library_method_compute_note_nullifier"}]},"100":{"source":"mod compute_note_hash_and_nullifier;\n\nuse crate::{\n macros::{\n calls_generation::{\n external_functions::{generate_external_function_calls, generate_external_function_self_calls_structs},\n internal_functions::generate_call_internal_struct,\n },\n dispatch::generate_public_dispatch,\n emit_public_init_nullifier::generate_emit_public_init_nullifier,\n internals_functions_generation::{create_fn_abi_exports, process_functions},\n storage::STORAGE_LAYOUT_NAME,\n utils::{is_fn_contract_library_method, is_fn_external, is_fn_internal, is_fn_test, module_has_storage},\n },\n messages::discovery::CustomMessageHandler,\n};\n\nuse compute_note_hash_and_nullifier::generate_contract_library_methods_compute_note_hash_and_nullifier;\n\n/// Configuration for the [`aztec`] macro.\n///\n/// This type lets users override different parts of the default aztec-nr contract behavior, such\n/// as message handling. These are advanced features that require careful understanding of\n/// the behavior of these systems.\n///\n/// ## Examples\n///\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyContract { ... }\n/// ```\npub struct AztecConfig {\n custom_message_handler: Option>,\n}\n\nimpl AztecConfig {\n /// Creates a new `AztecConfig` with default values.\n ///\n /// Calling `new` is equivalent to invoking the [`aztec`] macro with no parameters. The different methods\n /// (e.g. [`AztecConfig::custom_message_handler`]) can then be used to change the default behavior.\n pub comptime fn new() -> Self {\n Self { custom_message_handler: Option::none() }\n }\n\n /// Sets a handler for custom messages.\n ///\n /// This enables contracts to process non-standard messages (i.e. any with a message type that is not in\n /// [`crate::messages::msg_type`]).\n ///\n /// `handler` must be a function that conforms to the\n /// [`crate::messages::discovery::CustomMessageHandler`] type signature.\n pub comptime fn custom_message_handler(_self: Self, handler: CustomMessageHandler<()>) -> Self {\n Self { custom_message_handler: Option::some(handler) }\n }\n}\n\n/// Enables aztec-nr features on a `contract`.\n///\n/// All aztec-nr contracts should have this macro invoked on them, as it is the one that processes all contract\n/// functions, notes, storage, generates interfaces for external calls, and creates the message processing\n/// boilerplate.\n///\n/// ## Examples\n///\n/// Most contracts can simply invoke the macro with no parameters, resulting in default aztec-nr behavior:\n/// ```noir\n/// #[aztec]\n/// contract MyContract { ... }\n/// ```\n///\n/// Advanced contracts can use [`AztecConfig`] to customize parts of its behavior, such as message\n/// processing.\n/// ```noir\n/// #[aztec(aztec::macros::AztecConfig::new().custom_message_handler(my_handler))]\n/// contract MyAdvancedContract { ... }\n/// ```\n#[varargs]\npub comptime fn aztec(m: Module, args: [AztecConfig]) -> Quoted {\n let num_args = args.len();\n let config = if num_args == 0 {\n AztecConfig::new()\n } else if num_args == 1 {\n args[0]\n } else {\n panic(f\"#[aztec] expects 0 or 1 arguments, got {num_args}\")\n };\n\n // Functions that don't have #[external(...)], #[contract_library_method], or #[test] are not allowed in contracts.\n check_each_fn_macroified(m);\n\n // We generate new functions prefixed with `__aztec_nr_internals__` and we replace the original functions' bodies\n // with `static_assert(false, ...)` to prevent them from being called directly from within the contract.\n let functions = process_functions(m);\n\n // We generate structs and their implementations necessary for convenient functions calls.\n let interface = generate_contract_interface(m);\n let self_call_structs = generate_external_function_self_calls_structs(m);\n let call_internal_struct = generate_call_internal_struct(m);\n\n // We generate ABI exports for all the external functions in the contract.\n let fn_abi_exports = create_fn_abi_exports(m);\n\n // We generate `_compute_note_hash`, `_compute_note_nullifier` (and the deprecated\n // `_compute_note_hash_and_nullifier` wrapper) and `sync_state` functions only if they are not already implemented.\n // If they are implemented we just insert empty quotes.\n let contract_library_method_compute_note_hash_and_nullifier = if !m.functions().any(|f| {\n // Note that we don't test for `_compute_note_hash` or `_compute_note_nullifier` in order to make this simpler\n // - users must either implement all three or none.\n // Down the line we'll remove this check and use `AztecConfig`.\n f.name() == quote { _compute_note_hash_and_nullifier }\n }) {\n generate_contract_library_methods_compute_note_hash_and_nullifier()\n } else {\n quote {}\n };\n let process_custom_message_option = if config.custom_message_handler.is_some() {\n let handler = config.custom_message_handler.unwrap();\n quote { Option::some($handler) }\n } else {\n quote { Option::>::none() }\n };\n\n let offchain_inbox_sync_option = quote {\n Option::some(aztec::messages::processing::offchain::sync_inbox)\n };\n\n let sync_state_fn_and_abi_export = if !m.functions().any(|f| f.name() == quote { sync_state }) {\n generate_sync_state(process_custom_message_option, offchain_inbox_sync_option)\n } else {\n quote {}\n };\n\n if m.functions().any(|f| f.name() == quote { offchain_receive }) {\n panic(\n \"User-defined 'offchain_receive' is not allowed. The function is auto-injected by the #[aztec] macro. See https://docs.aztec.network/errors/7\",\n );\n }\n let offchain_receive_fn_and_abi_export = generate_offchain_receive();\n\n let (has_public_init_nullifier_fn, emit_public_init_nullifier_fn_body) = generate_emit_public_init_nullifier(m);\n let public_dispatch = generate_public_dispatch(m, has_public_init_nullifier_fn);\n\n quote {\n $interface\n $self_call_structs\n $call_internal_struct\n $functions\n $fn_abi_exports\n $contract_library_method_compute_note_hash_and_nullifier\n $public_dispatch\n $sync_state_fn_and_abi_export\n $emit_public_init_nullifier_fn_body\n $offchain_receive_fn_and_abi_export\n }\n}\n\ncomptime fn generate_contract_interface(m: Module) -> Quoted {\n let calls = generate_external_function_calls(m);\n\n let module_name = m.name();\n\n let has_storage_layout = module_has_storage(m) & STORAGE_LAYOUT_NAME.get(m).is_some();\n let storage_layout_getter = if has_storage_layout {\n let storage_layout_name = STORAGE_LAYOUT_NAME.get(m).unwrap();\n quote {\n pub fn storage_layout() -> StorageLayoutFields {\n $storage_layout_name.fields\n }\n }\n } else {\n quote {}\n };\n\n let library_storage_layout_getter = if has_storage_layout {\n quote {\n #[contract_library_method]\n $storage_layout_getter\n }\n } else {\n quote {}\n };\n\n quote {\n pub struct $module_name {\n pub target_contract: aztec::protocol::address::AztecAddress\n }\n\n impl $module_name {\n $calls\n\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> Self {\n Self { target_contract: addr }\n }\n\n pub fn interface() -> Self {\n Self { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $storage_layout_getter\n }\n\n #[contract_library_method]\n pub fn at(\n addr: aztec::protocol::address::AztecAddress\n ) -> $module_name {\n $module_name { target_contract: addr }\n }\n\n #[contract_library_method]\n pub fn interface() -> $module_name {\n $module_name { target_contract: aztec::protocol::address::AztecAddress::zero() }\n }\n\n $library_storage_layout_getter\n\n }\n}\n\n/// Generates the `sync_state` utility function that performs message discovery.\ncomptime fn generate_sync_state(process_custom_message_option: Quoted, offchain_inbox_sync_option: Quoted) -> Quoted {\n quote {\n pub struct sync_state_parameters {\n pub scope: aztec::protocol::address::AztecAddress,\n }\n\n #[abi(functions)]\n pub struct sync_state_abi {\n parameters: sync_state_parameters,\n }\n\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn sync_state(scope: aztec::protocol::address::AztecAddress) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::discovery::do_sync_state(\n address,\n _compute_note_hash,\n _compute_note_nullifier,\n $process_custom_message_option,\n $offchain_inbox_sync_option,\n scope,\n );\n }\n }\n}\n\n/// Generates an `offchain_receive` utility function that lets callers add messages to the offchain message inbox.\n///\n/// For more details, see `aztec::messages::processing::offchain::receive`.\ncomptime fn generate_offchain_receive() -> Quoted {\n quote {\n pub struct offchain_receive_parameters {\n pub messages: BoundedVec<\n aztec::messages::processing::offchain::OffchainMessage,\n aztec::messages::processing::offchain::MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL,\n >,\n }\n\n #[abi(functions)]\n pub struct offchain_receive_abi {\n parameters: offchain_receive_parameters,\n }\n\n /// Receives offchain messages into this contract's offchain inbox for subsequent processing.\n ///\n /// Each message is routed to the inbox scoped to its `recipient` field.\n ///\n /// For more details, see `aztec::messages::processing::offchain::receive`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]\n unconstrained fn offchain_receive(\n messages: BoundedVec<\n aztec::messages::processing::offchain::OffchainMessage,\n aztec::messages::processing::offchain::MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL,\n >,\n ) {\n let address = aztec::context::UtilityContext::new().this_address();\n aztec::messages::processing::offchain::receive(address, messages);\n }\n }\n}\n\n/// Checks that all functions in the module have a context macro applied.\n///\n/// Non-macroified functions are not allowed in contracts. They must all be one of\n/// [`crate::macros::functions::external`], [`crate::macros::functions::internal`] or `test`.\ncomptime fn check_each_fn_macroified(m: Module) {\n for f in m.functions() {\n let name = f.name();\n if !is_fn_external(f) & !is_fn_contract_library_method(f) & !is_fn_internal(f) & !is_fn_test(f) {\n // We don't suggest that #[contract_library_method] is allowed because we don't want to introduce another\n // concept\n panic(\n f\"Function {name} must be marked as either #[external(...)], #[internal(...)], or #[test]\",\n );\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec.nr","function_locations":[{"start":1648,"name":"AztecConfig::new"},{"start":2156,"name":"AztecConfig::custom_message_handler"},{"start":3050,"name":"aztec"},{"start":6527,"name":"generate_contract_interface"},{"start":8389,"name":"generate_sync_state"},{"start":9443,"name":"generate_offchain_receive"},{"start":11087,"name":"check_each_fn_macroified"}]},"105":{"source":"use crate::macros::internals_functions_generation::external_functions_registry::get_public_functions;\nuse crate::protocol::meta::utils::get_params_len_quote;\nuse crate::utils::cmap::CHashMap;\nuse super::functions::initialization_utils::EMIT_PUBLIC_INIT_NULLIFIER_FN_NAME;\nuse super::utils::compute_fn_selector;\nuse std::panic;\n\n/// Generates a `public_dispatch` function for an Aztec contract module `m`.\n///\n/// The generated function dispatches public calls based on selector to the appropriate contract function. If\n/// `generate_emit_public_init_nullifier` is true, it also handles dispatch to the macro-generated\n/// `__emit_public_init_nullifier` function.\npub comptime fn generate_public_dispatch(m: Module, generate_emit_public_init_nullifier: bool) -> Quoted {\n let functions = get_public_functions(m);\n\n let unit = get_type::<()>();\n\n let seen_selectors = &mut CHashMap::::new();\n\n let mut ifs = functions.map(|function: FunctionDefinition| {\n let parameters = function.parameters();\n let return_type = function.return_type();\n\n let fn_name = function.name();\n let selector: Field = compute_fn_selector(fn_name, parameters);\n\n // Since function selectors are computed as the first 4 bytes of the hash of the function signature, it's\n // possible to have collisions. With the following check, we ensure it doesn't happen within the same contract.\n let existing_fn = seen_selectors.get(selector);\n if existing_fn.is_some() {\n let existing_fn = existing_fn.unwrap();\n panic(\n f\"Public function selector collision detected between functions '{fn_name}' and '{existing_fn}'\",\n );\n }\n seen_selectors.insert(selector, fn_name);\n\n let params_len_quote = get_params_len_quote(parameters);\n\n let initial_read = if parameters.len() == 0 {\n quote {}\n } else {\n // The initial calldata_copy offset is 1 to skip the Field selector The expected calldata is the\n // serialization of\n // - FunctionSelector: the selector of the function intended to dispatch\n // - Parameters: the parameters of the function intended to dispatch That is, exactly what is expected for\n // a call to the target function, but with a selector added at the beginning.\n quote {\n let input_calldata: [Field; $params_len_quote] = aztec::oracle::avm::calldata_copy(1, $params_len_quote);\n let mut reader = aztec::protocol::utils::reader::Reader::new(input_calldata);\n }\n };\n\n let parameter_index: &mut u32 = &mut 0;\n let reads = parameters.map(|param: (Quoted, Type)| {\n let parameter_index_value = *parameter_index;\n let param_name = f\"arg{parameter_index_value}\".quoted_contents();\n let param_type = param.1;\n let read = quote {\n let $param_name: $param_type = aztec::protocol::traits::Deserialize::stream_deserialize(&mut reader);\n };\n *parameter_index += 1;\n quote { $read }\n });\n let read = reads.join(quote { });\n\n let mut args = @[];\n for parameter_index in 0..parameters.len() {\n let param_name = f\"arg{parameter_index}\".quoted_contents();\n args = args.push_back(quote { $param_name });\n }\n\n // We call a function whose name is prefixed with `__aztec_nr_internals__`. This is necessary because the\n // original function is intentionally made uncallable, preventing direct invocation within the contract.\n // Instead, a new function with the same name, but prefixed by `__aztec_nr_internals__`, has been generated to\n // be called here. For more details see the `process_functions` function.\n let name = f\"__aztec_nr_internals__{fn_name}\".quoted_contents();\n let args = args.join(quote { , });\n let call = quote { $name($args) };\n\n let return_code = if return_type == unit {\n quote {\n $call;\n // Force early return.\n aztec::oracle::avm::avm_return([]);\n }\n } else {\n quote {\n let return_value = aztec::protocol::traits::Serialize::serialize($call);\n aztec::oracle::avm::avm_return(return_value.as_vector());\n }\n };\n\n let if_ = quote {\n if selector == $selector {\n $initial_read\n $read\n $return_code\n }\n };\n if_\n });\n\n // If we injected the auto-generated public function to emit the public initialization nullifier, then\n // we'll also need to handle its dispatch.\n if generate_emit_public_init_nullifier {\n let name = EMIT_PUBLIC_INIT_NULLIFIER_FN_NAME;\n let init_nullifier_selector: Field = compute_fn_selector(name, @[]);\n\n ifs = ifs.push_back(\n quote {\n if selector == $init_nullifier_selector {\n $name();\n aztec::oracle::avm::avm_return([]);\n }\n },\n );\n }\n\n if ifs.len() == 0 {\n // No dispatch function if there are no public functions\n quote {}\n } else {\n let ifs = ifs.push_back(quote { panic(f\"Unknown selector {selector}\") });\n let dispatch = ifs.join(quote { });\n\n let body = quote {\n // We mark this as public because our whole system depends on public functions having this attribute.\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]\n pub unconstrained fn public_dispatch(selector: Field) {\n $dispatch\n }\n };\n\n body\n }\n}\n\ncomptime fn get_type() -> Type {\n let t: T = std::mem::zeroed();\n std::meta::type_of(t)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/dispatch.nr","function_locations":[{"start":768,"name":"generate_public_dispatch"},{"start":5832,"name":"get_type"}]},"113":{"source":"use crate::macros::{\n functions::auth_registry::AUTHORIZE_ONCE_REGISTRY,\n utils::{is_fn_initializer, is_fn_only_self, is_fn_view},\n};\n\n/// Gathers all attributes relevant to the function's ABI and returns a quote that can be applied to the newly\n/// generated function. We apply the abi marker attributes instead of the original ones (e.g. abi_view instead of view)\n/// to avoid the relevant attribute's functionality from getting triggered.\npub(crate) comptime fn get_abi_relevant_attributes(f: FunctionDefinition) -> Quoted {\n let mut attributes = quote {};\n\n if is_fn_view(f) {\n attributes = quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_view] };\n }\n\n if is_fn_only_self(f) {\n attributes =\n quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_only_self] };\n }\n\n if is_fn_initializer(f) {\n attributes =\n quote { $attributes #[aztec::macros::internals_functions_generation::abi_attributes::abi_initializer] };\n }\n\n attributes\n}\n\n/// Injects an authwit verification check of the form:\n/// ```\n/// if (!from.eq(context.maybe_msg_sender().unwrap())) {\n/// assert_current_call_valid_authwit::(&mut context, from);\n/// } else {\n/// assert(authwit_nonce, \"Invalid authwit nonce. When 'from' and 'msg_sender' are the\n/// same, authwit_nonce must be zero\");\n/// }\n/// ```\n/// where `from` and `authwit_nonce` are the names of the parameters that are expected to be present in the function\n/// definition. This check is injected by the `#[authorize_once(\"from_arg_name\", \"nonce_arg_name\")]`, which allows the\n/// user to define which parameters to use.\n///\n/// # Arguments\n/// * `f` - The function definition to inject the authwit verification check into. The function must have parameters\n/// matching the names specified in the `#[authorize_once]` attribute.\n/// * `is_private` - Whether the function is a private function (`true`) or a public function (`false`). This\n/// determines which authwit verification method to use: `assert_current_call_valid_authwit` for private functions or\n/// `assert_current_call_valid_authwit_public` for public functions.\npub(crate) comptime fn create_authorize_once_check(f: FunctionDefinition, is_private: bool) -> Quoted {\n let maybe_authorize_once_args = AUTHORIZE_ONCE_REGISTRY.get(f);\n let authorize_once_args = if maybe_authorize_once_args.is_some() {\n maybe_authorize_once_args.unwrap()\n } else {\n // We need to for authorize_once to have already executed so that we can retrieve its params - this depends on\n // the order in which the attributes are applied.\n panic(\n f\"Functions marked with #[authorize_once] must have the #[external(\\\"private\\\")] or #[external(\\\"public\\\")] attribute placed last\",\n )\n };\n\n let (from_arg_name, nonce_arg_name) = authorize_once_args;\n let name: Quoted = f.name();\n\n let from_arg_candidates = f.parameters().filter(|(name, _)| name == f\"{from_arg_name}\".quoted_contents());\n let (from_arg_name_quoted, from_arg_type) = if from_arg_candidates.len() == 1 {\n from_arg_candidates[0]\n } else {\n panic(\n f\"Function {name} does not have a {from_arg_name} parameter. Please specify which one to use in #[authorize_once(\\\"...\\\", \\\"authwit_nonce\\\")]\",\n )\n };\n if from_arg_type != quote { crate::protocol::address::aztec_address::AztecAddress }.as_type() {\n panic(\n f\"Argument {from_arg_name_quoted} in function {name} must be of type AztecAddress, but is of type {from_arg_type}\",\n )\n }\n\n let nonce_arg_candidates = f.parameters().filter(|(name, _)| name == f\"{nonce_arg_name}\".quoted_contents());\n let (nonce_arg_name_quoted, nonce_arg_type) = if nonce_arg_candidates.len() == 1 {\n nonce_arg_candidates[0]\n } else {\n panic(\n f\"Function {name} does not have a {nonce_arg_name}. Please specify which one to use in #[authorize_once(\\\"from\\\", \\\"...\\\")]\",\n )\n };\n if nonce_arg_type != quote { Field }.as_type() {\n panic(\n f\"Argument {nonce_arg_name_quoted} in function {name} must be of type Field, but is of type {nonce_arg_type}\",\n );\n }\n\n let nonce_check_quote = f\"{nonce_arg_name_quoted} == 0\".quoted_contents();\n\n let fn_call = if is_private {\n let params = f.parameters();\n let serialized_len_quote = if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as aztec::protocol::traits::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n };\n quote { aztec::authwit::auth::assert_current_call_valid_authwit::<($serialized_len_quote)> }\n } else {\n quote { aztec::authwit::auth::assert_current_call_valid_authwit_public }\n };\n let invalid_nonce_message = f\"Invalid authwit nonce. When '{from_arg_name}' and 'msg_sender' are the same, '{nonce_arg_name}' must be zero\"\n .as_quoted_str();\n quote { \n if (!$from_arg_name_quoted.eq(self.msg_sender())) {\n $fn_call(self.context, $from_arg_name_quoted);\n } else {\n assert($nonce_check_quote, $invalid_nonce_message);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/helpers.nr","function_locations":[{"start":532,"name":"get_abi_relevant_attributes"},{"start":2334,"name":"create_authorize_once_check"}]},"116":{"source":"use crate::macros::{\n internals_functions_generation::external::helpers::{create_authorize_once_check, get_abi_relevant_attributes},\n utils::{\n fn_has_authorize_once, fn_has_noinitcheck, is_fn_initializer, is_fn_only_self, is_fn_view,\n module_has_initializer, module_has_storage,\n },\n};\n\npub(crate) comptime fn generate_public_external(f: FunctionDefinition) -> Quoted {\n let module_has_initializer = module_has_initializer(f.module());\n let module_has_storage = module_has_storage(f.module());\n\n // Public functions undergo a lot of transformations from their Aztec.nr form.\n let original_params = f.parameters();\n\n let args_len_quote = if original_params.len() == 0 {\n // If the function has no parameters, we set the args_len to 0.\n quote { 0 }\n } else {\n // The following will give us ::N + ::N + ...\n original_params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::protocol::traits::Serialize>::N\n }\n })\n .join(quote {+})\n };\n\n let storage_init = if module_has_storage {\n quote {\n let storage = Storage::init(context);\n }\n } else {\n // Contract does not have Storage defined, so we set storage to the unit type `()`. ContractSelfPublic requires\n // a storage struct in its constructor. Using an Option type would lead to worse developer experience and\n // higher constraint counts so we use the unit type `()` instead.\n quote {\n let storage = ();\n }\n };\n\n // Unlike in the private case, in public the `context` does not need to receive the hash of the original params.\n let contract_self_creation = quote {\n #[allow(unused_variables)]\n let mut self = {\n let context = aztec::context::PublicContext::new(|| {\n // We start from 1 because we skip the selector for the dispatch function.\n let serialized_args : [Field; $args_len_quote] = aztec::oracle::avm::calldata_copy(1, $args_len_quote);\n aztec::hash::hash_args(serialized_args)\n });\n $storage_init\n let self_address = context.this_address();\n let call_self: CallSelf = CallSelf { address: self_address, context };\n let call_self_static: CallSelfStatic = CallSelfStatic { address: self_address, context };\n let internal: CallInternal = CallInternal { context };\n aztec::contract_self::ContractSelfPublic::new(context, storage, call_self, call_self_static, internal)\n };\n };\n\n let original_function_name = f.name();\n\n // Modifications introduced by the different marker attributes.\n let internal_check = if is_fn_only_self(f) {\n let assertion_message = f\"Function {original_function_name} can only be called by the same contract\";\n quote { assert(self.msg_sender() == self.address, $assertion_message); }\n } else {\n quote {}\n };\n\n let view_check = if is_fn_view(f) {\n let assertion_message = f\"Function {original_function_name} can only be called statically\".as_quoted_str();\n quote { assert(self.context.is_static_call(), $assertion_message); }\n } else {\n quote {}\n };\n\n let (assert_initializer, mark_as_initialized) = if is_fn_initializer(f) {\n (\n quote { aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_public(self.context); },\n quote { aztec::macros::functions::initialization_utils::mark_as_initialized_from_public_initializer(self.context); },\n )\n } else {\n (quote {}, quote {})\n };\n\n // Initialization checks are not included in contracts that don't have initializers.\n let init_check = if module_has_initializer & !fn_has_noinitcheck(f) & !is_fn_initializer(f) {\n quote { aztec::macros::functions::initialization_utils::assert_is_initialized_public(self.context); }\n } else {\n quote {}\n };\n\n // Inject the authwit check if the function is marked with #[authorize_once].\n let authorize_once_check = if fn_has_authorize_once(f) {\n create_authorize_once_check(f, false)\n } else {\n quote {}\n };\n\n let to_prepend = quote {\n $contract_self_creation\n $assert_initializer\n $init_check\n $internal_check\n $view_check\n $authorize_once_check\n };\n\n // `mark_as_initialized` is placed after the user's function body. If it ran at the beginning, the contract\n // would appear initialized while the initializer is still running, allowing contracts called by the initializer\n // to re-enter into a half-initialized contract.\n let to_append = quote {\n $mark_as_initialized\n };\n\n let fn_name = f\"__aztec_nr_internals__{original_function_name}\".quoted_contents();\n let body = f.body();\n let return_type = f.return_type();\n\n // New function parameters are the same as the original function's ones.\n let params = original_params.map(|(param_name, param_type)| quote { $param_name: $param_type }).join(quote {, });\n\n // Preserve all attributes that are relevant to the function's ABI.\n let abi_relevant_attributes = get_abi_relevant_attributes(f);\n\n // All public functions are automatically made unconstrained, even if they were not marked as such. This is because\n // instead of compiling into a circuit, they will compile to bytecode that will be later transpiled into AVM\n // bytecode.\n quote {\n #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]\n $abi_relevant_attributes\n unconstrained fn $fn_name($params) -> pub $return_type {\n $to_prepend\n $body\n $to_append\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/internals_functions_generation/external/public.nr","function_locations":[{"start":392,"name":"generate_public_external"}]},"126":{"source":"use crate::logging::{aztecnr_debug_log, aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\npub(crate) mod nonce_discovery;\npub(crate) mod partial_notes;\npub(crate) mod private_events;\npub mod private_notes;\npub mod process_message;\n\nuse crate::{\n messages::{\n discovery::process_message::process_message_ciphertext,\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{\n MessageContext, offchain::OffchainInboxSync, OffchainMessageWithContext,\n pending_tagged_log::PendingTaggedLog, validate_and_store_enqueued_notes_and_events,\n },\n },\n oracle::message_processing,\n utils::array,\n};\n\npub struct NoteHashAndNullifier {\n /// The result of [`crate::note::note_interface::NoteHash::compute_note_hash`].\n pub note_hash: Field,\n /// The result of [`crate::note::note_interface::NoteHash::compute_nullifier_unconstrained`].\n ///\n /// This value is unconstrained, as all of message discovery is unconstrained. It is `None` if the nullifier\n /// cannot be computed (e.g. because the nullifier hiding key is not available).\n pub inner_nullifier: Option,\n}\n\n/// A contract's way of computing note hashes.\n///\n/// Each contract in the network is free to compute their note's hash as they see fit - the hash function itself is not\n/// enshrined or standardized. Some aztec-nr functions however do need to know the details of this computation (e.g.\n/// when finding new notes), which is what this type represents.\n///\n/// This function takes a note's packed content, storage slot, note type ID, address of the emitting contract and\n/// randomness, and attempts to compute its inner note hash (not siloed by address nor uniqued by nonce).\n///\n/// ## Transient Notes\n///\n/// This function is meant to always be used on **settled** notes, i.e. those that have been inserted into the trees\n/// and for which the nonce is known. It is never invoked in the context of a transient note, as those are not involved\n/// in message processing.\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract by inspecting all note types in use and the storage layout. This injected function is a\n/// `#[contract_library_method]` called `_compute_note_hash`, and it looks something like this:\n///\n/// ```noir\n/// |packed_note, owner, storage_slot, note_type_id, _contract_address, randomness| {\n/// if note_type_id == MyNoteType::get_id() {\n/// if packed_note.len() != MY_NOTE_TYPE_SERIALIZATION_LENGTH {\n/// Option::none()\n/// } else {\n/// let note = MyNoteType::unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n/// Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n/// }\n/// } else if note_type_id == MyOtherNoteType::get_id() {\n/// ... // Similar to above but calling MyOtherNoteType::unpack\n/// } else {\n/// Option::none() // Unknown note type ID\n/// };\n/// }\n/// ```\npub type ComputeNoteHash = unconstrained fn(/* packed_note */BoundedVec, /*\n owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress, /*\nrandomness */ Field) -> Option;\n\n/// A contract's way of computing note nullifiers.\n///\n/// Like [`ComputeNoteHash`], each contract is free to derive nullifiers as they see fit. This function takes the\n/// unique note hash (used as the note hash for nullification for settled notes), plus the note's packed content and\n/// metadata, and attempts to compute the inner nullifier (not siloed by address).\n///\n/// ## Automatic Implementation\n///\n/// The [`[#aztec]`](crate::macros::aztec::aztec) macro automatically creates a correct implementation of this function\n/// for each contract called `_compute_note_nullifier`. It dispatches on `note_type_id` similarly to\n/// [`ComputeNoteHash`], then calls the note's\n/// [`compute_nullifier_unconstrained`](crate::note::note_interface::NoteHash::compute_nullifier_unconstrained) method.\npub type ComputeNoteNullifier = unconstrained fn(/* unique_note_hash */Field, /* packed_note */ BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/* randomness */ Field) -> Option;\n\n/// Deprecated: use [`ComputeNoteHash`] and [`ComputeNoteNullifier`] instead.\npub type ComputeNoteHashAndNullifier = unconstrained fn[Env](/* packed_note */BoundedVec,\n/* owner */ AztecAddress, /* storage_slot */ Field, /* note_type_id */ Field, /* contract_address */ AztecAddress,\n/*randomness */ Field, /* note nonce */ Field) -> Option;\n\n/// A handler for custom messages.\n///\n/// Contracts that emit custom messages (i.e. any with a message type that is not in [`crate::messages::msg_type`])\n/// need to use [`crate::macros::AztecConfig::custom_message_handler`] with a function of this type in order to\n/// process them. They will otherwise be **silently ignored**.\npub type CustomMessageHandler = unconstrained fn[Env](\n/* contract_address */AztecAddress,\n/* msg_type_id */ u64,\n/* msg_metadata */ u64,\n/* msg_content */ BoundedVec,\n/* message_context */ MessageContext,\n/* scope */ AztecAddress);\n\n/// Synchronizes the contract's private state with the network.\n///\n/// As blocks are mined, it is possible for a contract's private state to change (e.g. with new notes being created),\n/// but because these changes are private they will be invisible to most actors. This is the function that processes\n/// new transactions in order to discover new notes, events, and other kinds of private state changes.\n///\n/// The private state will be synchronized up to the block that will be used for private transactions (i.e. the anchor\n/// block. This will typically be close to the tip of the chain.\npub unconstrained fn do_sync_state(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n offchain_inbox_sync: Option>,\n scope: AztecAddress,\n) {\n aztecnr_debug_log!(\"Performing state synchronization\");\n\n // First we process all private logs, which can contain different kinds of messages e.g. private notes, partial\n // notes, private events, etc.\n let logs = message_processing::get_pending_tagged_logs(scope);\n logs.for_each(|_i, pending_tagged_log: PendingTaggedLog| {\n if pending_tagged_log.log.len() == 0 {\n aztecnr_warn_log_format!(\"Skipping empty log from tx {0}\")([pending_tagged_log.context.tx_hash]);\n } else {\n aztecnr_debug_log_format!(\"Processing log with tag {0}\")([pending_tagged_log.log.get(0)]);\n\n // We remove the tag from the pending tagged log and process the message ciphertext contained in it.\n let message_ciphertext = array::subbvec(pending_tagged_log.log, 1);\n\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_ciphertext,\n pending_tagged_log.context,\n scope,\n );\n }\n });\n\n if offchain_inbox_sync.is_some() {\n let msgs = offchain_inbox_sync.unwrap()(contract_address, scope);\n msgs.for_each(|_i, msg: OffchainMessageWithContext| {\n process_message_ciphertext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n msg.message_ciphertext,\n msg.message_context,\n scope,\n );\n });\n }\n\n // Then we process all pending partial notes, regardless of whether they were found in the current or previous\n // executions.\n partial_notes::fetch_and_process_partial_note_completion_logs(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n scope,\n );\n\n // Finally we validate all notes and events that were found as part of the previous processes, resulting in them\n // being added to PXE's database and retrievable via oracles (get_notes) and our TS API (PXE::getPrivateEvents).\n validate_and_store_enqueued_notes_and_events(scope);\n}\n\nmod test {\n use crate::ephemeral::EphemeralArray;\n use crate::messages::{\n discovery::{CustomMessageHandler, do_sync_state},\n logs::note::MAX_NOTE_PACKED_LEN,\n processing::{offchain::OffchainInboxSync, pending_tagged_log::PendingTaggedLog},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n\n #[test]\n unconstrained fn do_sync_state_does_not_panic_on_empty_logs() {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n\n let contract_address = AztecAddress { inner: 0xdeadbeef };\n\n env.utility_context_at(contract_address, |_| {\n // Mock the oracle call to return a known base slot, then populate an ephemeral\n // array at that slot so do_sync_state processes a non-empty log list.\n let base_slot = 42;\n let mock = std::test::OracleMock::mock(\"aztec_utl_getPendingTaggedLogs_v2\");\n let _ = mock.returns(base_slot);\n\n let logs: EphemeralArray = EphemeralArray::at(base_slot);\n logs.push(PendingTaggedLog { log: BoundedVec::new(), context: std::mem::zeroed() });\n assert_eq(logs.len(), 1);\n\n let no_handler: Option> = Option::none();\n let no_inbox_sync: Option> = Option::none();\n do_sync_state(\n contract_address,\n dummy_compute_note_hash,\n dummy_compute_note_nullifier,\n no_handler,\n no_inbox_sync,\n scope,\n );\n });\n }\n\n unconstrained fn dummy_compute_note_hash(\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n\n unconstrained fn dummy_compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec,\n _owner: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n Option::none()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr","function_locations":[{"start":6465,"name":"do_sync_state"},{"start":9175,"name":"test::do_sync_state_does_not_panic_on_empty_logs"},{"start":10673,"name":"test::dummy_compute_note_hash"},{"start":11034,"name":"test::dummy_compute_note_nullifier"}]},"127":{"source":"use crate::messages::{discovery::{ComputeNoteHash, ComputeNoteNullifier}, logs::note::MAX_NOTE_PACKED_LEN};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{\n address::AztecAddress,\n constants::MAX_NOTE_HASHES_PER_TX,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::ToField,\n};\n\n/// A struct with the discovered information of a complete note, required for delivery to PXE. Note that this is *not*\n/// the complete note information, since it does not include content, storage slot, etc.\npub(crate) struct DiscoveredNoteInfo {\n pub(crate) note_nonce: Field,\n pub(crate) note_hash: Field,\n pub(crate) inner_nullifier: Field,\n}\n\n/// Searches for note nonces that will result in a note that was emitted in a transaction. While rare, it is possible\n/// for multiple notes to have the exact same packed content and storage slot but different nonces, resulting in\n/// different unique note hashes. Because of this this function returns a *vector* of discovered notes, though in most\n/// cases it will contain a single element.\n///\n/// Due to how nonces are computed, this function requires knowledge of the transaction in which the note was created,\n/// more specifically the list of all unique note hashes in it plus the value of its first nullifier.\npub(crate) unconstrained fn attempt_note_nonce_discovery(\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) -> BoundedVec {\n let discovered_notes = &mut BoundedVec::new();\n\n aztecnr_debug_log_format!(\n \"Attempting nonce discovery on {0} potential notes on contract {1} for storage slot {2}\",\n )(\n [unique_note_hashes_in_tx.len() as Field, contract_address.to_field(), storage_slot],\n );\n\n let maybe_note_hash = compute_note_hash(\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_note_hash.is_none() {\n aztecnr_warn_log_format!(\n \"Unable to compute note hash for note of id {0} with packed length {1}, skipping nonce discovery\",\n )(\n [note_type_id, packed_note.len() as Field],\n );\n } else {\n let note_hash = maybe_note_hash.unwrap();\n let siloed_note_hash = compute_siloed_note_hash(contract_address, note_hash);\n\n // We need to find nonces (typically just one) that result in the siloed note hash that being uniqued into one\n // of the transaction's effects.\n // The nonce is meant to be derived from the index of the note hash in the transaction effects array. However,\n // due to an issue in the kernels the nonce might actually use any of the possible note hash indices - not\n // necessarily the one that corresponds to the note hash. Hence, we need to try them all.\n for i in 0..MAX_NOTE_HASHES_PER_TX {\n let nonce_for_i = compute_note_hash_nonce(first_nullifier_in_tx, i);\n let unique_note_hash_for_i = compute_unique_note_hash(nonce_for_i, siloed_note_hash);\n\n let matching_notes = bvec_filter(\n unique_note_hashes_in_tx,\n |unique_note_hash_in_tx| unique_note_hash_in_tx == unique_note_hash_for_i,\n );\n if matching_notes.len() > 1 {\n let identical_note_hashes = matching_notes.len();\n // Note that we don't actually check that the note hashes array contains unique values, only that the\n // note we found is unique. We don't expect for this to ever happen (it'd indicate a malicious node or\n // PXE, which are both assumed to be cooperative) so testing for it just in case is unnecessary, but we\n // _do_ need to handle it if we find a duplicate.\n panic(\n f\"Received {identical_note_hashes} identical note hashes for a transaction - these should all be unique\",\n )\n } else if matching_notes.len() == 1 {\n let maybe_inner_nullifier_for_i = compute_note_nullifier(\n unique_note_hash_for_i,\n packed_note,\n owner,\n storage_slot,\n note_type_id,\n contract_address,\n randomness,\n );\n\n if maybe_inner_nullifier_for_i.is_none() {\n // TODO: down the line we want to be able to store notes for which we don't know their nullifier,\n // e.g. notes that belong to someone that is not us (and for which we therefore don't know their\n // associated app-siloed nullifer hiding secret key).\n // https://linear.app/aztec-labs/issue/F-265/store-external-notes\n aztecnr_warn_log_format!(\n \"Unable to compute nullifier of unique note {0} with note type id {1} and owner {2}, skipping PXE insertion\",\n )(\n [unique_note_hash_for_i, note_type_id, owner.to_field()],\n );\n } else {\n // Note that while we did check that the note hash is the preimage of a unique note hash, we\n // perform no validations on the nullifier - we fundamentally cannot, since only the application\n // knows how to compute nullifiers. We simply trust it to have provided the correct one: if it\n // hasn't, then PXE may fail to realize that a given note has been nullified already, and calls to\n // the application could result in invalid transactions (with duplicate nullifiers). This is not a\n // concern because an application already has more direct means of making a call to it fail the\n // transaction.\n discovered_notes.push(\n DiscoveredNoteInfo {\n note_nonce: nonce_for_i,\n note_hash,\n inner_nullifier: maybe_inner_nullifier_for_i.unwrap(),\n },\n );\n }\n // We don't exit the loop - it is possible (though rare) for the exact same note content to be present\n // multiple times in the same transaction with different nonces. This typically doesn't happen due to\n // notes containing random values in order to hide their contents.\n }\n }\n }\n\n *discovered_notes\n}\n\n// There is no BoundedVec::filter in the stdlib, so we use this until that is implemented.\nunconstrained fn bvec_filter(\n bvec: BoundedVec,\n filter: fn[Env](T) -> bool,\n) -> BoundedVec {\n let filtered = &mut BoundedVec::new();\n\n bvec.for_each(|value| {\n if filter(value) {\n filtered.push(value);\n }\n });\n\n *filtered\n}\n\nmod test {\n use crate::{\n messages::logs::note::MAX_NOTE_PACKED_LEN,\n note::{\n note_interface::{NoteHash, NoteType},\n note_metadata::SettledNoteMetadata,\n utils::compute_note_hash_for_nullification,\n },\n oracle::random::random,\n test::mocks::mock_note::MockNote,\n utils::array,\n };\n\n use crate::protocol::{\n address::AztecAddress,\n hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash},\n traits::{FromField, Packable},\n };\n\n use super::attempt_note_nonce_discovery;\n\n // This implementation could be simpler, but this serves as a nice example of the expected flow in a real\n // implementation, and as a sanity check that the interface is sufficient.\n\n unconstrained fn compute_note_hash(\n packed_note: BoundedVec,\n owner: AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n Option::some(note.compute_note_hash(owner, storage_slot, randomness))\n } else {\n Option::none()\n }\n }\n\n unconstrained fn compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec,\n owner: AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: AztecAddress,\n _randomness: Field,\n ) -> Option {\n if (note_type_id == MockNote::get_id()) & (packed_note.len() == ::N) {\n let note = MockNote::unpack(array::subarray(packed_note.storage(), 0));\n note.compute_nullifier_unconstrained(owner, unique_note_hash)\n } else {\n Option::none()\n }\n }\n\n global VALUE: Field = 7;\n global FIRST_NULLIFIER_IN_TX: Field = 47;\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress::from_field(13);\n global OWNER: AztecAddress = AztecAddress::from_field(14);\n global STORAGE_SLOT: Field = 99;\n global RANDOMNESS: Field = 99;\n\n #[test]\n unconstrained fn no_note_hashes() {\n let unique_note_hashes_in_tx = BoundedVec::new();\n let packed_note = BoundedVec::new();\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n packed_note,\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_hash_computation_is_ignored() {\n let unique_note_hashes_in_tx = BoundedVec::from_array([random()]);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n |_, _, _, _, _, _| Option::none(),\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::new(),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n #[test]\n unconstrained fn failed_nullifier_computation_is_ignored() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n |_, _, _, _, _, _, _| Option::none(),\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 0);\n }\n\n struct NoteAndData {\n note: MockNote,\n note_nonce: Field,\n note_hash: Field,\n unique_note_hash: Field,\n inner_nullifier: Field,\n }\n\n unconstrained fn construct_note(value: Field, note_index_in_tx: u32) -> NoteAndData {\n let note_nonce = compute_note_hash_nonce(FIRST_NULLIFIER_IN_TX, note_index_in_tx);\n\n let hinted_note = MockNote::new(value)\n .contract_address(CONTRACT_ADDRESS)\n .owner(OWNER)\n .randomness(RANDOMNESS)\n .storage_slot(STORAGE_SLOT)\n .note_metadata(SettledNoteMetadata::new(note_nonce).into())\n .build_hinted_note();\n let note = hinted_note.note;\n\n let note_hash = note.compute_note_hash(OWNER, STORAGE_SLOT, RANDOMNESS);\n let unique_note_hash = compute_unique_note_hash(\n note_nonce,\n compute_siloed_note_hash(CONTRACT_ADDRESS, note_hash),\n );\n let inner_nullifier = note\n .compute_nullifier_unconstrained(OWNER, compute_note_hash_for_nullification(hinted_note))\n .expect(f\"Could not compute nullifier for note owned by {OWNER}\");\n\n NoteAndData { note, note_nonce, note_hash, unique_note_hash, inner_nullifier }\n }\n\n #[test]\n unconstrained fn single_note() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn multiple_notes_same_preimage() {\n let first_note_index_in_tx = 3;\n let first_note_and_data = construct_note(VALUE, first_note_index_in_tx);\n\n let second_note_index_in_tx = 5;\n let second_note_and_data = construct_note(VALUE, second_note_index_in_tx);\n\n // Both notes have the same preimage (and therefore packed representation), so both should be found in the same\n // call.\n assert_eq(first_note_and_data.note, second_note_and_data.note);\n let packed_note = first_note_and_data.note.pack();\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n unique_note_hashes_in_tx.set(first_note_index_in_tx, first_note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(second_note_index_in_tx, second_note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(packed_note),\n );\n\n assert_eq(discovered_notes.len(), 2);\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == first_note_and_data.note_nonce)\n & (discovered_note.note_hash == first_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == first_note_and_data.inner_nullifier)\n }));\n\n assert(discovered_notes.any(|discovered_note| {\n (discovered_note.note_nonce == second_note_and_data.note_nonce)\n & (discovered_note.note_hash == second_note_and_data.note_hash)\n & (discovered_note.inner_nullifier == second_note_and_data.inner_nullifier)\n }));\n }\n\n #[test]\n unconstrained fn single_note_misaligned_nonce() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The note is not at the correct index\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test]\n unconstrained fn single_note_nonce_with_index_past_note_hashes_in_tx() {\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The nonce is computed with an index that does not exist in the tx\n let note_index_in_tx = unique_note_hashes_in_tx.len() + 5;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n // The note is inserted at an arbitrary index - its true index is out of the array's bounds\n unique_note_hashes_in_tx.set(2, note_and_data.unique_note_hash);\n\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n\n assert_eq(discovered_notes.len(), 1);\n let discovered_note = discovered_notes.get(0);\n\n assert_eq(discovered_note.note_nonce, note_and_data.note_nonce);\n assert_eq(discovered_note.note_hash, note_and_data.note_hash);\n assert_eq(discovered_note.inner_nullifier, note_and_data.inner_nullifier);\n }\n\n #[test(should_fail_with = \"identical note hashes for a transaction\")]\n unconstrained fn duplicate_unique_note_hashes() {\n let note_index_in_tx = 2;\n let note_and_data = construct_note(VALUE, note_index_in_tx);\n\n let mut unique_note_hashes_in_tx = BoundedVec::from_array([\n random(), random(), random(), random(), random(), random(), random(),\n ]);\n\n // The same unique note hash is present in two indices in the array, which is not allowed. Note that we don't\n // test all note hashes for uniqueness, only those that we actually find.\n unique_note_hashes_in_tx.set(note_index_in_tx, note_and_data.unique_note_hash);\n unique_note_hashes_in_tx.set(note_index_in_tx + 1, note_and_data.unique_note_hash);\n\n let _ = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n FIRST_NULLIFIER_IN_TX,\n compute_note_hash,\n compute_note_nullifier,\n CONTRACT_ADDRESS,\n OWNER,\n STORAGE_SLOT,\n RANDOMNESS,\n MockNote::get_id(),\n BoundedVec::from_array(note_and_data.note.pack()),\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/nonce_discovery.nr","function_locations":[{"start":1866,"name":"attempt_note_nonce_discovery"},{"start":7210,"name":"bvec_filter"},{"start":8458,"name":"test::compute_note_hash"},{"start":9107,"name":"test::compute_note_nullifier"},{"start":9764,"name":"test::no_note_hashes"},{"start":10362,"name":"test::failed_hash_computation_is_ignored"},{"start":10959,"name":"test::failed_nullifier_computation_is_ignored"},{"start":12052,"name":"test::construct_note"},{"start":13085,"name":"test::single_note"},{"start":14249,"name":"test::multiple_notes_same_preimage"},{"start":16275,"name":"test::single_note_misaligned_nonce"},{"start":17515,"name":"test::single_note_nonce_with_index_past_note_hashes_in_tx"},{"start":18937,"name":"test::duplicate_unique_note_hashes"}]},"128":{"source":"use crate::{\n capsules::CapsuleArray,\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::partial_note::{decode_partial_note_private_message, MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN},\n processing::{\n enqueue_note_for_validation,\n get_pending_partial_notes_completion_logs,\n log_retrieval_response::{LogRetrievalResponse, MAX_LOG_CONTENT_LEN},\n },\n },\n utils::array,\n};\n\nuse crate::logging::{aztecnr_debug_log_format, aztecnr_warn_log_format};\nuse crate::protocol::{address::AztecAddress, hash::sha256_to_field, traits::{Deserialize, Serialize}};\n\n/// The slot in the PXE capsules where we store a `CapsuleArray` of `DeliveredPendingPartialNote`.\npub(crate) global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT\".as_bytes(),\n);\n\n/// A partial note that was delivered but is still pending completion. Contains the information necessary to find the\n/// log that will complete it and lead to a note being discovered and delivered.\n#[derive(Serialize, Deserialize)]\npub(crate) struct DeliveredPendingPartialNote {\n pub(crate) owner: AztecAddress,\n pub(crate) randomness: Field,\n pub(crate) note_completion_log_tag: Field,\n pub(crate) note_type_id: Field,\n pub(crate) packed_private_note_content: BoundedVec,\n}\n\npub(crate) unconstrained fn process_partial_note_private_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n scope: AztecAddress,\n) {\n let decoded = decode_partial_note_private_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n // We store the information of the partial note we found in a persistent capsule in PXE, so that we can later\n // search for the public log that will complete it.\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content) = decoded.unwrap();\n\n let pending = DeliveredPendingPartialNote {\n owner,\n randomness,\n note_completion_log_tag,\n note_type_id,\n packed_private_note_content,\n };\n\n CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n )\n .push(pending);\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode partial note private message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Searches for logs that would result in the completion of pending partial notes, ultimately resulting in the notes\n/// being delivered to PXE if completed.\npub(crate) unconstrained fn fetch_and_process_partial_note_completion_logs(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n scope: AztecAddress,\n) {\n let pending_partial_notes = CapsuleArray::at(\n contract_address,\n DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT,\n scope,\n );\n\n aztecnr_debug_log_format!(\"{} pending partial notes\")([pending_partial_notes.len() as Field]);\n\n // Each of the pending partial notes might get completed by a log containing its public values. For performance\n // reasons, we fetch all of these logs concurrently and then process them one by one, minimizing the amount of time\n // waiting for the node roundtrip.\n let maybe_completion_logs = get_pending_partial_notes_completion_logs(contract_address, pending_partial_notes);\n\n // Each entry in the maybe completion logs array corresponds to the entry in the pending partial notes array at the\n // same index. This means we can use the same index as we iterate through the responses to get both the partial\n // note and the log that might complete it.\n assert_eq(maybe_completion_logs.len(), pending_partial_notes.len());\n\n maybe_completion_logs.for_each(|i, maybe_log: Option| {\n let pending_partial_note = pending_partial_notes.get(i);\n\n if maybe_log.is_none() {\n aztecnr_debug_log_format!(\"Found no completion logs for partial note with tag {}\")(\n [pending_partial_note.note_completion_log_tag],\n );\n\n // Note that we're not removing the pending partial note from the capsule array, so we will continue\n // searching for this tagged log when performing message discovery in the future until we either find it or\n // the entry is somehow removed from the array.\n } else {\n aztecnr_debug_log_format!(\"Completion log found for partial note with tag {}\")([\n pending_partial_note.note_completion_log_tag,\n ]);\n let log = maybe_log.unwrap();\n\n // The first field in the completion log payload is the storage slot, followed by the public note\n // content fields.\n let storage_slot = log.log_payload.get(0);\n let public_note_content: BoundedVec = array::subbvec(log.log_payload, 1);\n\n // Public fields are assumed to all be placed at the end of the packed representation, so we combine\n // the private and public packed fields (i.e. the contents of the private message and public log\n // plaintext) to get the complete packed content.\n let complete_packed_note = array::append(\n pending_partial_note.packed_private_note_content,\n public_note_content,\n );\n\n let discovered_notes = attempt_note_nonce_discovery(\n log.unique_note_hashes_in_tx,\n log.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n pending_partial_note.note_type_id,\n complete_packed_note,\n );\n\n // TODO(#11627): is there anything reasonable we can do if we get a log but it doesn't result in a note\n // being found?\n if discovered_notes.len() == 0 {\n panic(\n f\"A partial note's completion log did not result in any notes being found - this should never happen\",\n );\n }\n\n aztecnr_debug_log_format!(\"Discovered {0} notes for partial note with tag {1}\")([\n discovered_notes.len() as Field,\n pending_partial_note.note_completion_log_tag,\n ]);\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n pending_partial_note.owner,\n storage_slot,\n pending_partial_note.randomness,\n discovered_note.note_nonce,\n complete_packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n log.tx_hash,\n );\n });\n\n // Because there is only a single log for a given tag, once we've processed the tagged log then we simply\n // delete the pending work entry, regardless of whether it was actually completed or not.\n pending_partial_notes.remove(i);\n }\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr","function_locations":[{"start":1784,"name":"process_partial_note_private_msg"},{"start":3162,"name":"fetch_and_process_partial_note_completion_logs"}]},"129":{"source":"use crate::{\n event::event_interface::compute_private_serialized_event_commitment,\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::MAX_MESSAGE_CONTENT_LEN, logs::event::decode_private_event_message,\n processing::enqueue_event_for_validation,\n },\n};\nuse crate::protocol::{address::AztecAddress, traits::ToField};\n\npub(crate) unconstrained fn process_private_event_msg(\n contract_address: AztecAddress,\n msg_metadata: u64,\n msg_content: BoundedVec,\n tx_hash: Field,\n) {\n let decoded = decode_private_event_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (event_type_id, randomness, serialized_event) = decoded.unwrap();\n\n let event_commitment =\n compute_private_serialized_event_commitment(serialized_event, randomness, event_type_id.to_field());\n\n enqueue_event_for_validation(\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private event message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_events.nr","function_locations":[{"start":547,"name":"process_private_event_msg"}]},"130":{"source":"use crate::{\n logging::{aztecnr_debug_log_format, aztecnr_warn_log_format},\n messages::{\n discovery::{ComputeNoteHash, ComputeNoteNullifier, nonce_discovery::attempt_note_nonce_discovery},\n encoding::MAX_MESSAGE_CONTENT_LEN,\n logs::note::{decode_private_note_message, MAX_NOTE_PACKED_LEN},\n processing::enqueue_note_for_validation,\n },\n protocol::{address::AztecAddress, constants::MAX_NOTE_HASHES_PER_TX, traits::ToField},\n};\n\npub(crate) unconstrained fn process_private_note_msg(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n msg_metadata: u64,\n msg_content: BoundedVec,\n) {\n let decoded = decode_private_note_message(msg_metadata, msg_content);\n\n if decoded.is_some() {\n let (note_type_id, owner, storage_slot, randomness, packed_note) = decoded.unwrap();\n\n attempt_note_discovery(\n contract_address,\n tx_hash,\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n } else {\n aztecnr_warn_log_format!(\n \"Could not decode private note message from tx {0}, ignoring\",\n )(\n [tx_hash],\n );\n }\n}\n\n/// Attempts discovery of a note given information about its contents and the transaction in which it is suspected the\n/// note was created.\npub unconstrained fn attempt_note_discovery(\n contract_address: AztecAddress,\n tx_hash: Field,\n unique_note_hashes_in_tx: BoundedVec,\n first_nullifier_in_tx: Field,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_type_id: Field,\n packed_note: BoundedVec,\n) {\n let discovered_notes = attempt_note_nonce_discovery(\n unique_note_hashes_in_tx,\n first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_type_id,\n packed_note,\n );\n\n if discovered_notes.len() == 0 {\n // A private note message that results in no discovered notes means none of the computed note hashes matched\n // any unique note hash in the transaction. This could indicate a malformed or malicious message (e.g. a sender\n // providing bogus note content).\n aztecnr_warn_log_format!(\n \"Discarding private note message from tx {0} for contract {1}: no matching note hash found in the tx\",\n )(\n [tx_hash, contract_address.to_field()],\n );\n } else {\n aztecnr_debug_log_format!(\n \"Discovered {0} notes from a private message for contract {1}\",\n )(\n [discovered_notes.len() as Field, contract_address.to_field()],\n );\n }\n\n discovered_notes.for_each(|discovered_note| {\n enqueue_note_for_validation(\n contract_address,\n owner,\n storage_slot,\n randomness,\n discovered_note.note_nonce,\n packed_note,\n discovered_note.note_hash,\n discovered_note.inner_nullifier,\n tx_hash,\n );\n });\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/private_notes.nr","function_locations":[{"start":861,"name":"process_private_note_msg"},{"start":2185,"name":"attempt_note_discovery"}]},"131":{"source":"use crate::messages::{\n discovery::{\n ComputeNoteHash, ComputeNoteNullifier, CustomMessageHandler, partial_notes::process_partial_note_private_msg,\n private_events::process_private_event_msg, private_notes::process_private_note_msg,\n },\n encoding::{decode_message, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN},\n encryption::{aes128::AES128, message_encryption::MessageEncryption},\n msg_type::{\n MIN_CUSTOM_MSG_TYPE_ID, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID, PRIVATE_EVENT_MSG_TYPE_ID, PRIVATE_NOTE_MSG_TYPE_ID,\n },\n processing::MessageContext,\n};\n\nuse crate::logging::{aztecnr_debug_log, aztecnr_warn_log_format};\nuse crate::protocol::address::AztecAddress;\n\n/// Processes a message that can contain notes, partial notes, or events.\n///\n/// Notes result in nonce discovery being performed prior to delivery, which requires knowledge of the transaction hash\n/// in which the notes would've been created (typically the same transaction in which the log was emitted), along with\n/// the list of unique note hashes in said transaction and the `compute_note_hash` and `compute_note_nullifier`\n/// functions. Once discovered, the notes are enqueued for validation.\n///\n/// Partial notes result in a pending partial note entry being stored in a PXE capsule, which will later be retrieved\n/// to search for the note's completion public log.\n///\n/// Events are processed by computing an event commitment from the serialized event data and its randomness field, then\n/// enqueueing the event data and commitment for validation.\npub unconstrained fn process_message_ciphertext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_ciphertext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n let message_plaintext_option = AES128::decrypt(message_ciphertext, recipient, contract_address);\n\n if message_plaintext_option.is_some() {\n process_message_plaintext(\n contract_address,\n compute_note_hash,\n compute_note_nullifier,\n process_custom_message,\n message_plaintext_option.unwrap(),\n message_context,\n recipient,\n );\n } else {\n aztecnr_warn_log_format!(\"Could not decrypt message ciphertext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n\npub(crate) unconstrained fn process_message_plaintext(\n contract_address: AztecAddress,\n compute_note_hash: ComputeNoteHash,\n compute_note_nullifier: ComputeNoteNullifier,\n process_custom_message: Option>,\n message_plaintext: BoundedVec,\n message_context: MessageContext,\n recipient: AztecAddress,\n) {\n // The first thing to do after decrypting the message is to determine what type of message we're processing. We\n // have 3 message types: private notes, partial notes and events.\n\n // We decode the message to obtain the message type id, metadata and content.\n let decoded = decode_message(message_plaintext);\n\n if decoded.is_some() {\n let (msg_type_id, msg_metadata, msg_content) = decoded.unwrap();\n\n if msg_type_id == PRIVATE_NOTE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private note msg\");\n\n process_private_note_msg(\n contract_address,\n message_context.tx_hash,\n message_context.unique_note_hashes_in_tx,\n message_context.first_nullifier_in_tx,\n compute_note_hash,\n compute_note_nullifier,\n msg_metadata,\n msg_content,\n );\n } else if msg_type_id == PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing partial note private msg\");\n\n process_partial_note_private_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n recipient,\n );\n } else if msg_type_id == PRIVATE_EVENT_MSG_TYPE_ID {\n aztecnr_debug_log!(\"Processing private event msg\");\n\n process_private_event_msg(\n contract_address,\n msg_metadata,\n msg_content,\n message_context.tx_hash,\n );\n } else if msg_type_id < MIN_CUSTOM_MSG_TYPE_ID {\n // The message type ID falls in the range reserved for aztec.nr built-in types but wasn't matched above.\n // This most likely means the message is malformed or a custom message was incorrectly assigned a reserved\n // ID. Custom message types must use IDs allocated via `custom_msg_type_id`.\n aztecnr_warn_log_format!(\n \"Message type ID {0} is in the reserved range but is not recognized, ignoring. See https://docs.aztec.network/errors/3\",\n )(\n [msg_type_id as Field],\n );\n } else if process_custom_message.is_some() {\n process_custom_message.unwrap()(\n contract_address,\n msg_type_id,\n msg_metadata,\n msg_content,\n message_context,\n recipient,\n );\n } else {\n // A custom message was received but no handler is configured. This likely means the contract emits custom\n // messages but forgot to register a handler via `AztecConfig::custom_message_handler`.\n aztecnr_warn_log_format!(\n \"Received custom message with type id {0} but no handler is configured, ignoring. See https://docs.aztec.network/errors/2\",\n )(\n [msg_type_id as Field],\n );\n }\n } else {\n aztecnr_warn_log_format!(\"Could not decode message plaintext from tx {0}, ignoring\")([message_context.tx_hash]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/discovery/process_message.nr","function_locations":[{"start":1975,"name":"process_message_ciphertext"},{"start":2968,"name":"process_message_plaintext"}]},"132":{"source":"// TODO(#12750): don't make these values assume we're using AES.\nuse crate::protocol::constants::PRIVATE_LOG_CIPHERTEXT_LEN;\nuse crate::utils::array;\n\n// We reassign to the constant here to communicate the distinction between a log and a message. In Aztec.nr, unlike in\n// protocol circuits, we have a concept of a message that can be emitted either as a private log or as an offchain\n// message. Message is a piece of data that is to be eventually delivered to a contract via the `process_message(...)`\n// utility function function that is injected by the #[aztec] macro. Note: PRIVATE_LOG_CIPHERTEXT_LEN is an amount of\n// fields, so MESSAGE_CIPHERTEXT_LEN is the size of the message in fields.\npub global MESSAGE_CIPHERTEXT_LEN: u32 = PRIVATE_LOG_CIPHERTEXT_LEN;\n\n// TODO(#12750): The global variables below should not be here as they are AES128 specific.\n// The header plaintext is 2 bytes (ciphertext length), padded to the 16-byte AES block size by PKCS#7.\npub(crate) global HEADER_CIPHERTEXT_SIZE_IN_BYTES: u32 = 16;\n// AES PKCS#7 always adds at least one byte of padding. Since each plaintext field is 32 bytes (a multiple of the\n// 16-byte AES block size), a full 16-byte padding block is always appended.\npub(crate) global AES128_PKCS7_EXPANSION_IN_BYTES: u32 = 16;\n\npub global EPH_PK_X_SIZE_IN_FIELDS: u32 = 1;\n\n// (15 - 1) * 31 - 16 - 16 = 402. Note: We multiply by 31 because ciphertext bytes are stored in fields using\n// encode_bytes_as_fields, which packs 31 bytes per field (since a Field is ~254 bits and can safely store 31 whole\n// bytes).\npub(crate) global MESSAGE_PLAINTEXT_SIZE_IN_BYTES: u32 = (MESSAGE_CIPHERTEXT_LEN - EPH_PK_X_SIZE_IN_FIELDS) * 31\n - HEADER_CIPHERTEXT_SIZE_IN_BYTES\n - AES128_PKCS7_EXPANSION_IN_BYTES;\n// The plaintext bytes represent Field values that were originally serialized using encode_fields_as_bytes, which\n// converts each Field to 32 bytes. To convert the plaintext bytes back to fields, we divide by 32. 402 / 32 = 12\npub global MESSAGE_PLAINTEXT_LEN: u32 = MESSAGE_PLAINTEXT_SIZE_IN_BYTES / 32;\n\npub global MESSAGE_EXPANDED_METADATA_LEN: u32 = 1;\n\n// The standard message layout is composed of:\n// - an initial field called the 'expanded metadata'\n// - an arbitrary number of fields following that called the 'message content'\n//\n// ```\n// message: [ msg_expanded_metadata, ...msg_content ]\n// ```\n//\n// The expanded metadata itself is interpreted as a u128, of which:\n// - the upper 64 bits are the message type id\n// - the lower 64 bits are called the 'message metadata'\n//\n// ```\n// msg_expanded_metadata: [ msg_type_id | msg_metadata ]\n// <--- 64 bits --->|<--- 64 bits --->\n// ```\n//\n// The meaning of the message metadata and message content depend on the value of the message type id. Note that there\n// is nothing special about the message metadata, it _can_ be considered part of the content. It just has a different\n// name to make it distinct from the message content given that it is not a full field.\n\n/// The maximum length of a message's content, i.e. not including the expanded message metadata.\npub global MAX_MESSAGE_CONTENT_LEN: u32 = MESSAGE_PLAINTEXT_LEN - MESSAGE_EXPANDED_METADATA_LEN;\n\n/// Encodes a message following aztec-nr's standard message encoding. This message can later be decoded with\n/// `decode_message` to retrieve the original values.\n///\n/// - The `msg_type` is an identifier that groups types of messages that are all processed the same way, e.g. private\n/// notes or events. Possible values are defined in `aztec::messages::msg_type`.\n/// - The `msg_metadata` and `msg_content` are the values stored in the message, whose meaning depends on the\n/// `msg_type`. The only special thing about `msg_metadata` that separates it from `msg_content` is that it is a u64\n/// instead of a full Field (due to details of how messages are encoded), allowing applications that can fit values\n/// into this smaller variable to achieve higher data efficiency.\npub fn encode_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; N],\n) -> [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] {\n std::static_assert(\n msg_content.len() <= MAX_MESSAGE_CONTENT_LEN,\n \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\",\n );\n\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n let mut message: [Field; (N + MESSAGE_EXPANDED_METADATA_LEN)] = std::mem::zeroed();\n\n message[0] = to_expanded_metadata(msg_type, msg_metadata);\n for i in 0..msg_content.len() {\n message[MESSAGE_EXPANDED_METADATA_LEN + i] = msg_content[i];\n }\n\n message\n}\n\n/// Decodes a standard aztec-nr message, i.e. one created via `encode_message`, returning the original encoded values.\n///\n/// Returns `None` if the message is empty or has invalid (>128 bit) expanded metadata.\n///\n/// Note that `encode_message` returns a fixed size array while this function takes a `BoundedVec`: this is because\n/// prior to decoding the message type is unknown, and consequentially not known at compile time. If working with\n/// fixed-size messages, consider using `BoundedVec::from_array` to convert them.\npub unconstrained fn decode_message(\n message: BoundedVec,\n) -> Option<(u64, u64, BoundedVec)> {\n Option::some(message)\n .and_then(|message| {\n // If MESSAGE_EXPANDED_METADATA_LEN is changed, causing the assertion below to fail, then the destructuring\n // of the\n // message encoding below must be updated as well.\n std::static_assert(\n MESSAGE_EXPANDED_METADATA_LEN == 1,\n \"unexpected value for MESSAGE_EXPANDED_METADATA_LEN\",\n );\n if message.len() < MESSAGE_EXPANDED_METADATA_LEN {\n Option::none()\n } else {\n Option::some(message.get(0))\n }\n })\n .and_then(|msg_expanded_metadata| from_expanded_metadata(msg_expanded_metadata))\n .map(|(msg_type_id, msg_metadata)| {\n let msg_content = array::subbvec(message, MESSAGE_EXPANDED_METADATA_LEN);\n (msg_type_id, msg_metadata, msg_content)\n })\n}\n\nglobal U64_SHIFT_MULTIPLIER: Field = 2.pow_32(64);\n\nfn to_expanded_metadata(msg_type: u64, msg_metadata: u64) -> Field {\n // We use multiplication instead of bit shifting operations to shift the type bits as bit shift operations are\n // expensive in circuits.\n let type_field: Field = (msg_type as Field) * U64_SHIFT_MULTIPLIER;\n let msg_metadata_field = msg_metadata as Field;\n\n type_field + msg_metadata_field\n}\n\nglobal TWO_POW_128: Field = 2.pow_32(128);\n\n/// Unpacks expanded metadata into (msg_type, msg_metadata). Returns `None` if `input >= 2^128`.\nfn from_expanded_metadata(input: Field) -> Option<(u64, u64)> {\n if input.lt(TWO_POW_128) {\n let msg_metadata = (input as u64);\n let msg_type = ((input - (msg_metadata as Field)) / U64_SHIFT_MULTIPLIER) as u64;\n // Use division instead of bit shift since bit shifts are expensive in circuits\n Option::some((msg_type, msg_metadata))\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray::subarray;\n use super::{\n decode_message, encode_message, from_expanded_metadata, MAX_MESSAGE_CONTENT_LEN, to_expanded_metadata,\n TWO_POW_128,\n };\n\n global U64_MAX: u64 = (2.pow_32(64) - 1) as u64;\n global U128_MAX: Field = (2.pow_32(128) - 1);\n\n #[test]\n unconstrained fn encode_decode_empty_message(msg_type: u64, msg_metadata: u64) {\n let encoded = encode_message(msg_type, msg_metadata, []);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), 0);\n }\n\n #[test]\n unconstrained fn encode_decode_short_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN / 2],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn encode_decode_full_message(\n msg_type: u64,\n msg_metadata: u64,\n msg_content: [Field; MAX_MESSAGE_CONTENT_LEN],\n ) {\n let encoded = encode_message(msg_type, msg_metadata, msg_content);\n let (decoded_msg_type, decoded_msg_metadata, decoded_msg_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_msg_type, msg_type);\n assert_eq(decoded_msg_metadata, msg_metadata);\n assert_eq(decoded_msg_content.len(), msg_content.len());\n assert_eq(subarray(decoded_msg_content.storage(), 0), msg_content);\n }\n\n #[test]\n unconstrained fn to_expanded_metadata_packing() {\n // Test case 1: All bits set\n let packed = to_expanded_metadata(U64_MAX, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let packed = to_expanded_metadata(U64_MAX, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let packed = to_expanded_metadata(0, U64_MAX);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let packed = to_expanded_metadata(0, 0);\n let (msg_type, msg_metadata) = from_expanded_metadata(packed).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn from_expanded_metadata_packing() {\n // Test case 1: All bits set\n let input = U128_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 2: Only log type bits set\n let input = (U128_MAX - U64_MAX as Field);\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, U64_MAX);\n assert_eq(msg_metadata, 0);\n\n // Test case 3: Only msg_metadata bits set\n let input = U64_MAX as Field;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, U64_MAX);\n\n // Test case 4: No bits set\n let input = 0;\n let (msg_type, msg_metadata) = from_expanded_metadata(input).unwrap();\n assert_eq(msg_type, 0);\n assert_eq(msg_metadata, 0);\n }\n\n #[test]\n unconstrained fn to_from_expanded_metadata(original_msg_type: u64, original_msg_metadata: u64) {\n let packed = to_expanded_metadata(original_msg_type, original_msg_metadata);\n let (unpacked_msg_type, unpacked_msg_metadata) = from_expanded_metadata(packed).unwrap();\n\n assert_eq(original_msg_type, unpacked_msg_type);\n assert_eq(original_msg_metadata, unpacked_msg_metadata);\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_message() {\n let msg_type_id: u64 = 42;\n let msg_metadata: u64 = 99;\n let mut msg_content = [0; MAX_MESSAGE_CONTENT_LEN];\n for i in 0..MAX_MESSAGE_CONTENT_LEN {\n msg_content[i] = i as Field;\n }\n\n let encoded = encode_message(msg_type_id, msg_metadata, msg_content);\n let (decoded_type_id, decoded_metadata, decoded_content) =\n decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(decoded_type_id, msg_type_id);\n assert_eq(decoded_metadata, msg_metadata);\n assert_eq(decoded_content, BoundedVec::from_array(msg_content));\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_message_fails() {\n let msg_content = [0; MAX_MESSAGE_CONTENT_LEN + 1];\n let _ = encode_message(0, 0, msg_content);\n }\n\n #[test]\n unconstrained fn decode_empty_message_returns_none() {\n assert(decode_message(BoundedVec::new()).is_none());\n }\n\n #[test]\n unconstrained fn decode_message_with_oversized_metadata_returns_none() {\n let message = BoundedVec::from_array([TWO_POW_128]);\n assert(decode_message(message).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encoding.nr","function_locations":[{"start":4136,"name":"encode_message"},{"start":5594,"name":"decode_message"},{"start":6617,"name":"to_expanded_metadata"},{"start":7131,"name":"from_expanded_metadata"},{"start":7894,"name":"tests::encode_decode_empty_message"},{"start":8444,"name":"tests::encode_decode_short_message"},{"start":9090,"name":"tests::encode_decode_full_message"},{"start":9628,"name":"tests::to_expanded_metadata_packing"},{"start":10713,"name":"tests::from_expanded_metadata_packing"},{"start":11770,"name":"tests::to_from_expanded_metadata"},{"start":12151,"name":"tests::encode_decode_max_size_message"},{"start":12934,"name":"tests::encode_oversized_message_fails"},{"start":13123,"name":"tests::decode_empty_message_returns_none"},{"start":13280,"name":"tests::decode_message_with_oversized_metadata_returns_none"}]},"133":{"source":"use crate::protocol::{address::AztecAddress, public_keys::AddressPoint, traits::ToField};\n\nuse crate::{\n keys::{\n ecdh_shared_secret::{\n compute_app_siloed_shared_secret, derive_ecdh_shared_secret, derive_shared_secret_field_mask,\n derive_shared_secret_subkey,\n },\n ephemeral::generate_positive_ephemeral_key_pair,\n },\n logging::aztecnr_warn_log_format,\n messages::{\n encoding::{\n EPH_PK_X_SIZE_IN_FIELDS, HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_CIPHERTEXT_LEN, MESSAGE_PLAINTEXT_LEN,\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES,\n },\n encryption::message_encryption::MessageEncryption,\n logs::arithmetic_generics_utils::{\n get_arr_of_size__message_bytes__from_PT, get_arr_of_size__message_bytes_padding__from_PT,\n },\n },\n oracle::{aes128_decrypt::try_aes128_decrypt, random::random, shared_secret::get_shared_secret},\n utils::{\n array,\n conversion::{\n bytes_as_fields::{decode_bytes_from_fields, encode_bytes_as_fields},\n fields_as_bytes::{encode_fields_as_bytes, try_decode_fields_from_bytes},\n },\n point::point_from_x_coord_and_sign,\n },\n};\n\nuse std::aes128::aes128_encrypt;\n\n/// Computes N close-to-uniformly-random 256 bits from a given app-siloed shared secret.\n///\n/// NEVER re-use the same iv and sym_key. DO NOT call this function more than once with the same s_app.\n///\n/// This function is only known to be safe if s_app is derived from combining a random ephemeral key with an\n/// address point and a contract address. See big comment within the body of the function.\nfn extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app: Field) -> [[u8; 32]; N] {\n /*\n * Unsafe because of https://eprint.iacr.org/2010/264.pdf Page 13, Lemma 2 (and the two paragraphs below it).\n *\n * If you call this function, you need to be careful and aware of how the arg `s_app` has been derived.\n *\n * The paper says that the way you derive aes keys and IVs should be fine with poseidon2 (modelled as a RO),\n * as long as you _don't_ use Poseidon2 as a PRG to generate the two exponents x & y which multiply to the\n * shared secret S:\n *\n * S = [x*y]*G.\n *\n * (Otherwise, you would have to \"key\" poseidon2, i.e. generate a uniformly string K which can be public and\n * compute Hash(x) as poseidon(K,x)).\n * In that lemma, k would be 2*254=508, and m would be the number of points on the grumpkin curve (which is\n * close to r according to the Hasse bound).\n *\n * Our shared secret S is [esk * address_sk] * G, and the question is: Can we compute hash(S) using poseidon2\n * instead of sha256?\n *\n * Well, esk is random and not generated with poseidon2, so that's good.\n * What about address_sk?\n * Well, address_sk = poseidon2(stuff) + ivsk, so there was some discussion about whether address_sk is\n * independent of poseidon2. Given that ivsk is random and independent of poseidon2, the address_sk is also\n * independent of poseidon2.\n *\n * Tl;dr: we believe it's safe to hash S = [esk * address_sk] * G using poseidon2, in order to derive a\n * symmetric key.\n *\n * If you're calling this function for a differently-derived `s_app`, be careful.\n */\n \n\n /* The output of this function needs to be 32 random bytes.\n * A single field won't give us 32 bytes of entropy. So we compute two \"random\" fields, by poseidon-hashing\n * with two different indices. We then extract the last 16 (big endian) bytes of each \"random\" field.\n * Note: we use to_be_bytes because it's slightly more efficient. But we have to be careful not to take bytes\n * from the \"big end\", because the \"big\" byte is not uniformly random over the byte: it only has < 6 bits of\n * randomness, because it's the big end of a 254-bit field element.\n */\n\n let mut all_bytes: [[u8; 32]; N] = std::mem::zeroed();\n std::static_assert(N < 256, \"N too large\");\n for k in 0..N {\n let rand1: Field = derive_shared_secret_subkey(s_app, 2 * k);\n let rand2: Field = derive_shared_secret_subkey(s_app, 2 * k + 1);\n\n let rand1_bytes: [u8; 32] = rand1.to_be_bytes();\n let rand2_bytes: [u8; 32] = rand2.to_be_bytes();\n\n let mut bytes: [u8; 32] = [0; 32];\n for i in 0..16 {\n // We take bytes from the \"little end\" of the be-bytes arrays:\n let j = 32 - i - 1;\n bytes[i] = rand1_bytes[j];\n bytes[16 + i] = rand2_bytes[j];\n }\n\n all_bytes[k] = bytes;\n }\n\n all_bytes\n}\n\nfn derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(\n many_random_256_bits: [[u8; 32]; N],\n) -> [([u8; 16], [u8; 16]); N] {\n // Many (sym_key, iv) pairs:\n let mut many_pairs: [([u8; 16], [u8; 16]); N] = std::mem::zeroed();\n for k in 0..N {\n let random_256_bits = many_random_256_bits[k];\n let mut sym_key = [0; 16];\n let mut iv = [0; 16];\n for i in 0..16 {\n sym_key[i] = random_256_bits[i];\n iv[i] = random_256_bits[i + 16];\n }\n many_pairs[k] = (sym_key, iv);\n }\n\n many_pairs\n}\n\npub fn derive_aes_symmetric_key_and_iv_from_shared_secret(s_app: Field) -> [([u8; 16], [u8; 16]); N] {\n let many_random_256_bits: [[u8; 32]; N] = extract_many_close_to_uniformly_random_256_bits_using_poseidon2(s_app);\n\n derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits(many_random_256_bits)\n}\n\npub struct AES128 {}\n\nimpl MessageEncryption for AES128 {\n\n /// AES128-CBC encryption for Aztec protocol messages.\n ///\n /// ## Overview\n ///\n /// The plaintext is an array of up to `MESSAGE_PLAINTEXT_LEN` (12) fields. The output is always exactly\n /// `MESSAGE_CIPHERTEXT_LEN` (15) fields, regardless of plaintext size. All output fields except the\n /// ephemeral public key are uniformly random `Field` values to any observer without knowledge of the\n /// shared secret, making all encrypted messages indistinguishable by size or content.\n ///\n /// ## PKCS#7 Padding\n ///\n /// AES operates on 16-byte blocks, so the plaintext must be padded to a multiple of 16. PKCS#7 padding always\n /// adds at least 1 byte (so the receiver can always detect and strip it), which means:\n /// - 1 B plaintext -> 15 B padding -> 16 B total\n /// - 15 B plaintext -> 1 B padding -> 16 B total\n /// - 16 B plaintext -> 16 B padding -> 32 B total (full extra block)\n ///\n /// In general: if the plaintext is already a multiple of 16, a full 16-byte padding block is appended.\n ///\n /// ## Encryption Steps\n ///\n /// **1. Body encryption.** The plaintext fields are serialized to bytes (32 bytes per field) and AES-128-CBC\n /// encrypted. Since 32 is a multiple of 16, PKCS#7 always adds a full 16-byte padding block (see above):\n ///\n /// ```text\n /// +---------------------------------------------+\n /// | body ct |\n /// | PlaintextLen*32 + 16 B |\n /// +-------------------------------+--------------+\n /// | encrypted plaintext fields | PKCS#7 (16B) |\n /// | (serialized at 32 B each) | |\n /// +-------------------------------+--------------+\n /// ```\n ///\n /// **2. Header encryption.** The byte length of `body_ct` is stored as a 2-byte big-endian integer. This 2-byte\n /// header plaintext is then AES-encrypted; PKCS#7 pads the remaining 14 bytes to fill one 16-byte AES block,\n /// producing a 16-byte header ciphertext:\n ///\n /// ```text\n /// +---------------------------+\n /// | header ct |\n /// | 16 B |\n /// +--------+------------------+\n /// | body ct| PKCS#7 (14B) |\n /// | length | |\n /// | (2 B) | |\n /// +--------+------------------+\n /// ```\n ///\n /// ## Wire Format\n ///\n /// Messages are transmitted as fields, not bytes. A field is ~254 bits and can safely store 31 whole bytes, so\n /// we need to pack our byte data into 31-byte chunks. This packing drives the wire format.\n ///\n /// **Step 1 -- Assemble bytes.** The ciphertexts are laid out in a byte array, padded with zero bytes to a\n /// multiple of 31 so it divides evenly into fields:\n ///\n /// ```text\n /// +------------+-------------------------+---------+\n /// | header ct | body ct | byte pad|\n /// | 16 B | PlaintextLen*32 + 16 B | (zeros) |\n /// +------------+-------------------------+---------+\n /// |<-------- padded to a multiple of 31 B -------->|\n /// ```\n ///\n /// **Step 2 -- Pack and mask.** The byte array is split into 31-byte chunks, each stored in one field. A\n /// Poseidon2-derived mask (see `derive_shared_secret_field_mask`) is added to each so that the resulting\n /// fields appear as uniformly random `Field` values to any observer without knowledge of the shared secret,\n /// hiding the fact that the underlying ciphertext consists of 128-bit AES blocks.\n ///\n /// **Step 3 -- Assemble ciphertext.** The ephemeral public key x-coordinate is prepended and random field padding\n /// is appended to fill to 15 fields:\n ///\n /// ```text\n /// +----------+-------------------------+-------------------+\n /// | eph_pk.x | masked message fields | random field pad |\n /// | | (packed 31 B per field) | (fills to 15) |\n /// +----------+-------------------------+-------------------+\n /// |<---------- MESSAGE_CIPHERTEXT_LEN = 15 fields -------->|\n /// ```\n ///\n /// ## Key Derivation\n ///\n /// The raw ECDH shared secret point is first app-siloed into a scalar `s_app` by hashing with the contract\n /// address (see\n /// [`compute_app_siloed_shared_secret`](crate::keys::ecdh_shared_secret::compute_app_siloed_shared_secret)).\n /// Two (key, IV) pairs are then derived from `s_app` via indexed Poseidon2 hashing: one pair for the body\n /// ciphertext and one for the header ciphertext.\n fn encrypt(\n plaintext: [Field; PlaintextLen],\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> [Field; MESSAGE_CIPHERTEXT_LEN] {\n std::static_assert(\n PlaintextLen <= MESSAGE_PLAINTEXT_LEN,\n \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\",\n );\n\n // AES 128 operates on bytes, not fields, so we need to convert the fields to bytes. (This process is then\n // reversed when processing the message in `process_message_ciphertext`)\n let plaintext_bytes = encode_fields_as_bytes(plaintext);\n\n // Derive ECDH shared secret with recipient using a fresh ephemeral keypair.\n let (eph_sk, eph_pk) = generate_positive_ephemeral_key_pair();\n\n let raw_shared_secret = derive_ecdh_shared_secret(\n eph_sk,\n recipient\n .to_address_point()\n .unwrap_or_else(|| {\n aztecnr_warn_log_format!(\n \"Attempted to encrypt message for an invalid recipient ({0})\",\n )(\n [recipient.to_field()],\n );\n\n // Safety: if the recipient is an invalid address, then it is not possible to encrypt a message for\n // them because we cannot establish a shared secret. This is never expected to occur during normal\n // operation. However, it is technically possible for us to receive an invalid address, and we must\n // therefore handle it. We could simply fail, but that'd introduce a potential security issue in\n // which an attacker forces a contract to encrypt a message for an invalid address, resulting in an\n // impossible transaction - this is sometimes called a 'king of the hill' attack. We choose instead\n // to not fail and encrypt the plaintext regardless using the shared secret that results from a\n // random valid address. The sender is free to choose this address and hence shared secret, but\n // this has no security implications as they already know not only the full plaintext but also the\n // ephemeral private key anyway.\n unsafe {\n random_address_point()\n }\n })\n .inner,\n );\n\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n // It is safe to derive AES keys from `s_app` using Poseidon2 because `s_app` was derived from an ECDH shared\n // secret using an AztecAddress (the recipient). See the block comment in\n // `extract_many_close_to_uniformly_random_256_bits_using_poseidon2` for more info.\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n let ciphertext_bytes = aes128_encrypt(plaintext_bytes, body_iv, body_sym_key);\n\n // Each plaintext field is 32 bytes (a multiple of the 16-byte AES block\n // size), so PKCS#7 always appends a full 16-byte padding block:\n // |ciphertext| = PlaintextLen*32 + 16 = 16 * (1 + PlaintextLen*32 / 16)\n std::static_assert(\n ciphertext_bytes.len() == 16 * (1 + (PlaintextLen * 32) / 16),\n \"unexpected ciphertext length\",\n );\n\n // Encrypt a 2-byte header containing the body ciphertext length.\n let header_plaintext = encode_header(ciphertext_bytes.len());\n\n // Note: the aes128_encrypt builtin fn automatically appends bytes to the input, according to pkcs#7; hence why\n // the output `header_ciphertext_bytes` is 16 bytes larger than the input in this case.\n let header_ciphertext_bytes = aes128_encrypt(header_plaintext, header_iv, header_sym_key);\n // Verify expected header ciphertext size at compile time.\n std::static_assert(\n header_ciphertext_bytes.len() == HEADER_CIPHERTEXT_SIZE_IN_BYTES,\n \"unexpected ciphertext header length\",\n );\n\n // Assemble the message byte array:\n // [header_ct (16B)] [body_ct] [padding to mult of 31]\n let message_bytes_padding_to_mult_31 = get_arr_of_size__message_bytes_padding__from_PT::();\n\n let mut message_bytes = get_arr_of_size__message_bytes__from_PT::();\n\n std::static_assert(\n message_bytes.len() % 31 == 0,\n \"Unexpected error: message_bytes.len() should be divisible by 31, by construction.\",\n );\n\n let mut offset = 0;\n for i in 0..header_ciphertext_bytes.len() {\n message_bytes[offset + i] = header_ciphertext_bytes[i];\n }\n offset += header_ciphertext_bytes.len();\n\n for i in 0..ciphertext_bytes.len() {\n message_bytes[offset + i] = ciphertext_bytes[i];\n }\n offset += ciphertext_bytes.len();\n\n for i in 0..message_bytes_padding_to_mult_31.len() {\n message_bytes[offset + i] = message_bytes_padding_to_mult_31[i];\n }\n offset += message_bytes_padding_to_mult_31.len();\n\n // Ideally we would be able to have a static assert where we check that the offset would be such that we've\n // written to the entire log_bytes array, but we cannot since Noir does not treat the offset as a comptime\n // value (despite the values that it goes through being known at each stage). We instead check that the\n // computation used to obtain the offset computes the expected value (which we _can_ do in a static check), and\n // then add a cheap runtime check to also validate that the offset matches this.\n std::static_assert(\n header_ciphertext_bytes.len() + ciphertext_bytes.len() + message_bytes_padding_to_mult_31.len()\n == message_bytes.len(),\n \"unexpected message length\",\n );\n assert(offset == message_bytes.len(), \"unexpected encrypted message length\");\n\n // Pack message bytes into fields (31 bytes per field) and prepend eph_pk.x.\n let message_bytes_as_fields = encode_bytes_as_fields(message_bytes);\n\n let mut ciphertext: [Field; MESSAGE_CIPHERTEXT_LEN] = [0; MESSAGE_CIPHERTEXT_LEN];\n\n ciphertext[0] = eph_pk.x;\n\n // Mask each content field with a Poseidon2-derived value, so that they appear as uniformly random `Field`\n // values\n let mut offset = 1;\n for i in 0..message_bytes_as_fields.len() {\n let mask = derive_shared_secret_field_mask(s_app, i as u32);\n ciphertext[offset + i] = message_bytes_as_fields[i] + mask;\n }\n offset += message_bytes_as_fields.len();\n\n // Pad with random fields so that padding is indistinguishable from masked data fields.\n for i in offset..MESSAGE_CIPHERTEXT_LEN {\n // Safety: we assume that the sender wants for the message to be private - a malicious one could simply\n // reveal its contents publicly. It is therefore fine to trust the sender to provide random padding.\n ciphertext[i] = unsafe { random() };\n }\n\n ciphertext\n }\n\n unconstrained fn decrypt(\n ciphertext: BoundedVec,\n recipient: AztecAddress,\n contract_address: AztecAddress,\n ) -> Option> {\n // Extract the ephemeral public key x-coordinate and masked fields, returning None for empty ciphertext.\n if ciphertext.len() > 0 {\n let masked_fields: BoundedVec =\n array::subbvec(ciphertext, EPH_PK_X_SIZE_IN_FIELDS);\n Option::some((ciphertext.get(0), masked_fields))\n } else {\n Option::none()\n }\n .and_then(|(eph_pk_x, masked_fields)| {\n // With the x-coordinate of the ephemeral public key we can reconstruct the point as we know that the\n // y-coordinate must be positive. This may fail however, as not all x-coordinates are on the curve. In\n // that case, we simply return `Option::none`.\n point_from_x_coord_and_sign(eph_pk_x, true).and_then(|eph_pk| {\n let s_app = get_shared_secret(recipient, eph_pk, contract_address);\n\n let unmasked_fields = masked_fields.mapi(|i, field| {\n let unmasked = unmask_field(s_app, i, field);\n // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it\n // later, so we can simply set it to 0\n unmasked.unwrap_or(0)\n });\n let ciphertext_without_eph_pk_x = decode_bytes_from_fields(unmasked_fields);\n\n // Derive symmetric keys:\n let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret::<2>(s_app);\n let (body_sym_key, body_iv) = pairs[0];\n let (header_sym_key, header_iv) = pairs[1];\n\n // Extract the header ciphertext\n let header_start = 0;\n let header_ciphertext: [u8; HEADER_CIPHERTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), header_start);\n // We need to convert the array to a BoundedVec because the oracle expects a BoundedVec as it's\n // designed to work with messages with unknown length at compile time. This would not be necessary\n // here as the header ciphertext length is fixed. But we do it anyway to not have to have duplicate\n // oracles.\n let header_ciphertext_bvec =\n BoundedVec::::from_array(header_ciphertext);\n\n try_aes128_decrypt(header_ciphertext_bvec, header_iv, header_sym_key)\n // Extract ciphertext length from header (2 bytes, big-endian)\n .and_then(|header_plaintext| extract_ciphertext_length(header_plaintext))\n .filter(|ciphertext_length| ciphertext_length <= MESSAGE_PLAINTEXT_SIZE_IN_BYTES)\n .map(|ciphertext_length| {\n // Extract and decrypt main ciphertext\n let ciphertext_start = header_start + HEADER_CIPHERTEXT_SIZE_IN_BYTES;\n let ciphertext_with_padding: [u8; MESSAGE_PLAINTEXT_SIZE_IN_BYTES] =\n array::subarray(ciphertext_without_eph_pk_x.storage(), ciphertext_start);\n BoundedVec::from_parts(ciphertext_with_padding, ciphertext_length)\n })\n // Decrypt main ciphertext and return it\n .and_then(|ciphertext| try_aes128_decrypt(ciphertext, body_iv, body_sym_key))\n // Convert bytes back to fields (32 bytes per field). Returns None if the actual bytes are\n // not valid.\n .and_then(|plaintext_bytes| try_decode_fields_from_bytes(plaintext_bytes))\n })\n })\n }\n}\n\n/// Encodes the body ciphertext length into a 2-byte big-endian header.\nfn encode_header(ciphertext_length: u32) -> [u8; 2] {\n [(ciphertext_length >> 8) as u8, ciphertext_length as u8]\n}\n\n/// Extracts the body ciphertext length from a decrypted header as a 2-byte big-endian integer.\n///\n/// Returns `Option::none()` if the header has fewer than 2 bytes.\nunconstrained fn extract_ciphertext_length(header: BoundedVec) -> Option {\n if header.len() >= 2 {\n Option::some(((header.get(0) as u32) << 8) | (header.get(1) as u32))\n } else {\n Option::none()\n }\n}\n\n/// 2^248: upper bound for values that fit in 31 bytes\nglobal TWO_POW_248: Field = 2.pow_32(248);\n\n/// Removes the Poseidon2-derived mask from a ciphertext field. Returns the unmasked value if it fits in 31 bytes\n/// (a content field), or `None` if it doesn't (random padding). Unconstrained to prevent accidental use in\n/// constrained context.\nunconstrained fn unmask_field(s_app: Field, index: u32, masked: Field) -> Option {\n let unmasked = masked - derive_shared_secret_field_mask(s_app, index);\n if unmasked.lt(TWO_POW_248) {\n Option::some(unmasked)\n } else {\n Option::none()\n }\n}\n\n/// Produces a random valid address point, i.e. one that is on the curve. This is equivalent to calling\n/// [`AztecAddress::to_address_point`] on a random valid address.\nunconstrained fn random_address_point() -> AddressPoint {\n let mut result = std::mem::zeroed();\n\n loop {\n // We simply produce random x coordinates until we find one that is on the curve. About half of the x\n // coordinates fulfill this condition, so this should only take a few iterations at most.\n let x_coord = random();\n let point = point_from_x_coord_and_sign(x_coord, true);\n if point.is_some() {\n result = AddressPoint { inner: point.unwrap() };\n break;\n }\n }\n\n result\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::{compute_app_siloed_shared_secret, derive_ecdh_shared_secret},\n messages::{\n encoding::{HEADER_CIPHERTEXT_SIZE_IN_BYTES, MESSAGE_PLAINTEXT_LEN, MESSAGE_PLAINTEXT_SIZE_IN_BYTES},\n encryption::message_encryption::MessageEncryption,\n },\n test::helpers::test_environment::TestEnvironment,\n };\n use crate::protocol::{address::AztecAddress, traits::FromField};\n use super::{AES128, encode_header, random_address_point};\n use std::{embedded_curve_ops::EmbeddedCurveScalar, test::OracleMock};\n\n #[test]\n unconstrained fn encrypt_decrypt_deterministic() {\n let env = TestEnvironment::new();\n\n // Message decryption requires oracles that are only available during private execution\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n\n let recipient = AztecAddress::from_field(\n 0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70c,\n );\n\n // Mock random values for deterministic test\n let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(eph_sk).times(1);\n\n let randomness = 0x0101010101010101010101010101010101010101010101010101010101010101;\n let _ = OracleMock::mock(\"aztec_utl_getRandomField\").returns(randomness).times(1000000);\n\n let _ = OracleMock::mock(\"aztec_prv_getNextAppTagAsSender\").returns(42);\n\n // Encrypt the message\n let encrypted_message = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n // Compute the same app-siloed shared secret that the oracle would return\n let raw_shared_secret = derive_ecdh_shared_secret(\n EmbeddedCurveScalar::from_field(eph_sk),\n recipient.to_address_point().unwrap().inner,\n );\n let s_app = compute_app_siloed_shared_secret(raw_shared_secret, contract_address);\n\n let _ = OracleMock::mock(\"aztec_utl_getSharedSecret\").returns(s_app);\n\n // Decrypt the message\n let decrypted = AES128::decrypt(encrypted_message, recipient, contract_address).unwrap();\n\n // The decryption function spits out a BoundedVec because it's designed to work with messages with unknown\n // length at compile time. For this reason we need to convert the original input to a BoundedVec.\n let plaintext_bvec = BoundedVec::::from_array(plaintext);\n\n // Verify decryption matches original plaintext\n assert_eq(decrypted, plaintext_bvec, \"Decrypted bytes should match original plaintext\");\n\n // The following is a workaround of \"struct is never constructed\" Noir compilation error (we only ever use\n // static methods of the struct).\n let _ = AES128 {};\n });\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_random() {\n // Same as `encrypt_decrypt_deterministic`, except we don't mock any of the oracles and rely on\n // `TestEnvironment` instead.\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test]\n unconstrained fn encrypt_to_invalid_address() {\n // x = 3 is a non-residue for this curve, resulting in an invalid address\n let invalid_address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n\n let _ = AES128::encrypt([1, 2, 3, 4], invalid_address, contract_address);\n }\n\n // Documents the PKCS#7 padding behavior that `encrypt` relies on (see its static_assert).\n #[test]\n fn pkcs7_padding_always_adds_at_least_one_byte() {\n let key = [0 as u8; 16];\n let iv = [0 as u8; 16];\n\n // 1 byte input + 15 bytes padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 1], iv, key).len(), 16);\n\n // 15 bytes input + 1 byte padding = 16 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 15], iv, key).len(), 16);\n\n // 16 bytes input (block-aligned) + full 16-byte padding block = 32 bytes\n assert_eq(std::aes128::aes128_encrypt([0; 16], iv, key).len(), 32);\n }\n\n #[test]\n unconstrained fn encrypt_decrypt_max_size_plaintext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let mut plaintext = [0; MESSAGE_PLAINTEXT_LEN];\n for i in 0..MESSAGE_PLAINTEXT_LEN {\n plaintext[i] = i as Field;\n }\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n assert_eq(\n AES128::decrypt(\n BoundedVec::from_array(ciphertext),\n recipient,\n contract_address,\n )\n .unwrap(),\n BoundedVec::from_array(plaintext),\n );\n });\n }\n\n #[test(should_fail_with = \"Plaintext length exceeds MESSAGE_PLAINTEXT_LEN\")]\n unconstrained fn encrypt_oversized_plaintext() {\n let address = AztecAddress { inner: 3 };\n let contract_address = AztecAddress { inner: 42 };\n let plaintext: [Field; MESSAGE_PLAINTEXT_LEN + 1] = [0; MESSAGE_PLAINTEXT_LEN + 1];\n let _ = AES128::encrypt(plaintext, address, contract_address);\n }\n\n #[test]\n unconstrained fn random_address_point_produces_valid_points() {\n // About half of random addresses are invalid, so testing just a couple gives us high confidence that\n // `random_address_point` is indeed producing valid addresses.\n for _ in 0..10 {\n let random_address = AztecAddress { inner: random_address_point().inner.x };\n assert(random_address.to_address_point().is_some());\n }\n }\n\n #[test]\n unconstrained fn decrypt_invalid_ephemeral_public_key() {\n let mut env = TestEnvironment::new();\n\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3, 4];\n let ciphertext = AES128::encrypt(plaintext, recipient, contract_address);\n\n // The first field of the ciphertext is the x-coordinate of the ephemeral public key. We set it to a known\n // non-residue (3), causing `decrypt` to fail to produce a decryption shared secret.\n let mut bad_ciphertext = BoundedVec::from_array(ciphertext);\n bad_ciphertext.set(0, 3);\n\n assert(AES128::decrypt(bad_ciphertext, recipient, contract_address).is_none());\n });\n }\n\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_ciphertext() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n assert(AES128::decrypt(BoundedVec::new(), recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header AES decrypt oracle to return an empty result. The TS oracle never throws on invalid\n // input: it decrypts to garbage bytes or returns empty\n #[test]\n unconstrained fn decrypt_returns_none_on_empty_header() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let empty_header = BoundedVec::::new();\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(empty_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n // Mocks the header oracle to return a 2-byte header that decodes to a ciphertext_length one past the maximum\n // allowed value, verifying the edge case is handled correctly.\n #[test]\n unconstrained fn decrypt_returns_none_on_oversized_ciphertext_length() {\n let mut env = TestEnvironment::new();\n let recipient = env.create_light_account();\n\n env.private_context(|context| {\n let contract_address = context.this_address();\n let plaintext = [1, 2, 3];\n let ciphertext = BoundedVec::from_array(AES128::encrypt(plaintext, recipient, contract_address));\n\n let bad_header = BoundedVec::::from_array(encode_header(\n MESSAGE_PLAINTEXT_SIZE_IN_BYTES + 1,\n ));\n let _ = OracleMock::mock(\"aztec_utl_decryptAes128\").returns(Option::some(bad_header)).times(1);\n\n assert(AES128::decrypt(ciphertext, recipient, contract_address).is_none());\n });\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr","function_locations":[{"start":1764,"name":"extract_many_close_to_uniformly_random_256_bits_using_poseidon2"},{"start":4783,"name":"derive_aes_symmetric_key_and_iv_from_uniformly_random_256_bits"},{"start":5332,"name":"derive_aes_symmetric_key_and_iv_from_shared_secret"},{"start":10365,"name":"::encrypt"},{"start":17702,"name":"::decrypt"},{"start":21732,"name":"encode_header"},{"start":22063,"name":"extract_ciphertext_length"},{"start":22648,"name":"unmask_field"},{"start":23061,"name":"random_address_point"},{"start":24228,"name":"test::encrypt_decrypt_deterministic"},{"start":26706,"name":"test::encrypt_decrypt_random"},{"start":27552,"name":"test::encrypt_to_invalid_address"},{"start":28002,"name":"test::pkcs7_padding_always_adds_at_least_one_byte"},{"start":28566,"name":"test::encrypt_decrypt_max_size_plaintext"},{"start":29465,"name":"test::encrypt_oversized_plaintext"},{"start":29823,"name":"test::random_address_point_produces_valid_points"},{"start":30274,"name":"test::decrypt_invalid_ephemeral_public_key"},{"start":31119,"name":"test::decrypt_returns_none_on_empty_ciphertext"},{"start":31673,"name":"test::decrypt_returns_none_on_empty_header"},{"start":32599,"name":"test::decrypt_returns_none_on_oversized_ciphertext_length"}]},"138":{"source":"use crate::{\n event::{event_interface::EventInterface, EventSelector},\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n utils::array,\n};\nuse crate::protocol::traits::{FromField, Serialize, ToField};\n\n/// The number of fields in a private event message content that are not the event's serialized representation (1 field\n/// for randomness).\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 1;\npub(crate) global PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 0;\n\n/// The maximum length of the packed representation of an event's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, randomness, etc.).\npub global MAX_EVENT_SERIALIZED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_event_message`].\npub fn encode_private_event_message(\n event: Event,\n randomness: Field,\n) -> [Field; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Event: EventInterface + Serialize,\n{\n std::static_assert(\n ::N <= MAX_EVENT_SERIALIZED_LEN,\n \"event's serialized length exceeds the maximum allowed for private events\",\n );\n\n // We use `Serialize` because we want for events to be processable by off-chain actors, e.g. block explorers,\n // wallets and apps, without having to rely on contract invocation. If we used `Packable` we'd need to call utility\n // functions in order to unpack events, which would introduce a level of complexity we don't currently think is\n // worth the savings in DA (for public events) and proving time (when encrypting private event messages).\n let serialized_event = event.serialize();\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_plaintext = [0; PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n\n for i in 0..serialized_event.len() {\n msg_plaintext[PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = serialized_event[i];\n }\n\n // The event type id is stored in the message metadata\n encode_message(\n PRIVATE_EVENT_MSG_TYPE_ID,\n Event::get_event_type_id().to_field() as u64,\n msg_plaintext,\n )\n}\n\n/// Decodes the plaintext from a private event message (i.e. one of type [`PRIVATE_EVENT_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_event_message`].\n///\n/// Note that while [`encode_private_event_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_event_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(EventSelector, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let event_type_id = EventSelector::from_field(msg_metadata as Field);\n\n // If PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // destructuring of the private event message encoding below must be updated as well.\n std::static_assert(\n PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 1,\n \"unexpected value for PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let randomness = msg_content.get(PRIVATE_EVENT_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let serialized_event = array::subbvec(msg_content, PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((event_type_id, randomness, serialized_event))\n }\n}\n\nmod test {\n use crate::{\n event::event_interface::EventInterface,\n messages::{\n encoding::decode_message,\n logs::event::{decode_private_event_message, encode_private_event_message},\n msg_type::PRIVATE_EVENT_MSG_TYPE_ID,\n },\n };\n use crate::protocol::traits::Serialize;\n use crate::test::mocks::mock_event::MockEvent;\n\n global VALUE: Field = 7;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let event = MockEvent::new(VALUE).build_event();\n\n let message_plaintext = encode_private_event_message(event, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_EVENT_MSG_TYPE_ID);\n\n let (event_type_id, randomness, serialized_event) =\n decode_private_event_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(event_type_id, MockEvent::get_event_type_id());\n assert_eq(randomness, RANDOMNESS);\n assert_eq(serialized_event, BoundedVec::from_array(event.serialize()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_event_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0]);\n assert(decode_private_event_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/event.nr","function_locations":[{"start":1377,"name":"encode_private_event_message"},{"start":3755,"name":"decode_private_event_message"},{"start":5127,"name":"test::encode_decode"},{"start":5869,"name":"test::decode_empty_content_returns_none"},{"start":6064,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"140":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\n\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX: u32 = 1;\npub(crate) global PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 2;\n\n/// The maximum length of the packed representation of a note's contents. This is limited by private log size,\n/// encryption overhead and extra fields in the message (e.g. message type id, storage slot, randomness, etc.).\npub global MAX_NOTE_PACKED_LEN: u32 = MAX_MESSAGE_CONTENT_LEN - PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_private_note_message`].\npub fn encode_private_note_message(\n note: Note,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n) -> [Field; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n Note: NoteType + Packable,\n{\n let packed_note = note.pack();\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // encoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let mut msg_content = [0; PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX] = storage_slot;\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n for i in 0..packed_note.len() {\n msg_content[PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_note[i];\n }\n\n // Notes use the note type id for metadata\n encode_message(PRIVATE_NOTE_MSG_TYPE_ID, Note::get_id() as u64, msg_content)\n}\n\n/// Decodes the plaintext from a private note message (i.e. one of type [`PRIVATE_NOTE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_private_note_message`].\n///\n/// Note that while [`encode_private_note_message`] returns a fixed-size array, this function takes a [`BoundedVec`]\n/// instead. This is because when decoding we're typically processing runtime-sized plaintexts, more specifically,\n/// those that originate from [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_private_note_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(Field, AztecAddress, Field, Field, BoundedVec)> {\n if msg_content.len() <= PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN is changed, causing the assertion below to fail, then the\n // decoding below must be updated as well.\n std::static_assert(\n PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN\",\n );\n\n let owner = AztecAddress::from_field(msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_OWNER_INDEX));\n let storage_slot = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_STORAGE_SLOT_INDEX);\n let randomness = msg_content.get(PRIVATE_NOTE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let packed_note = array::subbvec(msg_content, PRIVATE_NOTE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN);\n\n Option::some((note_type_id, owner, storage_slot, randomness, packed_note))\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::note::{decode_private_note_message, encode_private_note_message, MAX_NOTE_PACKED_LEN},\n msg_type::PRIVATE_NOTE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global STORAGE_SLOT: Field = 9;\n global RANDOMNESS: Field = 10;\n\n #[test]\n unconstrained fn encode_decode() {\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[derive(Packable)]\n struct MaxSizeNote {\n data: [Field; MAX_NOTE_PACKED_LEN],\n }\n\n impl NoteType for MaxSizeNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test]\n unconstrained fn encode_decode_max_size_note() {\n let mut data = [0; MAX_NOTE_PACKED_LEN];\n for i in 0..MAX_NOTE_PACKED_LEN {\n data[i] = i as Field;\n }\n let note = MaxSizeNote { data };\n\n let encoded = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n let (msg_type_id, msg_metadata, msg_content) = decode_message(BoundedVec::from_array(encoded)).unwrap();\n\n assert_eq(msg_type_id, PRIVATE_NOTE_MSG_TYPE_ID);\n\n let (note_type_id, owner, storage_slot, randomness, packed_note) =\n decode_private_note_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MaxSizeNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(storage_slot, STORAGE_SLOT);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(packed_note, BoundedVec::from_array(data));\n }\n\n #[derive(Packable)]\n struct OversizedNote {\n data: [Field; MAX_NOTE_PACKED_LEN + 1],\n }\n\n impl NoteType for OversizedNote {\n fn get_id() -> Field {\n 0\n }\n }\n\n #[test(should_fail_with = \"Invalid message content: it must have a length of at most MAX_MESSAGE_CONTENT_LEN\")]\n fn encode_oversized_note_fails() {\n let note = OversizedNote { data: [0; MAX_NOTE_PACKED_LEN + 1] };\n let _ = encode_private_note_message(note, OWNER, STORAGE_SLOT, RANDOMNESS);\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_private_note_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_with_only_reserved_fields_returns_none() {\n let content = BoundedVec::from_array([0, 0, 0]);\n assert(decode_private_note_message(0, content).is_none());\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/note.nr","function_locations":[{"start":1518,"name":"encode_private_note_message"},{"start":3312,"name":"decode_private_note_message"},{"start":5000,"name":"test::encode_decode"},{"start":5923,"name":"test::::get_id"},{"start":6019,"name":"test::encode_decode_max_size_note"},{"start":7035,"name":"test::::get_id"},{"start":7221,"name":"test::encode_oversized_note_fails"},{"start":7456,"name":"test::decode_empty_content_returns_none"},{"start":7650,"name":"test::decode_with_only_reserved_fields_returns_none"}]},"141":{"source":"use crate::{\n messages::{\n encoding::{encode_message, MAX_MESSAGE_CONTENT_LEN, MESSAGE_EXPANDED_METADATA_LEN},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n utils::array,\n};\nuse crate::protocol::{address::AztecAddress, traits::{FromField, Packable, ToField}};\n\n/// The number of fields in a private note message content that are not the note's packed representation.\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN: u32 = 3;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX: u32 = 0;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX: u32 = 1;\npub(crate) global PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX: u32 = 2;\n\n/// Partial notes have a maximum packed length of their private fields bound by extra content in their private message\n/// (e.g. the storage slot, note completion log tag, etc.).\npub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 =\n MAX_MESSAGE_CONTENT_LEN - PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN;\n\n/// Creates the plaintext for a partial note private message (i.e. one of type [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// This plaintext is meant to be decoded via [`decode_partial_note_private_message`].\npub fn encode_partial_note_private_message(\n partial_note_private_content: PartialNotePrivateContent,\n owner: AztecAddress,\n randomness: Field,\n note_completion_log_tag: Field,\n ) -> [Field; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N + MESSAGE_EXPANDED_METADATA_LEN]\nwhere\n PartialNotePrivateContent: NoteType + Packable,\n{\n let packed_private_content = partial_note_private_content.pack();\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail, then\n // the encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n let mut msg_content =\n [0; PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + ::N];\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX] = owner.to_field();\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX] = randomness;\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX] = note_completion_log_tag;\n\n for i in 0..packed_private_content.len() {\n msg_content[PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN + i] = packed_private_content[i];\n }\n\n encode_message(\n PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n // Notes use the note type id for metadata\n PartialNotePrivateContent::get_id() as u64,\n msg_content,\n )\n}\n\n/// Decodes the plaintext from a partial note private message (i.e. one of type\n/// [`PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID`]).\n///\n/// Returns `None` if `msg_content` has too few fields. This plaintext is meant to have originated\n/// from [`encode_partial_note_private_message`].\n///\n/// Note that while [`encode_partial_note_private_message`] returns a fixed-size array, this function takes a\n/// [`BoundedVec`] instead. This is because when decoding we're typically processing runtime-sized plaintexts, more\n/// specifically, those that originate from\n/// [`crate::messages::encryption::message_encryption::MessageEncryption::decrypt`].\npub(crate) unconstrained fn decode_partial_note_private_message(\n msg_metadata: u64,\n msg_content: BoundedVec,\n) -> Option<(AztecAddress, Field, Field, Field, BoundedVec)> {\n if msg_content.len() < PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN {\n Option::none()\n } else {\n let note_type_id: Field = msg_metadata as Field; // TODO: make note type id not be a full field\n\n // If PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN is changed, causing the assertion below to fail,\n // then the destructuring of the partial note private message encoding below must be updated as well.\n std::static_assert(\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN == 3,\n \"unexpected value for PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NON_NOTE_FIELDS_LEN\",\n );\n\n // We currently have three fields that are not the partial note's packed representation, which are the owner,\n // the randomness, and the note completion log tag.\n let owner = AztecAddress::from_field(\n msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_OWNER_INDEX),\n );\n let randomness = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RANDOMNESS_INDEX);\n let note_completion_log_tag = msg_content.get(PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_NOTE_COMPLETION_LOG_TAG_INDEX);\n\n let packed_private_note_content: BoundedVec = array::subbvec(\n msg_content,\n PARTIAL_NOTE_PRIVATE_MSG_PLAINTEXT_RESERVED_FIELDS_LEN,\n );\n\n Option::some(\n (owner, randomness, note_completion_log_tag, note_type_id, packed_private_note_content),\n )\n }\n}\n\nmod test {\n use crate::{\n messages::{\n encoding::decode_message,\n logs::partial_note::{decode_partial_note_private_message, encode_partial_note_private_message},\n msg_type::PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID,\n },\n note::note_interface::NoteType,\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, Packable}};\n use crate::test::mocks::mock_note::MockNote;\n\n global VALUE: Field = 7;\n global OWNER: AztecAddress = AztecAddress::from_field(8);\n global RANDOMNESS: Field = 10;\n global NOTE_COMPLETION_LOG_TAG: Field = 11;\n\n #[test]\n unconstrained fn encode_decode() {\n // Note that here we use MockNote as the private fields of a partial note\n let note = MockNote::new(VALUE).build_note();\n\n let message_plaintext = encode_partial_note_private_message(note, OWNER, RANDOMNESS, NOTE_COMPLETION_LOG_TAG);\n\n let (msg_type_id, msg_metadata, msg_content) =\n decode_message(BoundedVec::from_array(message_plaintext)).unwrap();\n\n assert_eq(msg_type_id, PARTIAL_NOTE_PRIVATE_MSG_TYPE_ID);\n\n let (owner, randomness, note_completion_log_tag, note_type_id, packed_note) =\n decode_partial_note_private_message(msg_metadata, msg_content).unwrap();\n\n assert_eq(note_type_id, MockNote::get_id());\n assert_eq(owner, OWNER);\n assert_eq(randomness, RANDOMNESS);\n assert_eq(note_completion_log_tag, NOTE_COMPLETION_LOG_TAG);\n assert_eq(packed_note, BoundedVec::from_array(note.pack()));\n }\n\n #[test]\n unconstrained fn decode_empty_content_returns_none() {\n let empty = BoundedVec::new();\n assert(decode_partial_note_private_message(0, empty).is_none());\n }\n\n #[test]\n unconstrained fn decode_succeeds_with_only_reserved_fields() {\n let content = BoundedVec::from_array([0, 0, 0]);\n let (_, _, _, _, packed_note) = decode_partial_note_private_message(0, content).unwrap();\n assert_eq(packed_note.len(), 0);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/logs/partial_note.nr","function_locations":[{"start":1715,"name":"encode_partial_note_private_message"},{"start":3810,"name":"decode_partial_note_private_message"},{"start":6022,"name":"test::encode_decode"},{"start":6999,"name":"test::decode_empty_content_returns_none"},{"start":7197,"name":"test::decode_succeeds_with_only_reserved_fields"}]},"151":{"source":"pub(crate) mod event_validation_request;\npub mod offchain;\n\nmod message_context;\npub use message_context::MessageContext;\n\npub(crate) mod note_validation_request;\npub(crate) mod log_retrieval_request;\npub(crate) mod log_retrieval_response;\npub(crate) mod pending_tagged_log;\n\nuse crate::{\n capsules::CapsuleArray,\n ephemeral::EphemeralArray,\n event::EventSelector,\n messages::{\n discovery::partial_notes::DeliveredPendingPartialNote,\n encoding::MESSAGE_CIPHERTEXT_LEN,\n logs::{event::MAX_EVENT_SERIALIZED_LEN, note::MAX_NOTE_PACKED_LEN},\n processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse,\n note_validation_request::NoteValidationRequest,\n },\n },\n oracle::message_processing,\n};\nuse crate::protocol::{\n address::AztecAddress,\n constants::DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n hash::{compute_log_tag, sha256_to_field},\n traits::{Deserialize, Serialize},\n};\nuse event_validation_request::EventValidationRequest;\n\nglobal NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\nglobal LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT: Field = sha256_to_field(\n \"AZTEC_NR::LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT\".as_bytes(),\n);\n\n/// An offchain-delivered message with resolved context, ready for processing during sync.\n#[derive(Serialize, Deserialize)]\npub struct OffchainMessageWithContext {\n pub message_ciphertext: BoundedVec,\n pub message_context: MessageContext,\n}\n\n/// Enqueues a note for validation and storage by PXE.\n///\n/// Once validated, the note becomes retrievable via the `get_notes` oracle. The note will be scoped to\n/// `contract_address`, meaning other contracts will not be able to access it unless authorized.\n///\n/// In order for the note validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many note validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// The `packed_note` is what `getNotes` will later return. PXE indexes notes by `storage_slot`, so this value is\n/// typically used to filter notes that correspond to different state variables. `note_hash` and `nullifier` are the\n/// inner hashes, i.e. the raw hashes returned by `NoteHash::compute_note_hash` and `NoteHash::compute_nullifier`. PXE\n/// will verify that the siloed unique note hash was inserted into the tree at `tx_hash`, and will store the nullifier\n/// to later check for nullification.\n///\n/// `owner` is the address used in note hash and nullifier computation, often requiring knowledge of their nullifier\n/// secret key.\n///\n/// `scope` is the account to which the note message was delivered (i.e. the address the message was encrypted to).\n/// This determines which PXE account can see the note - other accounts will not be able to access it (e.g. other\n/// accounts will not be able to see one another's token balance notes, even in the same PXE) unless authorized. In\n/// most cases `recipient` equals `owner`, but they can differ in scenarios like delegated discovery.\npub unconstrained fn enqueue_note_for_validation(\n contract_address: AztecAddress,\n owner: AztecAddress,\n storage_slot: Field,\n randomness: Field,\n note_nonce: Field,\n packed_note: BoundedVec,\n note_hash: Field,\n nullifier: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n NoteValidationRequest {\n contract_address,\n owner,\n storage_slot,\n randomness,\n note_nonce,\n packed_note,\n note_hash,\n nullifier,\n tx_hash,\n },\n )\n}\n\n/// Enqueues an event for validation and storage by PXE.\n///\n/// This is the primary way for custom message handlers (registered via\n/// [`crate::macros::AztecConfig::custom_message_handler`]) to deliver reassembled events back to PXE after processing\n/// application-specific message formats.\n///\n/// In order for the event validation and insertion to occur, `validate_and_store_enqueued_notes_and_events` must be\n/// later called. For optimal performance, accumulate as many event validation requests as possible and then validate\n/// them all at the end (which results in PXE minimizing the number of network round-trips).\n///\n/// Note that `validate_and_store_enqueued_notes_and_events` is called by Aztec.nr after processing messages, so custom\n/// message processors do not need to be concerned with this.\npub unconstrained fn enqueue_event_for_validation(\n contract_address: AztecAddress,\n event_type_id: EventSelector,\n randomness: Field,\n serialized_event: BoundedVec,\n event_commitment: Field,\n tx_hash: Field,\n) {\n EphemeralArray::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).push(\n EventValidationRequest {\n contract_address,\n event_type_id,\n randomness,\n serialized_event,\n event_commitment,\n tx_hash,\n },\n )\n}\n\n/// Validates and stores all enqueued notes and events.\n///\n/// Processes all requests enqueued via [`enqueue_note_for_validation`] and [`enqueue_event_for_validation`], inserting\n/// them into the note database and event store respectively, making them queryable via `get_notes` oracle and our TS\n/// API (PXE::getPrivateEvents).\npub unconstrained fn validate_and_store_enqueued_notes_and_events(scope: AztecAddress) {\n message_processing::validate_and_store_enqueued_notes_and_events(\n NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT,\n MAX_NOTE_PACKED_LEN as Field,\n MAX_EVENT_SERIALIZED_LEN as Field,\n scope,\n );\n\n // Defensive clearing: purge the queues after processing to prevent double-processing if this function is called\n // more than once in the same call frame. It is currently defensive because we only call this once per sync run.\n let _ = EphemeralArray::::at(NOTE_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n let _ = EphemeralArray::::at(EVENT_VALIDATION_REQUESTS_ARRAY_BASE_SLOT).clear();\n}\n\n/// Efficiently queries the node for logs that result in the completion of all `DeliveredPendingPartialNote`s stored in\n/// a `CapsuleArray` by performing all node communication concurrently. Returns an `EphemeralArray` with Options\n/// for the responses that correspond to the pending partial notes at the same index.\n///\n/// For example, given an array with pending partial notes `[ p1, p2, p3 ]`, where `p1` and `p3` have corresponding\n/// completion logs but `p2` does not, the returned `EphemeralArray` will have contents `[some(p1_log), none(),\n/// some(p3_log)]`.\npub(crate) unconstrained fn get_pending_partial_notes_completion_logs(\n contract_address: AztecAddress,\n pending_partial_notes: CapsuleArray,\n) -> EphemeralArray> {\n let log_retrieval_requests = EphemeralArray::at(LOG_RETRIEVAL_REQUESTS_ARRAY_BASE_SLOT);\n\n // We create a LogRetrievalRequest for each PendingPartialNote in the EphemeralArray. Because we need the indices in\n // the request array to match the indices in the partial note array, we can't use EphemeralArray::for_each, as that\n // function has arbitrary iteration order. Instead, we manually iterate the array from the beginning and push into\n // the requests array, which we expect to be empty.\n let mut i = 0;\n let pending_partial_notes_count = pending_partial_notes.len();\n while i < pending_partial_notes_count {\n let pending_partial_note = pending_partial_notes.get(i);\n // Partial note completion logs are emitted with a domain-separated tag. To find matching logs, we apply the\n // same domain separation to the stored raw tag.\n let log_tag = compute_log_tag(\n pending_partial_note.note_completion_log_tag,\n DOM_SEP__NOTE_COMPLETION_LOG_TAG,\n );\n log_retrieval_requests.push(LogRetrievalRequest { contract_address, unsiloed_tag: log_tag });\n i += 1;\n }\n\n let responses = message_processing::get_logs_by_tag(log_retrieval_requests);\n\n // Defensive clearing: prevent stale requests if this function is called more than once in the same call frame.\n let _ = log_retrieval_requests.clear();\n\n responses\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/mod.nr","function_locations":[{"start":3763,"name":"enqueue_note_for_validation"},{"start":5177,"name":"enqueue_event_for_validation"},{"start":5884,"name":"validate_and_store_enqueued_notes_and_events"},{"start":7412,"name":"get_pending_partial_notes_completion_logs"}]},"153":{"source":"use crate::{\n capsules::CapsuleArray,\n context::UtilityContext,\n ephemeral::EphemeralArray,\n messages::{encoding::MESSAGE_CIPHERTEXT_LEN, processing::OffchainMessageWithContext},\n oracle::contract_sync::set_contract_sync_cache_invalid,\n protocol::{\n address::AztecAddress,\n constants::MAX_TX_LIFETIME,\n hash::sha256_to_field,\n traits::{Deserialize, Serialize},\n },\n};\n\n/// Base capsule slot for the persistent inbox of [`PendingOffchainMsg`] entries.\n///\n/// This is the slot where we accumulate messages received through [`receive`].\nglobal OFFCHAIN_INBOX_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_INBOX_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to pass tx hash resolution requests to PXE.\nglobal OFFCHAIN_CONTEXT_REQUESTS_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_CONTEXT_REQUESTS_SLOT\".as_bytes());\n\n/// Ephemeral array slot used by [`sync_inbox`] to collect messages ready for processing.\nglobal OFFCHAIN_READY_MESSAGES_SLOT: Field = sha256_to_field(\"AZTEC_NR::OFFCHAIN_READY_MESSAGES_SLOT\".as_bytes());\n\n/// Maximum number of offchain messages accepted by `offchain_receive` in a single call.\npub global MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL: u32 = 16;\n\n/// Tolerance added to the `MAX_TX_LIFETIME` cap for message expiration.\nglobal TX_EXPIRATION_TOLERANCE: u64 = 7200; // 2 hours\n\n/// Maximum time-to-live for a tx-bound offchain message.\n///\n/// After `anchor_block_timestamp + MAX_MSG_TTL`, the message is evicted from the inbox.\nglobal MAX_MSG_TTL: u64 = MAX_TX_LIFETIME + TX_EXPIRATION_TOLERANCE;\n\n/// A function that manages offchain-delivered messages for processing during sync.\n///\n/// Offchain messages are messages that are not broadcasted via onchain logs. They are instead delivered to the\n/// recipient by calling the `offchain_receive` utility function (injected by the `#[aztec]` macro). Message transport\n/// is the app's responsibility. Typical examples of transport methods are: messaging apps, email, QR codes, etc.\n///\n/// Once offchain messages are delivered to the recipient's private environment via `offchain_receive`, messages are\n/// locally stored in a persistent inbox.\n///\n/// This function determines when each message in said inbox is ready for processing, when it can be safely disposed\n/// of, etc.\n///\n/// The only current implementation of an `OffchainInboxSync` is [`sync_inbox`], which manages an inbox with expiration\n/// based eviction and automatic transaction context resolution.\npub(crate) type OffchainInboxSync = unconstrained fn[Env](\n/* contract_address */AztecAddress, /* scope */ AztecAddress) -> EphemeralArray;\n\n/// A message delivered via the `offchain_receive` utility function.\npub struct OffchainMessage {\n /// The encrypted message payload.\n pub ciphertext: BoundedVec,\n /// The intended recipient of the message.\n pub recipient: AztecAddress,\n /// The hash of the transaction that produced this message. `Option::none` indicates a tx-less message.\n pub tx_hash: Option,\n /// Anchor block timestamp at message emission.\n pub anchor_block_timestamp: u64,\n}\n\n/// An offchain message awaiting processing (or re-processing) in the inbox.\n///\n/// Messages remain in the inbox until they expire, even if they have already been processed. This is necessary to\n/// handle reorgs: a processed message may need to be re-processed if the transaction that provided its context is\n/// reverted. On each sync, resolved messages are promoted to [`OffchainMessageWithContext`] for processing.\n#[derive(Serialize, Deserialize)]\nstruct PendingOffchainMsg {\n /// The encrypted message payload.\n ciphertext: BoundedVec,\n /// The intended recipient of the message.\n recipient: AztecAddress,\n /// The hash of the transaction that produced this message. A value of 0 indicates a tx-less message.\n tx_hash: Field,\n /// Anchor block timestamp at message emission. Used to compute the effective expiration: messages are evicted\n /// after `anchor_block_timestamp + MAX_MSG_TTL`.\n anchor_block_timestamp: u64,\n}\n\n/// Delivers offchain messages to the given contract's offchain inbox for subsequent processing.\n///\n/// Offchain messages are transaction effects that are not broadcasted via onchain logs. Instead, the sender shares the\n/// message to the recipient through an external channel (e.g. a URL accessible by the recipient). The recipient then\n/// calls this function to hand the messages to the contract so they can be processed through the same mechanisms as\n/// onchain messages.\n///\n/// Each message is routed to the inbox scoped to its `recipient` field, so messages for different accounts are\n/// automatically isolated.\n///\n/// Messages are processed when their originating transaction is found onchain (providing the context needed to\n/// validate resulting notes and events).\n///\n/// Messages are kept in the inbox until they expire. The effective expiration is\n/// `anchor_block_timestamp + MAX_MSG_TTL`.\n///\n/// Processing order is not guaranteed.\npub unconstrained fn receive(\n contract_address: AztecAddress,\n messages: BoundedVec,\n) {\n // May contain duplicates if multiple messages target the same recipient. This is harmless since\n // cache invalidation on the TS side is idempotent (deleting an already-deleted key is a no-op).\n let mut scopes: BoundedVec = BoundedVec::new();\n let mut i = 0;\n let messages_len = messages.len();\n while i < messages_len {\n let msg = messages.get(i);\n let tx_hash = if msg.tx_hash.is_some() {\n msg.tx_hash.unwrap()\n } else {\n 0\n };\n let inbox: CapsuleArray =\n CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, msg.recipient);\n inbox.push(\n PendingOffchainMsg {\n ciphertext: msg.ciphertext,\n recipient: msg.recipient,\n tx_hash,\n anchor_block_timestamp: msg.anchor_block_timestamp,\n },\n );\n scopes.push(msg.recipient);\n i += 1;\n }\n\n set_contract_sync_cache_invalid(contract_address, scopes);\n}\n\n/// Returns offchain-delivered messages to process during sync.\n///\n/// Messages remain in the inbox and are reprocessed on each sync until their originating transaction is no longer at\n/// risk of being dropped by a reorg.\npub unconstrained fn sync_inbox(\n contract_address: AztecAddress,\n scope: AztecAddress,\n) -> EphemeralArray {\n let inbox: CapsuleArray = CapsuleArray::at(contract_address, OFFCHAIN_INBOX_SLOT, scope);\n let context_resolution_requests: EphemeralArray = EphemeralArray::at(OFFCHAIN_CONTEXT_REQUESTS_SLOT).clear();\n let ready_to_process: EphemeralArray =\n EphemeralArray::at(OFFCHAIN_READY_MESSAGES_SLOT).clear();\n\n // Build a request list aligned with the inbox indices.\n let mut i = 0;\n let inbox_len = inbox.len();\n while i < inbox_len {\n let msg = inbox.get(i);\n context_resolution_requests.push(msg.tx_hash);\n i += 1;\n }\n\n // Ask PXE to resolve contexts for all requested tx hashes. The oracle returns responses in a new\n // ephemeral array.\n let resolved_contexts =\n crate::oracle::message_processing::get_message_contexts_by_tx_hash(context_resolution_requests);\n\n assert_eq(resolved_contexts.len(), inbox_len);\n\n let now = UtilityContext::new().timestamp();\n\n let mut j = inbox_len;\n while j > 0 {\n // This loop decides what to do with each message in the offchain message inbox. We need to handle 3\n // different scenarios for each message.\n //\n // 1. The TX that emitted this message is still not known to PXE: in this case we can't yet process this\n // message, as any notes or events discovered will fail to be validated. So we leave the message in the inbox,\n // awaiting for future syncs to detect that the TX became available.\n //\n // 2. The message is not associated to a TX to begin with. The current version of offchain message processing\n // does not support this case, but in the future it will. Right now, a message without an associated TX will\n // sit in the inbox until it expires.\n //\n // 3. The TX that emitted this message has been found by PXE. That gives us all the information needed to\n // process the message. We add the message to the `ready_to_process` EphemeralArray so that the `sync_state`\n // loop\n // processes it.\n //\n // In all cases, if the message has expired (i.e. `now > anchor_block_timestamp + MAX_MSG_TTL`), we remove it\n // from the inbox.\n //\n // Note: the loop runs backwards because it might call `inbox.remove(j)` to purge expired messages and we also\n // need to align it with `resolved_contexts.get(j)`. Going from last to first simplifies the algorithm as\n // not yet visited element indexes remain stable.\n j -= 1;\n let maybe_ctx = resolved_contexts.get(j);\n let msg = inbox.get(j);\n\n // Compute the message's effective expiration timestamp to determine if we can purge it from the inbox.\n let effective_expiration = msg.anchor_block_timestamp + MAX_MSG_TTL;\n\n // Message expired. We remove it from the inbox.\n if now > effective_expiration {\n inbox.remove(j);\n }\n\n // Scenario 1: associated TX not yet available. We keep the message in the inbox, as it might become\n // processable as new blocks get mined.\n // Scenario 2: no TX associated to message. The message will sit in the inbox until it expires.\n if maybe_ctx.is_none() {\n continue;\n }\n\n // Scenario 3: Message is ready to process, add to result array. Note we still keep it in the inbox unless we\n // consider it has expired: this is because we need to account for reorgs. If reorg occurs after we processed\n // a message, the effects of processing the message get rewind. However, the associated TX can be included in\n // a subsequent block. Should that happen, the message must be re-processed to ensure consistency.\n let message_context = maybe_ctx.unwrap();\n ready_to_process.push(OffchainMessageWithContext { message_ciphertext: msg.ciphertext, message_context });\n }\n\n ready_to_process\n}\n\nmod test {\n use crate::{\n capsules::CapsuleArray, oracle::random::random, protocol::address::AztecAddress,\n test::helpers::test_environment::TestEnvironment,\n };\n use super::{\n MAX_MSG_TTL, MAX_OFFCHAIN_MESSAGES_PER_RECEIVE_CALL, OFFCHAIN_INBOX_SLOT, OffchainMessage, PendingOffchainMsg,\n receive, sync_inbox,\n };\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n /// Creates an `OffchainMessage` with dummy ciphertext and the given scope as recipient.\n fn make_msg(recipient: AztecAddress, tx_hash: Option, anchor_block_timestamp: u64) -> OffchainMessage {\n OffchainMessage { ciphertext: BoundedVec::new(), recipient, tx_hash, anchor_block_timestamp }\n }\n\n /// Advances the TXE block timestamp by `offset` seconds and returns the resulting timestamp.\n unconstrained fn advance_by(env: TestEnvironment, offset: u64) -> u64 {\n env.advance_next_block_timestamp_by(offset);\n env.mine_block();\n env.last_block_timestamp()\n }\n\n #[test]\n unconstrained fn empty_inbox_returns_empty_result() {\n let (env, scope) = setup();\n env.utility_context(|context| {\n let result = sync_inbox(context.this_address(), scope);\n let inbox: CapsuleArray =\n CapsuleArray::at(context.this_address(), OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0);\n assert_eq(inbox.len(), 0);\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn tx_bound_msg_not_expired_before_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance, but not past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn tx_less_msg_expires_after_max_msg_ttl() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::none(), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n // Advance past anchor_ts + MAX_MSG_TTL.\n let _now = advance_by(env, MAX_MSG_TTL + 1);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // context is None, not ready\n assert_eq(inbox.len(), 0); // expired, removed\n });\n }\n\n #[test]\n unconstrained fn unresolved_tx_stays_in_inbox() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(random()), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // not resolved, not ready\n assert_eq(inbox.len(), 1); // not expired, stays\n });\n }\n\n #[test]\n unconstrained fn multiple_messages_mixed_expiration() {\n let (env, scope) = setup();\n let anchor_ts = advance_by(env, 10);\n\n let survivor_tx_hash = random();\n\n env.utility_context(|context| {\n let address = context.this_address();\n let mut msgs: BoundedVec = BoundedVec::new();\n // Message 0: tx-bound, anchor_ts in the past so it expires at\n // anchor_ts + MAX_MSG_TTL. We set anchor to 0 so it expires quickly.\n msgs.push(make_msg(scope, Option::some(random()), 0));\n // Message 1: tx-bound, anchor_ts is recent so it survives.\n msgs.push(make_msg(scope, Option::some(survivor_tx_hash), anchor_ts));\n // Message 2: tx-less, anchor_ts=0 so it also expires.\n msgs.push(make_msg(scope, Option::none(), 0));\n receive(address, msgs);\n });\n\n // Advance past MAX_MSG_TTL for anchor_ts=0, but not for anchor_ts=anchor_ts.\n let _now = advance_by(env, MAX_MSG_TTL);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n assert_eq(result.len(), 0); // all contexts are None\n // Message 0 expired (anchor=0), message 1 survived (anchor=anchor_ts),\n // Message 2 expired (anchor=0).\n assert_eq(inbox.len(), 1);\n assert_eq(inbox.get(0).tx_hash, survivor_tx_hash);\n });\n }\n\n // -- Resolved context (ready to process) ------------------------------\n\n #[test]\n unconstrained fn resolved_msg_is_ready_to_process() {\n let (env, scope) = setup();\n // TestEnvironment::new() deploys protocol contracts, creating blocks with tx effects.\n // In TXE, tx hashes equal Fr(blockNumber), so Fr(1) is the tx effect from block 1.\n // We use this as a \"known resolvable\" tx hash.\n let known_tx_hash: Field = 1;\n let anchor_ts = advance_by(env, 10);\n\n env.utility_context(|context| {\n let mut msgs: BoundedVec = BoundedVec::new();\n msgs.push(make_msg(scope, Option::some(known_tx_hash), anchor_ts));\n receive(context.this_address(), msgs);\n });\n\n let _now = advance_by(env, 100);\n\n env.utility_context(|context| {\n let address = context.this_address();\n let result = sync_inbox(address, scope);\n let inbox: CapsuleArray = CapsuleArray::at(address, OFFCHAIN_INBOX_SLOT, scope);\n\n // The message should be ready to process since its tx context was resolved.\n assert_eq(result.len(), 1);\n\n let ctx = result.get(0).message_context;\n assert_eq(ctx.tx_hash, known_tx_hash);\n assert(ctx.first_nullifier_in_tx != 0, \"resolved context must have a first nullifier\");\n\n // Message stays in inbox (not expired) for potential reorg reprocessing.\n assert_eq(inbox.len(), 1);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/messages/processing/offchain.nr","function_locations":[{"start":5298,"name":"receive"},{"start":6741,"name":"sync_inbox"},{"start":11111,"name":"test::setup"},{"start":11441,"name":"test::make_msg"},{"start":11724,"name":"test::advance_by"},{"start":11915,"name":"test::empty_inbox_returns_empty_result"},{"start":12378,"name":"test::tx_bound_msg_expires_after_max_msg_ttl"},{"start":13343,"name":"test::tx_bound_msg_not_expired_before_max_msg_ttl"},{"start":14301,"name":"test::tx_less_msg_expires_after_max_msg_ttl"},{"start":15243,"name":"test::unresolved_tx_stays_in_inbox"},{"start":16137,"name":"test::multiple_messages_mixed_expiration"},{"start":17876,"name":"test::resolved_msg_is_ready_to_process"}]},"171":{"source":"#[oracle(aztec_utl_decryptAes128)]\nunconstrained fn aes128_decrypt_oracle(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {}\n\n/// Attempts to decrypt a ciphertext using AES128.\n///\n/// Returns `Option::some(plaintext)` on success, or `Option::none()` if decryption fails (e.g. due to malformed\n/// ciphertext or invalid PKCS#7 padding). Note that decryption with the wrong key will almost always return `None`\n/// because the decrypted garbage data will have invalid PKCS#7 padding.\n///\n/// Note that we accept ciphertext as a BoundedVec, not as an array. This is because this function is typically used\n/// when processing logs and at that point we don't have comptime information about the length of the ciphertext as\n/// the log is not specific to any individual note.\n// TODO(F-498): review naming consistency\npub unconstrained fn try_aes128_decrypt(\n ciphertext: BoundedVec,\n iv: [u8; 16],\n sym_key: [u8; 16],\n) -> Option> {\n aes128_decrypt_oracle(ciphertext, iv, sym_key)\n}\n\nmod test {\n use crate::{\n keys::ecdh_shared_secret::compute_app_siloed_shared_secret,\n messages::encryption::aes128::derive_aes_symmetric_key_and_iv_from_shared_secret,\n utils::{array::subarray::subarray, point::point_from_x_coord},\n };\n use crate::protocol::address::AztecAddress;\n use crate::test::helpers::test_environment::TestEnvironment;\n use super::try_aes128_decrypt;\n use std::aes128::aes128_encrypt;\n\n global CONTRACT_ADDRESS: AztecAddress = AztecAddress { inner: 42 };\n global TEST_PLAINTEXT_LENGTH: u32 = 10;\n global TEST_CIPHERTEXT_LENGTH: u32 = 16;\n global TEST_PADDING_LENGTH: u32 = TEST_CIPHERTEXT_LENGTH - TEST_PLAINTEXT_LENGTH;\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n\n let received_plaintext = try_aes128_decrypt(ciphertext_bvec, iv, sym_key).unwrap();\n assert_eq(received_plaintext.len(), TEST_PLAINTEXT_LENGTH);\n assert_eq(received_plaintext.max_len(), TEST_CIPHERTEXT_LENGTH);\n assert_eq(subarray::<_, _, TEST_PLAINTEXT_LENGTH>(received_plaintext.storage(), 0), plaintext);\n assert_eq(\n subarray::<_, _, TEST_PADDING_LENGTH>(received_plaintext.storage(), TEST_PLAINTEXT_LENGTH),\n [0 as u8; TEST_PADDING_LENGTH],\n );\n })\n }\n\n #[test]\n unconstrained fn aes_encrypt_then_decrypt_with_bad_sym_key_is_caught() {\n let env = TestEnvironment::new();\n\n env.utility_context(|_| {\n // Decrypting with the wrong key results in garbage data with invalid PKCS#7 padding,\n // so the oracle returns None.\n let shared_secret_point = point_from_x_coord(1).unwrap();\n let s_app = compute_app_siloed_shared_secret(shared_secret_point, CONTRACT_ADDRESS);\n\n let (sym_key, iv) = derive_aes_symmetric_key_and_iv_from_shared_secret::<1>(s_app)[0];\n\n let plaintext: [u8; TEST_PLAINTEXT_LENGTH] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n let ciphertext: [u8; TEST_CIPHERTEXT_LENGTH] = aes128_encrypt(plaintext, iv, sym_key);\n\n let mut bad_sym_key = sym_key;\n bad_sym_key[0] = 0;\n\n let ciphertext_bvec = BoundedVec::::from_array(ciphertext);\n // Decryption with wrong key returns None because the garbage output has invalid PKCS#7 padding.\n let result = try_aes128_decrypt(ciphertext_bvec, iv, bad_sym_key);\n assert(result.is_none(), \"decryption with bad key should return None\");\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/aes128_decrypt.nr","function_locations":[{"start":194,"name":"aes128_decrypt_oracle"},{"start":1046,"name":"try_aes128_decrypt"},{"start":1860,"name":"test::aes_encrypt_then_decrypt"},{"start":3150,"name":"test::aes_encrypt_then_decrypt_with_bad_sym_key_is_caught"}]},"173":{"source":"//! AVM oracles.\n//!\n//! There are only available during public execution. Calling any of them from a private or utility function will\n//! result in runtime errors.\n\nuse crate::protocol::address::{AztecAddress, EthAddress};\n\npub unconstrained fn address() -> AztecAddress {\n address_opcode()\n}\npub unconstrained fn sender() -> AztecAddress {\n sender_opcode()\n}\npub unconstrained fn transaction_fee() -> Field {\n transaction_fee_opcode()\n}\npub unconstrained fn chain_id() -> Field {\n chain_id_opcode()\n}\npub unconstrained fn version() -> Field {\n version_opcode()\n}\npub unconstrained fn block_number() -> u32 {\n block_number_opcode()\n}\npub unconstrained fn timestamp() -> u64 {\n timestamp_opcode()\n}\npub unconstrained fn min_fee_per_l2_gas() -> u128 {\n min_fee_per_l2_gas_opcode()\n}\npub unconstrained fn min_fee_per_da_gas() -> u128 {\n min_fee_per_da_gas_opcode()\n}\npub unconstrained fn l2_gas_left() -> u32 {\n l2_gas_left_opcode()\n}\npub unconstrained fn da_gas_left() -> u32 {\n da_gas_left_opcode()\n}\npub unconstrained fn is_static_call() -> bool {\n is_static_call_opcode()\n}\npub unconstrained fn note_hash_exists(note_hash: Field, leaf_index: u64) -> bool {\n note_hash_exists_opcode(note_hash, leaf_index)\n}\npub unconstrained fn emit_note_hash(note_hash: Field) {\n emit_note_hash_opcode(note_hash)\n}\npub unconstrained fn nullifier_exists(siloed_nullifier: Field) -> bool {\n nullifier_exists_opcode(siloed_nullifier)\n}\npub unconstrained fn emit_nullifier(nullifier: Field) {\n emit_nullifier_opcode(nullifier)\n}\npub unconstrained fn emit_public_log(message: [Field]) {\n emit_public_log_opcode(message)\n}\npub unconstrained fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: u64) -> bool {\n l1_to_l2_msg_exists_opcode(msg_hash, msg_leaf_index)\n}\npub unconstrained fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {\n send_l2_to_l1_msg_opcode(recipient, content)\n}\n\npub unconstrained fn call(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn call_static(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_static_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn calldata_copy(cdoffset: u32, copy_size: u32) -> [Field; N] {\n calldata_copy_opcode(cdoffset, copy_size)\n}\n\n/// `success_copy` is placed immediately after the CALL opcode to get the success value\npub unconstrained fn success_copy() -> bool {\n success_copy_opcode()\n}\n\npub unconstrained fn returndata_size() -> u32 {\n returndata_size_opcode()\n}\n\npub unconstrained fn returndata_copy(rdoffset: u32, copy_size: u32) -> [Field] {\n returndata_copy_opcode(rdoffset, copy_size)\n}\n\n/// The additional prefix is to avoid clashing with the `return` Noir keyword.\npub unconstrained fn avm_return(returndata: [Field]) {\n return_opcode(returndata)\n}\n\n/// This opcode reverts using the exact data given. In general it should only be used to do rethrows, where the revert\n/// data is the same as the original revert data. For normal reverts, use Noir's `assert` which, on top of reverting,\n/// will also add an error selector to the revert data.\npub unconstrained fn revert(revertdata: [Field]) {\n revert_opcode(revertdata)\n}\n\npub unconstrained fn storage_read(storage_slot: Field, contract_address: Field) -> Field {\n storage_read_opcode(storage_slot, contract_address)\n}\n\npub unconstrained fn storage_write(storage_slot: Field, value: Field) {\n storage_write_opcode(storage_slot, value);\n}\n\n#[oracle(aztec_avm_address)]\nunconstrained fn address_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_sender)]\nunconstrained fn sender_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_transactionFee)]\nunconstrained fn transaction_fee_opcode() -> Field {}\n\n#[oracle(aztec_avm_chainId)]\nunconstrained fn chain_id_opcode() -> Field {}\n\n#[oracle(aztec_avm_version)]\nunconstrained fn version_opcode() -> Field {}\n\n#[oracle(aztec_avm_blockNumber)]\nunconstrained fn block_number_opcode() -> u32 {}\n\n#[oracle(aztec_avm_timestamp)]\nunconstrained fn timestamp_opcode() -> u64 {}\n\n#[oracle(aztec_avm_minFeePerL2Gas)]\nunconstrained fn min_fee_per_l2_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_minFeePerDaGas)]\nunconstrained fn min_fee_per_da_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_l2GasLeft)]\nunconstrained fn l2_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_daGasLeft)]\nunconstrained fn da_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_isStaticCall)]\nunconstrained fn is_static_call_opcode() -> bool {}\n\n#[oracle(aztec_avm_noteHashExists)]\nunconstrained fn note_hash_exists_opcode(note_hash: Field, leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_emitNoteHash)]\nunconstrained fn emit_note_hash_opcode(note_hash: Field) {}\n\n#[oracle(aztec_avm_nullifierExists)]\nunconstrained fn nullifier_exists_opcode(siloed_nullifier: Field) -> bool {}\n\n#[oracle(aztec_avm_emitNullifier)]\nunconstrained fn emit_nullifier_opcode(nullifier: Field) {}\n\n#[oracle(aztec_avm_emitPublicLog)]\nunconstrained fn emit_public_log_opcode(message: [Field]) {}\n\n#[oracle(aztec_avm_l1ToL2MsgExists)]\nunconstrained fn l1_to_l2_msg_exists_opcode(msg_hash: Field, msg_leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_sendL2ToL1Msg)]\nunconstrained fn send_l2_to_l1_msg_opcode(recipient: EthAddress, content: Field) {}\n\n#[oracle(aztec_avm_calldataCopy)]\nunconstrained fn calldata_copy_opcode(cdoffset: u32, copy_size: u32) -> [Field; N] {}\n\n#[oracle(aztec_avm_returndataSize)]\nunconstrained fn returndata_size_opcode() -> u32 {}\n\n#[oracle(aztec_avm_returndataCopy)]\nunconstrained fn returndata_copy_opcode(rdoffset: u32, copy_size: u32) -> [Field] {}\n\n#[oracle(aztec_avm_return)]\nunconstrained fn return_opcode(returndata: [Field]) {}\n\n#[oracle(aztec_avm_revert)]\nunconstrained fn revert_opcode(revertdata: [Field]) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_call)]\nunconstrained fn call_opcode(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_staticCall)]\nunconstrained fn call_static_opcode(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n#[oracle(aztec_avm_successCopy)]\nunconstrained fn success_copy_opcode() -> bool {}\n\n#[oracle(aztec_avm_storageRead)]\nunconstrained fn storage_read_opcode(storage_slot: Field, contract_address: Field) -> Field {}\n\n#[oracle(aztec_avm_storageWrite)]\nunconstrained fn storage_write_opcode(storage_slot: Field, value: Field) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/avm.nr","function_locations":[{"start":272,"name":"address"},{"start":343,"name":"sender"},{"start":415,"name":"transaction_fee"},{"start":489,"name":"chain_id"},{"start":555,"name":"version"},{"start":623,"name":"block_number"},{"start":693,"name":"timestamp"},{"start":770,"name":"min_fee_per_l2_gas"},{"start":856,"name":"min_fee_per_da_gas"},{"start":934,"name":"l2_gas_left"},{"start":1005,"name":"da_gas_left"},{"start":1080,"name":"is_static_call"},{"start":1193,"name":"note_hash_exists"},{"start":1302,"name":"emit_note_hash"},{"start":1414,"name":"nullifier_exists"},{"start":1518,"name":"emit_nullifier"},{"start":1614,"name":"emit_public_log"},{"start":1741,"name":"l1_to_l2_msg_exists"},{"start":1880,"name":"send_l2_to_l1_msg"},{"start":2080,"name":"call"},{"start":2310,"name":"call_static"},{"start":2486,"name":"calldata_copy"},{"start":2669,"name":"success_copy"},{"start":2746,"name":"returndata_size"},{"start":2859,"name":"returndata_copy"},{"start":3044,"name":"avm_return"},{"start":3421,"name":"revert"},{"start":3545,"name":"storage_read"},{"start":3676,"name":"storage_write"},{"start":3807,"name":"address_opcode"},{"start":3888,"name":"sender_opcode"},{"start":3979,"name":"transaction_fee_opcode"},{"start":4056,"name":"chain_id_opcode"},{"start":4132,"name":"version_opcode"},{"start":4215,"name":"block_number_opcode"},{"start":4293,"name":"timestamp_opcode"},{"start":4386,"name":"min_fee_per_l2_gas_opcode"},{"start":4479,"name":"min_fee_per_da_gas_opcode"},{"start":4559,"name":"l2_gas_left_opcode"},{"start":4639,"name":"da_gas_left_opcode"},{"start":4726,"name":"is_static_call_opcode"},{"start":4850,"name":"note_hash_exists_opcode"},{"start":4945,"name":"emit_note_hash_opcode"},{"start":5060,"name":"nullifier_exists_opcode"},{"start":5156,"name":"emit_nullifier_opcode"},{"start":5253,"name":"emit_public_log_opcode"},{"start":5384,"name":"l1_to_l2_msg_exists_opcode"},{"start":5504,"name":"send_l2_to_l1_msg_opcode"},{"start":5637,"name":"calldata_copy_opcode"},{"start":5726,"name":"returndata_size_opcode"},{"start":5848,"name":"returndata_copy_opcode"},{"start":5932,"name":"return_opcode"},{"start":6016,"name":"revert_opcode"},{"start":6463,"name":"call_opcode"},{"start":6923,"name":"call_static_opcode"},{"start":7007,"name":"success_copy_opcode"},{"start":7136,"name":"storage_read_opcode"},{"start":7247,"name":"storage_write_opcode"}]},"176":{"source":"use crate::protocol::{address::AztecAddress, traits::{Deserialize, Serialize}};\n\n/// Stores arbitrary information in a per-contract non-volatile database, which can later be retrieved with `load`. If\n/// data was already stored at this slot, it is overwritten.\n// TODO(F-498): review naming consistency\npub unconstrained fn store(contract_address: AztecAddress, slot: Field, value: T, scope: AztecAddress)\nwhere\n T: Serialize,\n{\n let serialized = value.serialize();\n set_capsule_oracle(contract_address, slot, serialized, scope);\n}\n\n/// Returns data previously stored via `storeCapsule` in the per-contract non-volatile database. Returns\n/// Option::none() if nothing was stored at the given slot.\n// TODO(F-498): review naming consistency\npub unconstrained fn load(contract_address: AztecAddress, slot: Field, scope: AztecAddress) -> Option\nwhere\n T: Deserialize,\n{\n let serialized_option = get_capsule_oracle(contract_address, slot, ::N, scope);\n serialized_option.map(|arr| Deserialize::deserialize(arr))\n}\n\n/// Deletes data in the per-contract non-volatile database. Does nothing if no data was present.\npub unconstrained fn delete(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {\n delete_oracle(contract_address, slot, scope);\n}\n\n/// Copies a number of contiguous entries in the per-contract non-volatile database. This allows for efficient data\n/// structures by avoiding repeated calls to `loadCapsule` and `storeCapsule`. Supports overlapping source and\n/// destination regions (which will result in the overlapped source values being overwritten). All copied slots must\n/// exist in the database (i.e. have been stored and not deleted)\npub unconstrained fn copy(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {\n copy_oracle(contract_address, src_slot, dst_slot, num_entries, scope);\n}\n\n#[oracle(aztec_utl_setCapsule)]\nunconstrained fn set_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n values: [Field; N],\n scope: AztecAddress,\n) {}\n\n/// We need to pass in `array_len` (the value of N) as a parameter to tell the oracle how many fields the response must\n/// have.\n///\n/// Note that the oracle returns an Option<[Field; N]> because we cannot return an Option directly. That would\n/// require for the oracle resolver to know the shape of T (e.g. if T were a struct of 3 u32 values then the expected\n/// response shape would be 3 single items, whereas it were a struct containing `u32, [Field;10], u32` then the\n/// expected shape would be single, array, single.). Instead, we return the serialization and deserialize in Noir.\n#[oracle(aztec_utl_getCapsule)]\nunconstrained fn get_capsule_oracle(\n contract_address: AztecAddress,\n slot: Field,\n array_len: u32,\n scope: AztecAddress,\n) -> Option<[Field; N]> {}\n\n#[oracle(aztec_utl_deleteCapsule)]\nunconstrained fn delete_oracle(contract_address: AztecAddress, slot: Field, scope: AztecAddress) {}\n\n#[oracle(aztec_utl_copyCapsule)]\nunconstrained fn copy_oracle(\n contract_address: AztecAddress,\n src_slot: Field,\n dst_slot: Field,\n num_entries: u32,\n scope: AztecAddress,\n) {}\n\nmod test {\n // These tests are sort of redundant since we already test the oracle implementation directly in TypeScript, but\n // they are cheap regardless and help ensure both that the TXE implementation works accordingly and that the Noir\n // oracles are hooked up correctly.\n\n use crate::{\n oracle::capsules::{copy, delete, load, store},\n test::{helpers::test_environment::TestEnvironment, mocks::MockStruct},\n };\n use crate::protocol::{address::AztecAddress, traits::{FromField, ToField}};\n\n global SLOT: Field = 1;\n\n unconstrained fn setup() -> (TestEnvironment, AztecAddress) {\n let mut env = TestEnvironment::new();\n let scope = env.create_light_account();\n (env, scope)\n }\n\n #[test]\n unconstrained fn stores_and_loads() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), value);\n });\n }\n\n #[test]\n unconstrained fn store_overwrites() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n\n let new_value = MockStruct::new(7, 8);\n store(contract_address, SLOT, new_value, scope);\n\n assert_eq(load(contract_address, SLOT, scope).unwrap(), new_value);\n });\n }\n\n #[test]\n unconstrained fn loads_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_stored_value() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let value = MockStruct::new(5, 6);\n store(contract_address, SLOT, value, scope);\n delete(contract_address, SLOT, scope);\n\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn deletes_empty_slot() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n delete(contract_address, SLOT, scope);\n let loaded_value: Option = load(contract_address, SLOT, scope);\n assert_eq(loaded_value, Option::none());\n });\n }\n\n #[test]\n unconstrained fn copies_non_overlapping_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 5;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 10;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_src_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 1;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 2;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[1] and src[2] should have been overwritten since they are also dst[0] and dst[1]\n assert_eq(load(contract_address, src, scope).unwrap(), values[0]); // src[0] (unchanged)\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[0]); // dst[0]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[1]); // dst[1]\n });\n }\n\n #[test]\n unconstrained fn copies_overlapping_values_with_dst_ahead() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n let src = 2;\n\n let values = [MockStruct::new(5, 6), MockStruct::new(7, 8), MockStruct::new(9, 10)];\n store(contract_address, src, values[0], scope);\n store(contract_address, src + 1, values[1], scope);\n store(contract_address, src + 2, values[2], scope);\n\n let dst = 1;\n copy(contract_address, src, dst, 3, scope);\n\n assert_eq(load(contract_address, dst, scope).unwrap(), values[0]);\n assert_eq(load(contract_address, dst + 1, scope).unwrap(), values[1]);\n assert_eq(load(contract_address, dst + 2, scope).unwrap(), values[2]);\n\n // src[0] and src[1] should have been overwritten since they are also dst[1] and dst[2]\n assert_eq(load(contract_address, src, scope).unwrap(), values[1]); // dst[1]\n assert_eq(load(contract_address, src + 1, scope).unwrap(), values[2]); // dst[2]\n assert_eq(load(contract_address, src + 2, scope).unwrap(), values[2]); // src[2] (unchanged)\n });\n }\n\n #[test(should_fail_with = \"copy empty slot\")]\n unconstrained fn cannot_copy_empty_values() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n\n copy(contract_address, SLOT, SLOT, 1, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_store_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let value = MockStruct::new(5, 6);\n store(other_contract_address, SLOT, value, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_load_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n let _: Option = load(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_delete_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n delete(other_contract_address, SLOT, scope);\n });\n }\n\n #[test(should_fail_with = \"not allowed to access\")]\n unconstrained fn cannot_copy_other_contract() {\n let (env, scope) = setup();\n env.private_context(|context| {\n let contract_address = context.this_address();\n let other_contract_address = AztecAddress::from_field(contract_address.to_field() + 1);\n\n copy(other_contract_address, SLOT, SLOT, 0, scope);\n });\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/capsules.nr","function_locations":[{"start":433,"name":"store"},{"start":886,"name":"load"},{"start":1247,"name":"delete"},{"start":1866,"name":"copy"},{"start":2131,"name":"set_capsule_oracle"},{"start":2931,"name":"get_capsule_oracle"},{"start":3067,"name":"delete_oracle"},{"start":3261,"name":"copy_oracle"},{"start":3884,"name":"test::setup"},{"start":4060,"name":"test::stores_and_loads"},{"start":4450,"name":"test::store_overwrites"},{"start":4957,"name":"test::loads_empty_slot"},{"start":5311,"name":"test::deletes_stored_value"},{"start":5819,"name":"test::deletes_empty_slot"},{"start":6233,"name":"test::copies_non_overlapping_values"},{"start":7106,"name":"test::copies_overlapping_values_with_src_ahead"},{"start":8366,"name":"test::copies_overlapping_values_with_dst_ahead"},{"start":9648,"name":"test::cannot_copy_empty_values"},{"start":9970,"name":"test::cannot_store_other_contract"},{"start":10443,"name":"test::cannot_load_other_contract"},{"start":10891,"name":"test::cannot_delete_other_contract"},{"start":11311,"name":"test::cannot_copy_other_contract"}]},"177":{"source":"use crate::protocol::address::AztecAddress;\n\n#[oracle(aztec_utl_setContractSyncCacheInvalid)]\nunconstrained fn set_contract_sync_cache_invalid_oracle(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {}\n\n/// Forces the PXE to re-sync the given contract for a set of scopes on the next query.\n///\n/// Call this after writing data (e.g. offchain messages) that the contract's `sync_state` function needs to discover.\n/// Without invalidation, the sync cache would skip re-running `sync_state` until the next block.\npub unconstrained fn set_contract_sync_cache_invalid(\n contract_address: AztecAddress,\n scopes: BoundedVec,\n) {\n set_contract_sync_cache_invalid_oracle(contract_address, scopes);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/contract_sync.nr","function_locations":[{"start":242,"name":"set_contract_sync_cache_invalid_oracle"},{"start":700,"name":"set_contract_sync_cache_invalid"}]},"179":{"source":"use crate::context::UtilityContext;\n\n#[oracle(aztec_utl_getUtilityContext)]\nunconstrained fn get_utility_context_oracle() -> UtilityContext {}\n\n/// Returns a utility context built from the global variables of anchor block and the contract address of the function\n/// being executed.\npub unconstrained fn get_utility_context() -> UtilityContext {\n get_utility_context_oracle()\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/execution.nr","function_locations":[{"start":140,"name":"get_utility_context_oracle"},{"start":344,"name":"get_utility_context"}]},"189":{"source":"use crate::ephemeral::EphemeralArray;\nuse crate::messages::processing::{\n log_retrieval_request::LogRetrievalRequest, log_retrieval_response::LogRetrievalResponse, MessageContext,\n pending_tagged_log::PendingTaggedLog,\n};\nuse crate::protocol::address::AztecAddress;\n\n/// Finds new private logs that may have been sent to all registered accounts in PXE in the current contract and\n/// returns them in an ephemeral array with an oracle-allocated base slot.\npub(crate) unconstrained fn get_pending_tagged_logs(scope: AztecAddress) -> EphemeralArray {\n let result_slot = get_pending_tagged_logs_oracle(scope);\n EphemeralArray::at(result_slot)\n}\n\n#[oracle(aztec_utl_getPendingTaggedLogs_v2)]\nunconstrained fn get_pending_tagged_logs_oracle(scope: AztecAddress) -> Field {}\n\n/// Validates note/event requests stored in ephemeral arrays.\npub(crate) unconstrained fn validate_and_store_enqueued_notes_and_events(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {\n validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot,\n event_validation_requests_array_slot,\n max_note_packed_len,\n max_event_serialized_len,\n scope,\n );\n}\n\n#[oracle(aztec_utl_validateAndStoreEnqueuedNotesAndEvents_v2)]\nunconstrained fn validate_and_store_enqueued_notes_and_events_oracle(\n note_validation_requests_array_slot: Field,\n event_validation_requests_array_slot: Field,\n max_note_packed_len: Field,\n max_event_serialized_len: Field,\n scope: AztecAddress,\n) {}\n\n/// Fetches logs by tag from an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_logs_by_tag(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_logs_by_tag_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getLogsByTag_v2)]\nunconstrained fn get_logs_by_tag_v2_oracle(request_array_slot: Field) -> Field {}\n\n/// Resolves message contexts for tx hashes in an ephemeral request array and returns a response ephemeral array.\npub(crate) unconstrained fn get_message_contexts_by_tx_hash(\n requests: EphemeralArray,\n) -> EphemeralArray> {\n let response_slot = get_message_contexts_by_tx_hash_v2_oracle(requests.slot);\n EphemeralArray::at(response_slot)\n}\n\n#[oracle(aztec_utl_getMessageContextsByTxHash_v2)]\nunconstrained fn get_message_contexts_by_tx_hash_v2_oracle(request_array_slot: Field) -> Field {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/message_processing.nr","function_locations":[{"start":570,"name":"get_pending_tagged_logs"},{"start":795,"name":"get_pending_tagged_logs_oracle"},{"start":1128,"name":"validate_and_store_enqueued_notes_and_events"},{"start":1692,"name":"validate_and_store_enqueued_notes_and_events_oracle"},{"start":1938,"name":"get_logs_by_tag"},{"start":2163,"name":"get_logs_by_tag_v2_oracle"},{"start":2423,"name":"get_message_contexts_by_tx_hash"},{"start":2694,"name":"get_message_contexts_by_tx_hash_v2_oracle"}]},"196":{"source":"use crate::protocol::address::aztec_address::AztecAddress;\nuse crate::protocol::point::Point;\n\n#[oracle(aztec_utl_getSharedSecret)]\nunconstrained fn get_shared_secret_oracle(\n address: AztecAddress,\n ephPk: Point,\n contract_address: AztecAddress,\n) -> Field {}\n\n/// Returns an app-siloed shared secret between `address` and someone who knows the secret key behind an ephemeral\n/// public key `ephPk`.\n///\n/// The returned value is a Field `s_app`, computed as:\n///\n/// ```text\n/// S = address_secret * ephPk (raw ECDH point)\n/// s_app = h(DOM_SEP, S.x, S.y, contract) (app-siloed scalar)\n/// ```\n///\n/// where `contract` is the address of the calling contract. The oracle host validates this matches its execution\n/// context.\n///\n/// Without app-siloing, a malicious contract could call this oracle with public information (address, ephPk) and\n/// obtain the same raw secret as the legitimate contract, enabling cross-contract decryption. By including the\n/// contract address in the hash, each contract receives a different `s_app`, preventing this attack.\n///\n/// Callers derive indexed subkeys from `s_app` via\n/// [`derive_shared_secret_subkey`](crate::keys::ecdh_shared_secret::derive_shared_secret_subkey).\npub unconstrained fn get_shared_secret(address: AztecAddress, ephPk: Point, contract_address: AztecAddress) -> Field {\n get_shared_secret_oracle(address, ephPk, contract_address)\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr","function_locations":[{"start":267,"name":"get_shared_secret_oracle"},{"start":1354,"name":"get_shared_secret"}]},"245":{"source":"/// Appends the elements of the second `BoundedVec` to the end of the first one. The resulting `BoundedVec` can have\n/// any arbitrary maximum length, but it must be large enough to fit all of the elements of both the first and second\n/// vectors.\npub fn append(\n a: BoundedVec,\n b: BoundedVec,\n) -> BoundedVec {\n let mut dst = BoundedVec::new();\n\n dst.extend_from_bounded_vec(a);\n dst.extend_from_bounded_vec(b);\n\n dst\n}\n\nmod test {\n use super::append;\n\n #[test]\n unconstrained fn append_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::new();\n let b: BoundedVec<_, 14> = BoundedVec::new();\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 0);\n assert_eq(result.storage(), std::mem::zeroed());\n }\n\n #[test]\n unconstrained fn append_non_empty_vecs() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let result: BoundedVec = append(a, b);\n\n assert_eq(result.len(), 6);\n assert_eq(result.storage(), [1, 2, 3, 4, 5, 6, std::mem::zeroed(), std::mem::zeroed()]);\n }\n\n #[test(should_fail_with = \"out of bounds\")]\n unconstrained fn append_non_empty_vecs_insufficient_max_len() {\n let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]);\n let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]);\n\n let _: BoundedVec = append(a, b);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/append.nr","function_locations":[{"start":396,"name":"append"},{"start":608,"name":"test::append_empty_vecs"},{"start":933,"name":"test::append_non_empty_vecs"},{"start":1387,"name":"test::append_non_empty_vecs_insufficient_max_len"}]},"248":{"source":"/// Returns `DstLen` elements from a source array, starting at `offset`. `DstLen` must not be larger than the number of\n/// elements past `offset`.\n///\n/// Examples:\n/// ```\n/// let foo: [Field; 2] = subarray([1, 2, 3, 4, 5], 2);\n/// assert_eq(foo, [3, 4]);\n///\n/// let bar: [Field; 5] = subarray([1, 2, 3, 4, 5], 2); // fails - we can't return 5 elements since only 3 remain\n/// ```\npub fn subarray(src: [T; SrcLen], offset: u32) -> [T; DstLen] {\n assert(offset + DstLen <= SrcLen, \"DstLen too large for offset\");\n\n let mut dst: [T; DstLen] = std::mem::zeroed();\n for i in 0..DstLen {\n dst[i] = src[i + offset];\n }\n\n dst\n}\n\nmod test {\n use super::subarray;\n\n #[test]\n unconstrained fn subarray_into_empty() {\n // In all of these cases we're setting DstLen to be 0, so we always get back an empty array.\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 2), []);\n }\n\n #[test]\n unconstrained fn subarray_complete() {\n assert_eq(subarray::([], 0), []);\n assert_eq(subarray([1, 2, 3, 4, 5], 0), [1, 2, 3, 4, 5]);\n }\n\n #[test]\n unconstrained fn subarray_different_end_sizes() {\n // We implicitly select how many values to read in the size of the return array\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4, 5]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3]);\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [2]);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subarray_offset_too_large() {\n // With an offset of 1 we can only request up to 4 elements\n let _: [_; 5] = subarray([1, 2, 3, 4, 5], 1);\n }\n\n #[test(should_fail)]\n unconstrained fn subarray_bad_return_value() {\n assert_eq(subarray([1, 2, 3, 4, 5], 1), [3, 3, 4, 5]);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr","function_locations":[{"start":483,"name":"subarray"},{"start":776,"name":"test::subarray_into_empty"},{"start":1100,"name":"test::subarray_complete"},{"start":1294,"name":"test::subarray_different_end_sizes"},{"start":1736,"name":"test::subarray_offset_too_large"},{"start":1941,"name":"test::subarray_bad_return_value"}]},"249":{"source":"use crate::utils::array;\n\n/// Returns `DstMaxLen` elements from a source BoundedVec, starting at `offset`. `offset` must not be larger than the\n/// original length, and `DstLen` must not be larger than the total number of elements past `offset` (including the\n/// zeroed elements past `len()`).\n///\n/// Only elements at the beginning of the vector can be removed: it is not possible to also remove elements at the end\n/// of the vector by passing a value for `DstLen` that is smaller than `len() - offset`.\n///\n/// Examples:\n/// ```\n/// let foo = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n/// assert_eq(subbvec(foo, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n///\n/// let bar: BoundedVec<_, 1> = subbvec(foo, 2); // fails - we can't return just 1 element since 3 remain\n/// let baz: BoundedVec<_, 10> = subbvec(foo, 3); // fails - we can't return 10 elements since only 7 remain\n/// ```\npub fn subbvec(\n bvec: BoundedVec,\n offset: u32,\n) -> BoundedVec {\n // from_parts_unchecked does not verify that the elements past len are zeroed, but that is not an issue in our case\n // because we're constructing the new storage array as a subarray of the original one (which should have zeroed\n // storage past len), guaranteeing correctness. This is because `subarray` does not allow extending arrays past\n // their original length.\n BoundedVec::from_parts_unchecked(array::subarray(bvec.storage(), offset), bvec.len() - offset)\n}\n\nmod test {\n use super::subbvec;\n\n #[test]\n unconstrained fn subbvec_empty() {\n let bvec = BoundedVec::::from_array([]);\n assert_eq(subbvec(bvec, 0), bvec);\n }\n\n #[test]\n unconstrained fn subbvec_complete() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), bvec);\n\n let smaller_capacity = BoundedVec::<_, 5>::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 0), smaller_capacity);\n }\n\n #[test]\n unconstrained fn subbvec_partial() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 8>::from_array([3, 4, 5]));\n assert_eq(subbvec(bvec, 2), BoundedVec::<_, 3>::from_array([3, 4, 5]));\n }\n\n #[test]\n unconstrained fn subbvec_into_empty() {\n let bvec: BoundedVec<_, 10> = BoundedVec::from_array([1, 2, 3, 4, 5]);\n assert_eq(subbvec(bvec, 5), BoundedVec::<_, 5>::from_array([]));\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_offset_past_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n let _: BoundedVec<_, 1> = subbvec(bvec, 6);\n }\n\n #[test(should_fail)]\n unconstrained fn subbvec_insufficient_dst_len() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // We're not providing enough space to hold all of the items inside the original BoundedVec. subbvec can cause\n // for the capacity to reduce, but not the length (other than by len - offset).\n let _: BoundedVec<_, 1> = subbvec(bvec, 2);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_causes_enlarge() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // subbvec does not support capacity increases\n let _: BoundedVec<_, 11> = subbvec(bvec, 0);\n }\n\n #[test(should_fail_with = \"DstLen too large for offset\")]\n unconstrained fn subbvec_dst_len_too_large_for_offset() {\n let bvec = BoundedVec::<_, 10>::from_array([1, 2, 3, 4, 5]);\n\n // This effectively requests a capacity increase, since there'd be just one element plus the 5 empty slots,\n // which is less than 7.\n let _: BoundedVec<_, 7> = subbvec(bvec, 4);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr","function_locations":[{"start":1041,"name":"subbvec"},{"start":1612,"name":"test::subbvec_empty"},{"start":1775,"name":"test::subbvec_complete"},{"start":2083,"name":"test::subbvec_partial"},{"start":2376,"name":"test::subbvec_into_empty"},{"start":2609,"name":"test::subbvec_offset_past_len"},{"start":2816,"name":"test::subbvec_insufficient_dst_len"},{"start":3270,"name":"test::subbvec_dst_len_causes_enlarge"},{"start":3579,"name":"test::subbvec_dst_len_too_large_for_offset"}]},"252":{"source":"use std::static_assert;\n\n/// Encodes an array of bytes as fields.\n///\n/// Use\n/// [`decode_bytes_from_fields`](crate::utils::conversion::bytes_as_fields::decode_bytes_from_fields) to recover\n/// the original bytes.\n///\n/// The `bytes` array length must be a multiple of 31. If padding is added, it will need to be manually removed\n/// after decoding.\n///\n/// ## Encoding\n///\n/// Each 31-byte chunk is interpreted as a big-endian integer and stored in a `Field`. For input `[1, 10, 3, ..., 0]`\n/// (31 bytes), the resulting `Field` is `1 * 256^30 + 10 * 256^29 + 3 * 256^28 + ... + 0`.\npub fn encode_bytes_as_fields(bytes: [u8; N]) -> [Field; N / 31] {\n static_assert(N % 31 == 0, \"N must be a multiple of 31\");\n\n let mut fields = [0; N / 31];\n for i in 0..N / 31 {\n let mut field = 0;\n for j in 0..31 {\n field = field * 256 + bytes[i * 31 + j] as Field;\n }\n fields[i] = field;\n }\n\n fields\n}\n\n/// Decodes fields back into bytes.\n///\n/// Inverse of\n/// [`encode_bytes_as_fields`](crate::utils::conversion::bytes_as_fields::encode_bytes_as_fields).\n/// Each input `Field` must fit in 248 bits; `Field::to_be_bytes::<31>()` fails the proof otherwise.\npub fn decode_bytes_from_fields(fields: BoundedVec) -> BoundedVec {\n let mut bytes = BoundedVec::new();\n for i in 0..fields.len() {\n let chunk: [u8; 31] = fields.get(i).to_be_bytes();\n for j in 0..31 {\n bytes.push(chunk[j]);\n }\n }\n bytes\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_bytes_from_fields, encode_bytes_as_fields};\n\n #[test]\n unconstrained fn round_trips_bytes(input: [u8; 93]) {\n let fields = encode_bytes_as_fields(input);\n\n // In production the fields fly through the system and arrive as a BoundedVec on the other end.\n let fields_bvec = BoundedVec::<_, 6>::from_array(fields);\n let bytes_back = decode_bytes_from_fields(fields_bvec);\n\n assert_eq(bytes_back.len(), input.len());\n assert_eq(subarray(bytes_back.storage(), 0), input);\n }\n\n #[test(should_fail_with = \"N must be a multiple of 31\")]\n unconstrained fn encode_rejects_length_not_multiple_of_31() {\n let _fields = encode_bytes_as_fields([0; 32]);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 31 limbs\")]\n unconstrained fn decode_rejects_oversized_field() {\n // `Field::to_be_bytes::<31>()` fails the proof when a field has any bit above position 247 set.\n let oversized: Field = (1 as Field) * 2.pow_32(249);\n let input = BoundedVec::<_, 1>::from_array([oversized]);\n let _bytes = decode_bytes_from_fields(input);\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/bytes_as_fields.nr","function_locations":[{"start":662,"name":"encode_bytes_as_fields"},{"start":1313,"name":"decode_bytes_from_fields"},{"start":1719,"name":"tests::round_trips_bytes"},{"start":2252,"name":"tests::encode_rejects_length_not_multiple_of_31"},{"start":2454,"name":"tests::decode_rejects_oversized_field"}]},"253":{"source":"/// Encodes an array of fields as bytes.\n///\n/// Losslessly preserves any field value; use\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes) to\n/// recover the original fields.\n///\n/// ## Encoding\n///\n/// Each field is written as 32 big-endian bytes and the chunks are concatenated. The field array `[5, 42]` becomes:\n///\n/// ```text\n/// [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, // First field (32 bytes)\n/// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42] // Second field (32 bytes)\n/// ```\n///\n/// ## Privacy\n///\n/// The BN254 modulus is `< 2^254`, so every 32-byte chunk has its top bit at zero and the next bit biased. The output\n/// is therefore distinguishable from uniform random bytes; take this into account when feeding it into anything that\n/// assumes uniform randomness (e.g. ciphertexts meant to look random).\npub fn encode_fields_as_bytes(fields: [Field; N]) -> [u8; 32 * N] {\n let mut bytes = [0; 32 * N];\n for i in 0..N {\n let chunk: [u8; 32] = fields[i].to_be_bytes();\n for j in 0..32 {\n bytes[i * 32 + j] = chunk[j];\n }\n }\n bytes\n}\n\n/// Decodes bytes back into fields.\n///\n/// Panics if the input length is not a multiple of 32 or if any chunk exceeds the BN254 field modulus. See\n/// [`try_decode_fields_from_bytes`](crate::utils::conversion::fields_as_bytes::try_decode_fields_from_bytes)\n/// for a non-panicking variant.\npub fn decode_fields_from_bytes(bytes: BoundedVec) -> BoundedVec {\n assert(bytes.len() % 32 == 0, \"Input length must be a multiple of 32\");\n try_decode_fields_from_bytes(bytes).expect(f\"Value does not fit in field\")\n}\n\n/// Decodes bytes back into fields, returning None on failure.\n///\n/// Inverse of\n/// [`encode_fields_as_bytes`](crate::utils::conversion::fields_as_bytes::encode_fields_as_bytes).\n/// Returns `Option::none()` if the input length is not a multiple of 32, or if any 32-byte chunk is `>=` the BN254\n/// field modulus.\npub fn try_decode_fields_from_bytes(bytes: BoundedVec) -> Option> {\n if bytes.len() % 32 == 0 {\n let num_chunks = bytes.len() / 32;\n let mut fields: BoundedVec = BoundedVec::new();\n for i in 0..num_chunks {\n let maybe_field = try_decode_field_from_bytes(bytes, i * 32);\n if maybe_field.is_some() {\n fields.push(maybe_field.unwrap());\n }\n }\n if fields.len() == num_chunks {\n Option::some(fields)\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n}\n\nfn try_decode_field_from_bytes(bytes: BoundedVec, offset: u32) -> Option {\n // Field arithmetic silently wraps values >= the modulus, so we compare each chunk against the modulus\n // byte-by-byte (big-endian) while building `field`. cmp: 0 = equal so far, 1 = less than modulus, 2 = exceeds.\n let p = std::field::modulus_be_bytes();\n let mut field = 0;\n let mut cmp: u8 = 0;\n for j in 0..32 {\n let byte = bytes.get(offset + j);\n field = field * 256 + byte as Field;\n if cmp == 0 {\n if byte < p[j] {\n cmp = 1;\n } else if byte > p[j] {\n cmp = 2;\n }\n }\n }\n\n if cmp == 1 {\n Option::some(field)\n } else {\n Option::none()\n }\n}\n\nmod tests {\n use crate::utils::array::subarray;\n use super::{decode_fields_from_bytes, encode_fields_as_bytes, try_decode_fields_from_bytes};\n\n #[test]\n unconstrained fn round_trips_fields(input: [Field; 3]) {\n let bytes = encode_fields_as_bytes(input);\n\n // In production the bytes fly through the system and arrive as a BoundedVec on the other end. 113 is an\n // arbitrary max length larger than the input length of 96.\n let bytes_bvec = BoundedVec::<_, 113>::from_array(bytes);\n let fields_back = try_decode_fields_from_bytes(bytes_bvec).unwrap();\n\n assert_eq(fields_back.len(), input.len());\n assert_eq(subarray(fields_back.storage(), 0), input);\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_length_not_multiple_of_32() {\n let input = BoundedVec::<_, 64>::from_parts([0 as u8; 64], 33);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test]\n unconstrained fn try_decode_accepts_max_field() {\n // -1 in field arithmetic wraps to `modulus - 1`, the largest valid field value.\n let max_field_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let input = BoundedVec::<_, 32>::from_array(max_field_as_bytes);\n\n let fields = try_decode_fields_from_bytes(input).unwrap();\n\n assert_eq(fields.get(0), -1);\n }\n\n // Verifies the overflow check: take the max allowed value, bump a random byte, feed it in.\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n // Skip if the selected byte is already 255. Acceptable under fuzz testing.\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n }\n\n #[test]\n unconstrained fn try_decode_returns_none_on_chunk_equal_to_modulus() {\n // The field modulus itself is not a valid field value (it wraps to 0).\n let p: [u8; 32] = std::field::modulus_be_bytes().as_array();\n let input = BoundedVec::::from_array(p);\n assert(try_decode_fields_from_bytes(input).is_none());\n }\n\n #[test(should_fail_with = \"Input length must be a multiple of 32\")]\n unconstrained fn decode_asserts_length_multiple_of_32() {\n let input = BoundedVec::<_, 143>::from_array([\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n 30, 31, 32, 33,\n ]);\n let _fields = decode_fields_from_bytes(input);\n }\n\n #[test(should_fail_with = \"Value does not fit in field\")]\n unconstrained fn decode_panics_on_chunk_above_modulus(random_value: u8) {\n let index_of_byte_to_bump = random_value % 32;\n let max_field_value_as_bytes: [u8; 32] = (-1).to_be_bytes();\n let byte_to_bump = max_field_value_as_bytes[index_of_byte_to_bump as u32];\n\n if byte_to_bump != 255 {\n let mut input = BoundedVec::<_, 32>::from_array(max_field_value_as_bytes);\n input.set(index_of_byte_to_bump as u32, byte_to_bump + 1);\n let _fields = decode_fields_from_bytes(input);\n }\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/conversion/fields_as_bytes.nr","function_locations":[{"start":1007,"name":"encode_fields_as_bytes"},{"start":1603,"name":"decode_fields_from_bytes"},{"start":2190,"name":"try_decode_fields_from_bytes"},{"start":2829,"name":"try_decode_field_from_bytes"},{"start":3733,"name":"tests::round_trips_fields"},{"start":4320,"name":"tests::try_decode_returns_none_on_length_not_multiple_of_32"},{"start":4528,"name":"tests::try_decode_accepts_max_field"},{"start":5063,"name":"tests::try_decode_returns_none_on_chunk_above_modulus"},{"start":5718,"name":"tests::try_decode_returns_none_on_chunk_equal_to_modulus"},{"start":6128,"name":"tests::decode_asserts_length_multiple_of_32"},{"start":6544,"name":"tests::decode_panics_on_chunk_above_modulus"}]},"256":{"source":"use crate::protocol::{point::Point, utils::field::sqrt};\n\n// I am storing the modulus minus 1 divided by 2 here because full modulus would throw \"String literal too large\" error\n// Full modulus is 21888242871839275222246405745257275088548364400416034343698204186575808495617\nglobal BN254_FR_MODULUS_DIV_2: Field = 10944121435919637611123202872628637544274182200208017171849102093287904247808;\n\n/// Returns: true if p.y <= MOD_DIV_2, else false.\npub fn get_sign_of_point(p: Point) -> bool {\n // We store only a \"sign\" of the y coordinate because the rest can be derived from the x coordinate. To get the\n // sign we check if the y coordinate is less or equal than the field's modulus minus 1 divided by 2. Ideally we'd\n // do `y <= MOD_DIV_2`, but there's no `lte` function, so instead we do `!(y > MOD_DIV_2)`, which is equivalent,\n // and then rewrite that as `!(MOD_DIV_2 < y)`, since we also have no `gt` function.\n !BN254_FR_MODULUS_DIV_2.lt(p.y)\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\npub fn point_from_x_coord(x: Field) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n sqrt(rhs).map(|y| Point { x, y, is_infinite: false })\n}\n\n/// Returns a `Point` in the Grumpkin curve given its x coordinate and sign for the y coordinate.\n///\n/// Because not all values in the field are valid x coordinates of points in the curve (i.e. there is no corresponding\n/// y value in the field that satisfies the curve equation), it may not be possible to reconstruct a `Point`.\n/// `Option::none()` is returned in such cases.\n///\n/// @param x - The x coordinate of the point @param sign - The \"sign\" of the y coordinate - determines whether y <=\n/// (Fr.MODULUS - 1) / 2\npub fn point_from_x_coord_and_sign(x: Field, sign: bool) -> Option {\n // y ^ 2 = x ^ 3 - 17\n let rhs = x * x * x - 17;\n\n sqrt(rhs).map(|y| {\n // If there is a square root, we need to ensure it has the correct \"sign\"\n let y_is_positive = !BN254_FR_MODULUS_DIV_2.lt(y);\n let final_y = if y_is_positive == sign { y } else { -y };\n Point { x, y: final_y, is_infinite: false }\n })\n}\n\nmod test {\n use crate::protocol::point::Point;\n use crate::utils::point::{\n BN254_FR_MODULUS_DIV_2, get_sign_of_point, point_from_x_coord, point_from_x_coord_and_sign,\n };\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign() {\n // Test positive y coordinate\n let x = 0x1af41f5de96446dc3776a1eb2d98bb956b7acd9979a67854bec6fa7c2973bd73;\n let sign = true;\n let p = point_from_x_coord_and_sign(x, sign).unwrap();\n\n assert_eq(p.x, x);\n assert_eq(p.y, 0x07fc22c7f2c7057571f137fe46ea9c95114282bc95d37d71ec4bfb88de457d4a);\n assert_eq(p.is_infinite, false);\n\n // Test negative y coordinate\n let x2 = 0x247371652e55dd74c9af8dbe9fb44931ba29a9229994384bd7077796c14ee2b5;\n let sign2 = false;\n let p2 = point_from_x_coord_and_sign(x2, sign2).unwrap();\n\n assert_eq(p2.x, x2);\n assert_eq(p2.y, 0x26441aec112e1ae4cee374f42556932001507ad46e255ffb27369c7e3766e5c0);\n assert_eq(p2.is_infinite, false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_valid() {\n // x = 8 is a known quadratic residue - should give a valid point\n let result = point_from_x_coord(Field::from(8));\n assert(result.is_some());\n\n let point = result.unwrap();\n assert_eq(point.x, Field::from(8));\n // Check curve equation y^2 = x^3 - 17\n assert_eq(point.y * point.y, point.x * point.x * point.x - 17);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_invalid() {\n // x = 3 is a non-residue for this curve - should give None\n let x = Field::from(3);\n let maybe_point = point_from_x_coord(x);\n assert(maybe_point.is_none());\n }\n\n #[test]\n unconstrained fn test_both_roots_satisfy_curve() {\n // Derive a point from x = 8 (known to be valid from test_point_from_x_coord_valid)\n let x: Field = 8;\n let point = point_from_x_coord(x).unwrap();\n\n // Check y satisfies curve equation\n assert_eq(point.y * point.y, x * x * x - 17);\n\n // Check -y also satisfies curve equation\n let neg_y = 0 - point.y;\n assert_eq(neg_y * neg_y, x * x * x - 17);\n\n // Verify they are different (unless y = 0)\n assert(point.y != neg_y);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_and_sign_invalid() {\n // x = 3 has no valid point on the curve (from test_point_from_x_coord_invalid)\n let x = Field::from(3);\n let result_positive = point_from_x_coord_and_sign(x, true);\n let result_negative = point_from_x_coord_and_sign(x, false);\n\n assert(result_positive.is_none());\n assert(result_negative.is_none());\n }\n\n #[test]\n unconstrained fn test_get_sign_of_point() {\n // Derive a point from x = 8, then test both possible y values\n let point = point_from_x_coord(8).unwrap();\n let neg_point = Point { x: point.x, y: 0 - point.y, is_infinite: false };\n\n // One should be \"positive\" (y <= MOD_DIV_2) and one \"negative\"\n let sign1 = get_sign_of_point(point);\n let sign2 = get_sign_of_point(neg_point);\n assert(sign1 != sign2);\n\n // y = 0 should return true (0 <= MOD_DIV_2)\n let zero_y_point = Point { x: 0, y: 0, is_infinite: false };\n assert(get_sign_of_point(zero_y_point) == true);\n\n // y = MOD_DIV_2 should return true (exactly at boundary)\n let boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2, is_infinite: false };\n assert(get_sign_of_point(boundary_point) == true);\n\n // y = MOD_DIV_2 + 1 should return false (just over boundary)\n let over_boundary_point = Point { x: 0, y: BN254_FR_MODULUS_DIV_2 + 1, is_infinite: false };\n assert(get_sign_of_point(over_boundary_point) == false);\n }\n\n #[test]\n unconstrained fn test_point_from_x_coord_zero() {\n // x = 0: y^2 = 0^3 - 17 = -17, which is not a quadratic residue in BN254 scalar field\n let result = point_from_x_coord(0);\n assert(result.is_none());\n }\n\n #[test]\n unconstrained fn test_bn254_fr_modulus_div_2() {\n // Verify that BN254_FR_MODULUS_DIV_2 == (p - 1) / 2 This means: 2 * BN254_FR_MODULUS_DIV_2 + 1 == p == 0 (in\n // the field)\n assert_eq(2 * BN254_FR_MODULUS_DIV_2 + 1, 0);\n }\n\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/aztec-nr/aztec/src/utils/point.nr","function_locations":[{"start":488,"name":"get_sign_of_point"},{"start":1371,"name":"point_from_x_coord"},{"start":2088,"name":"point_from_x_coord_and_sign"},{"start":2697,"name":"test::test_point_from_x_coord_and_sign"},{"start":3524,"name":"test::test_point_from_x_coord_valid"},{"start":3966,"name":"test::test_point_from_x_coord_invalid"},{"start":4228,"name":"test::test_both_roots_satisfy_curve"},{"start":4803,"name":"test::test_point_from_x_coord_and_sign_invalid"},{"start":5214,"name":"test::test_get_sign_of_point"},{"start":6328,"name":"test::test_point_from_x_coord_zero"},{"start":6573,"name":"test::test_bn254_fr_modulus_div_2"}]},"266":{"source":"use std::default::Default;\nuse std::hash::Hasher;\n\nglobal RATE: u32 = 3;\n\npub struct Poseidon2 {\n cache: [Field; 3],\n state: [Field; 4],\n cache_size: u32,\n squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2 {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2::hash_internal(input, message_size)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2 {\n let mut result =\n Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n self.state[0] += self.cache[0];\n self.state[1] += self.cache[1];\n self.state[2] += self.cache[2];\n self.state = crate::poseidon2_permutation(self.state);\n }\n\n fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(input: [Field; N], in_len: u32) -> Field {\n let two_pow_64 = 18446744073709551616;\n let iv: Field = (in_len as Field) * two_pow_64;\n let mut state = [0; 4];\n state[RATE] = iv;\n\n if std::runtime::is_unconstrained() {\n for i in 0..(in_len / RATE) {\n state[0] += input[i * RATE];\n state[1] += input[i * RATE + 1];\n state[2] += input[i * RATE + 2];\n state = crate::poseidon2_permutation(state);\n }\n\n // handle remaining elements after last full RATE-sized chunk\n let num_extra_fields = in_len % RATE;\n if num_extra_fields != 0 {\n let remainder_start = in_len - num_extra_fields;\n state[0] += input[remainder_start];\n if num_extra_fields > 1 {\n state[1] += input[remainder_start + 1];\n }\n }\n } else {\n let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];\n states[0] = state;\n\n // process all full RATE-sized chunks, storing state after each permutation\n for chunk_idx in 0..(N / RATE) {\n for i in 0..RATE {\n state[i] += input[chunk_idx * RATE + i];\n }\n state = crate::poseidon2_permutation(state);\n states[chunk_idx + 1] = state;\n }\n\n // get state at the last full block before in_len\n let first_partially_filled_chunk = in_len / RATE;\n state = states[first_partially_filled_chunk];\n\n // handle remaining elements after last full RATE-sized chunk\n let remainder_start = (in_len / RATE) * RATE;\n for j in 0..RATE {\n let idx = remainder_start + j;\n if idx < in_len {\n state[j] += input[idx];\n }\n }\n }\n\n // always run final permutation unless we just completed a full chunk\n // still need to permute once if in_len is 0\n if (in_len == 0) | (in_len % RATE != 0) {\n state = crate::poseidon2_permutation(state);\n };\n\n state[0]\n }\n}\n\npub struct Poseidon2Hasher {\n _state: [Field],\n}\n\nimpl Hasher for Poseidon2Hasher {\n fn finish(self) -> Field {\n let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)\n let mut sponge = Poseidon2::new(iv);\n for i in 0..self._state.len() {\n sponge.absorb(self._state[i]);\n }\n sponge.squeeze()\n }\n\n fn write(&mut self, input: Field) {\n self._state = self._state.push_back(input);\n }\n}\n\nimpl Default for Poseidon2Hasher {\n fn default() -> Self {\n Poseidon2Hasher { _state: @[] }\n }\n}\n","path":"/Users/maximvezenov/nargo/github.com/noir-lang/poseidon/v0.3.0/src/poseidon2.nr","function_locations":[{"start":333,"name":"Poseidon2::hash"},{"start":442,"name":"Poseidon2::new"},{"start":649,"name":"Poseidon2::perform_duplex"},{"start":923,"name":"Poseidon2::absorb"},{"start":1453,"name":"Poseidon2::squeeze"},{"start":1814,"name":"Poseidon2::hash_internal"},{"start":4105,"name":"::finish"},{"start":4426,"name":"::write"},{"start":4549,"name":"::default"}]},"286":{"source":"use crate::traits::{Deserialize, Empty, FromField, Serialize, ToField};\nuse std::meta::derive;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct FunctionSelector {\n // Low 32 bits of the poseidon2 hash of the function signature.\n pub inner: u32,\n}\n\nimpl FromField for FunctionSelector {\n fn from_field(field: Field) -> Self {\n Self { inner: field as u32 }\n }\n}\n\nimpl ToField for FunctionSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n}\n\nimpl Empty for FunctionSelector {\n fn empty() -> Self {\n Self { inner: 0 as u32 }\n }\n}\n\nimpl FunctionSelector {\n pub fn from_u32(value: u32) -> Self {\n Self { inner: value }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = crate::hash::poseidon2_hash_bytes(bytes);\n\n // `hash` is automatically truncated to fit within 32 bits.\n FunctionSelector::from_field(hash)\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n}\n\n#[test]\nfn test_is_valid_selector() {\n let selector = FunctionSelector::from_signature(\"IS_VALID()\");\n assert_eq(selector.to_field(), 0x73cdda47);\n}\n\n#[test]\nfn test_long_selector() {\n let selector =\n FunctionSelector::from_signature(\"foo_and_bar_and_baz_and_foo_bar_baz_and_bar_foo\");\n assert_eq(selector.to_field(), 0x7590a997);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr","function_locations":[{"start":333,"name":"::from_field"},{"start":448,"name":"::to_field"},{"start":544,"name":"::empty"},{"start":652,"name":"FunctionSelector::from_u32"},{"start":756,"name":"FunctionSelector::from_signature"},{"start":1006,"name":"FunctionSelector::zero"},{"start":1079,"name":"test_is_valid_selector"},{"start":1231,"name":"test_long_selector"}]},"355":{"source":"mod poseidon2_chunks;\n\nuse crate::{\n abis::{\n contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage,\n function_selector::FunctionSelector, nullifier::Nullifier, private_log::PrivateLog,\n transaction::tx_request::TxRequest,\n },\n address::{AztecAddress, EthAddress},\n constants::{\n CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, DOM_SEP__NOTE_HASH_NONCE,\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__SILOED_NOTE_HASH, DOM_SEP__SILOED_NULLIFIER,\n DOM_SEP__UNIQUE_NOTE_HASH, FUNCTION_TREE_HEIGHT, NULL_MSG_SENDER_CONTRACT_ADDRESS,\n TWO_POW_64,\n },\n merkle_tree::root_from_sibling_path,\n messaging::l2_to_l1_message::L2ToL1Message,\n poseidon2::Poseidon2Sponge,\n side_effect::{Counted, Scoped},\n traits::{FromField, Hash, ToField},\n utils::field::{field_from_bytes, field_from_bytes_32_trunc},\n};\n\npub use poseidon2_chunks::poseidon2_absorb_in_chunks_existing_sponge;\nuse poseidon2_chunks::poseidon2_absorb_in_chunks;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\n// TODO: refactor these into their own files: sha256, poseidon2, some protocol-specific hash computations, some merkle computations.\n\npub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field {\n let sha256_hashed = sha256::digest(bytes_to_hash);\n let hash_in_a_field = field_from_bytes_32_trunc(sha256_hashed);\n\n hash_in_a_field\n}\n\npub fn private_functions_root_from_siblings(\n selector: FunctionSelector,\n vk_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT],\n) -> Field {\n let function_leaf_preimage = ContractClassFunctionLeafPreimage { selector, vk_hash };\n let function_leaf = function_leaf_preimage.hash();\n root_from_sibling_path(\n function_leaf,\n function_leaf_index,\n function_leaf_sibling_path,\n )\n}\n\n/// Siloing in the context of Aztec refers to the process of hashing a note hash with a contract address (this way\n/// the note hash is scoped to a specific contract). This is used to prevent intermingling of notes between contracts.\npub fn compute_siloed_note_hash(contract_address: AztecAddress, note_hash: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), note_hash],\n DOM_SEP__SILOED_NOTE_HASH,\n )\n}\n\n/// Computes unique, siloed note hashes from siloed note hashes.\n///\n/// The protocol injects uniqueness into every note_hash, so that every single note_hash in the\n/// tree is unique. This prevents faerie gold attacks, where a malicious sender could create\n/// two identical note_hashes for a recipient (meaning only one would be nullifiable in future).\n///\n/// Most privacy protocols will inject the note's leaf_index (its position in the Note Hashes Tree)\n/// into the note, but this requires the creator of a note to wait until their tx is included in\n/// a block to know the note's final note hash (the unique, siloed note hash), because inserting\n/// leaves into trees is the job of a block producer.\n///\n/// We took a different approach so that the creator of a note will know each note's unique, siloed\n/// note hash before broadcasting their tx to the network.\n/// (There was also a historical requirement relating to \"chained transactions\" -- a feature that\n/// Aztec Connect had to enable notes to be spent from distinct txs earlier in the same block,\n/// and hence before an archive block root had been established for that block -- but that feature\n/// was abandoned for the Aztec Network for having too many bad tradeoffs).\n///\n/// (\n/// Edit: it is no longer true that all final note_hashes will be known by the creator of a tx\n/// before they send it to the network. If a tx makes public function calls, then _revertible_\n/// note_hashes that are created in private will not be made unique in private by the Reset circuit,\n/// but will instead be made unique by the AVM, because the `note_index_in_tx` will not be known\n/// until the AVM has executed the public functions of the tx. (See an explanation in\n/// reset_output_composer.nr for why).\n/// For some such txs, the `note_index_in_tx` might still be predictable through simulation, but\n/// for txs whose public functions create a varying number of non-revertible notes (determined at\n/// runtime), the `note_index_in_tx` will not be deterministically derivable before submitting the\n/// tx to the network.\n/// )\n///\n/// We use the `first_nullifier` of a tx as a seed of uniqueness. We have a guarantee that there will\n/// always be at least one nullifier per tx, because the init circuit will create one if one isn't\n/// created naturally by any functions of the tx. (Search \"protocol_nullifier\").\n/// We combine the `first_nullifier` with the note's index (its position within this tx's new\n/// note_hashes array) (`note_index_in_tx`) to get a truly unique value to inject into a note, which\n/// we call a `note_nonce`.\npub fn compute_unique_note_hash(note_nonce: Field, siloed_note_hash: Field) -> Field {\n let inputs = [note_nonce, siloed_note_hash];\n poseidon2_hash_with_separator(inputs, DOM_SEP__UNIQUE_NOTE_HASH)\n}\n\npub fn compute_note_hash_nonce(first_nullifier_in_tx: Field, note_index_in_tx: u32) -> Field {\n // Hashing the first nullifier with note index in tx is guaranteed to be unique (because all nullifiers are also\n // unique).\n poseidon2_hash_with_separator(\n [first_nullifier_in_tx, note_index_in_tx as Field],\n DOM_SEP__NOTE_HASH_NONCE,\n )\n}\n\npub fn compute_note_nonce_and_unique_note_hash(\n siloed_note_hash: Field,\n first_nullifier: Field,\n note_index_in_tx: u32,\n) -> Field {\n let note_nonce = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n compute_unique_note_hash(note_nonce, siloed_note_hash)\n}\n\npub fn compute_siloed_nullifier(contract_address: AztecAddress, nullifier: Field) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), nullifier],\n DOM_SEP__SILOED_NULLIFIER,\n )\n}\n\npub fn create_protocol_nullifier(tx_request: TxRequest) -> Scoped> {\n // The protocol nullifier is ascribed a special side-effect counter of 1. No other side-effect\n // can have counter 1 (see `validate_as_first_call` for that assertion).\n Nullifier { value: tx_request.hash(), note_hash: 0 }.count(1).scope(\n NULL_MSG_SENDER_CONTRACT_ADDRESS,\n )\n}\n\npub fn compute_log_tag(raw_tag: Field, dom_sep: u32) -> Field {\n poseidon2_hash_with_separator([raw_tag], dom_sep)\n}\n\npub fn compute_siloed_private_log_first_field(\n contract_address: AztecAddress,\n field: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [contract_address.to_field(), field],\n DOM_SEP__PRIVATE_LOG_FIRST_FIELD,\n )\n}\n\npub fn compute_siloed_private_log(contract_address: AztecAddress, log: PrivateLog) -> PrivateLog {\n let mut fields = log.fields;\n fields[0] = compute_siloed_private_log_first_field(contract_address, fields[0]);\n PrivateLog::new(fields, log.length)\n}\n\npub fn compute_contract_class_log_hash(log: [Field; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS]) -> Field {\n poseidon2_hash(log)\n}\n\npub fn compute_app_siloed_secret_key(\n master_secret_key: EmbeddedCurveScalar,\n app_address: AztecAddress,\n key_type_domain_separator: Field,\n) -> Field {\n poseidon2_hash_with_separator(\n [master_secret_key.hi, master_secret_key.lo, app_address.to_field()],\n key_type_domain_separator,\n )\n}\n\npub fn compute_l2_to_l1_message_hash(\n message: Scoped,\n rollup_version_id: Field,\n chain_id: Field,\n) -> Field {\n let contract_address_bytes: [u8; 32] = message.contract_address.to_field().to_be_bytes();\n let recipient_bytes: [u8; 20] = message.inner.recipient.to_be_bytes();\n let content_bytes: [u8; 32] = message.inner.content.to_be_bytes();\n let rollup_version_id_bytes: [u8; 32] = rollup_version_id.to_be_bytes();\n let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();\n\n let mut bytes: [u8; 148] = std::mem::zeroed();\n for i in 0..32 {\n bytes[i] = contract_address_bytes[i];\n bytes[i + 32] = rollup_version_id_bytes[i];\n // 64 - 84 are for recipient.\n bytes[i + 84] = chain_id_bytes[i];\n bytes[i + 116] = content_bytes[i];\n }\n\n for i in 0..20 {\n bytes[64 + i] = recipient_bytes[i];\n }\n\n sha256_to_field(bytes)\n}\n\n// TODO: consider a variant that enables domain separation with a u32 (we seem to have standardised u32s for domain separators)\n/// Computes sha256 hash of 2 input fields.\n///\n/// @returns A truncated field (i.e., the first byte is always 0).\npub fn accumulate_sha256(v0: Field, v1: Field) -> Field {\n // Concatenate two fields into 32 x 2 = 64 bytes\n let v0_as_bytes: [u8; 32] = v0.to_be_bytes();\n let v1_as_bytes: [u8; 32] = v1.to_be_bytes();\n let hash_input_flattened = v0_as_bytes.concat(v1_as_bytes);\n\n sha256_to_field(hash_input_flattened)\n}\n\npub fn poseidon2_hash(inputs: [Field; N]) -> Field {\n poseidon::poseidon2::Poseidon2::hash(inputs, N)\n}\n\n#[no_predicates]\npub fn poseidon2_hash_with_separator(inputs: [Field; N], separator: T) -> Field\nwhere\n T: ToField,\n{\n let inputs_with_separator = [separator.to_field()].concat(inputs);\n poseidon2_hash(inputs_with_separator)\n}\n\n/// Computes a Poseidon2 hash over a dynamic-length subarray of the given input.\n/// Only the first `in_len` fields of `input` are absorbed; any remaining fields are ignored.\n/// The caller is responsible for ensuring that the input is padded with zeros if required.\n#[no_predicates]\npub fn poseidon2_hash_subarray(input: [Field; N], in_len: u32) -> Field {\n let mut sponge = poseidon2_absorb_in_chunks(input, in_len);\n sponge.squeeze()\n}\n\n// This function is unconstrained because it is intended to be used in unconstrained context only as\n// in constrained contexts it would be too inefficient.\npub unconstrained fn poseidon2_hash_with_separator_bounded_vec(\n inputs: BoundedVec,\n separator: T,\n) -> Field\nwhere\n T: ToField,\n{\n let in_len = inputs.len() + 1;\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n sponge.absorb(separator.to_field());\n\n for i in 0..inputs.len() {\n sponge.absorb(inputs.get(i));\n }\n\n sponge.squeeze()\n}\n\n#[no_predicates]\npub fn poseidon2_hash_bytes(inputs: [u8; N]) -> Field {\n let mut fields = [0; (N + 30) / 31];\n let mut field_index = 0;\n let mut current_field = [0; 31];\n for i in 0..inputs.len() {\n let index = i % 31;\n current_field[index] = inputs[i];\n if index == 30 {\n fields[field_index] = field_from_bytes(current_field, false);\n current_field = [0; 31];\n field_index += 1;\n }\n }\n if field_index != fields.len() {\n fields[field_index] = field_from_bytes(current_field, false);\n }\n poseidon2_hash(fields)\n}\n\n#[test]\nfn subarray_hash_matches_fixed() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash the entire values_to_hash.\n let fixed_len_hash = poseidon::poseidon2::Poseidon2::hash(values_to_hash, values_to_hash.len());\n\n assert_eq(subarray_hash, fixed_len_hash);\n}\n\n#[test]\nfn subarray_hash_matches_variable() {\n let values_to_hash = [3; 17];\n let padded = values_to_hash.concat([0; 11]);\n let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());\n\n // Hash up to values_to_hash.len() fields of the padded array.\n let variable_len_hash = poseidon::poseidon2::Poseidon2::hash(padded, values_to_hash.len());\n\n assert_eq(subarray_hash, variable_len_hash);\n}\n\n#[test]\nfn smoke_sha256_to_field() {\n let full_buffer = [\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\n 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,\n 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,\n 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,\n 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,\n 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,\n 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\n ];\n let result = sha256_to_field(full_buffer);\n\n assert(result == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184c7);\n\n // to show correctness of the current ver (truncate one byte) vs old ver (mod full bytes):\n let result_bytes = sha256::digest(full_buffer);\n let truncated_field = crate::utils::field::field_from_bytes_32_trunc(result_bytes);\n assert(truncated_field == result);\n let mod_res = result + (result_bytes[31] as Field);\n assert(mod_res == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184e0);\n}\n\n#[test]\nfn unique_siloed_note_hash_matches_typescript() {\n let inner_note_hash = 1;\n let contract_address = AztecAddress::from_field(2);\n let first_nullifier = 3;\n let note_index_in_tx = 4;\n\n let siloed_note_hash = compute_siloed_note_hash(contract_address, inner_note_hash);\n let siloed_note_hash_from_ts =\n 0x1986a4bea3eddb1fff917d629a13e10f63f514f401bdd61838c6b475db949169;\n assert_eq(siloed_note_hash, siloed_note_hash_from_ts);\n\n let nonce: Field = compute_note_hash_nonce(first_nullifier, note_index_in_tx);\n let note_hash_nonce_from_ts =\n 0x28e7799791bf066a57bb51fdd0fbcaf3f0926414314c7db515ea343f44f5d58b;\n assert_eq(nonce, note_hash_nonce_from_ts);\n\n let unique_siloed_note_hash_from_nonce = compute_unique_note_hash(nonce, siloed_note_hash);\n let unique_siloed_note_hash = compute_note_nonce_and_unique_note_hash(\n siloed_note_hash,\n first_nullifier,\n note_index_in_tx,\n );\n assert_eq(unique_siloed_note_hash_from_nonce, unique_siloed_note_hash);\n\n let unique_siloed_note_hash_from_ts =\n 0x29949aef207b715303b24639737c17fbfeb375c1d965ecfa85c7e4f0febb7d16;\n assert_eq(unique_siloed_note_hash, unique_siloed_note_hash_from_ts);\n}\n\n#[test]\nfn siloed_nullifier_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let nullifier = 456;\n\n let res = compute_siloed_nullifier(contract_address, nullifier);\n\n let siloed_nullifier_from_ts =\n 0x169b50336c1f29afdb8a03d955a81e485f5ac7d5f0b8065673d1e407e5877813;\n\n assert_eq(res, siloed_nullifier_from_ts);\n}\n\n#[test]\nfn siloed_private_log_first_field_matches_typescript() {\n let contract_address = AztecAddress::from_field(123);\n let field = 456;\n let res = compute_siloed_private_log_first_field(contract_address, field);\n\n let siloed_private_log_first_field_from_ts =\n 0x29480984f7b9257fded523d50addbcfc8d1d33adcf2db73ef3390a8fd5cdffaa;\n\n assert_eq(res, siloed_private_log_first_field_from_ts);\n}\n\n#[test]\nfn empty_l2_to_l1_message_hash_matches_typescript() {\n // All zeroes\n let res = compute_l2_to_l1_message_hash(\n L2ToL1Message { recipient: EthAddress::zero(), content: 0 }.scope(AztecAddress::from_field(\n 0,\n )),\n 0,\n 0,\n );\n\n let empty_l2_to_l1_msg_hash_from_ts =\n 0x003b18c58c739716e76429634a61375c45b3b5cd470c22ab6d3e14cee23dd992;\n\n assert_eq(res, empty_l2_to_l1_msg_hash_from_ts);\n}\n\n#[test]\nfn l2_to_l1_message_hash_matches_typescript() {\n let message = L2ToL1Message { recipient: EthAddress::from_field(1), content: 2 }.scope(\n AztecAddress::from_field(3),\n );\n let version = 4;\n let chainId = 5;\n\n let hash = compute_l2_to_l1_message_hash(message, version, chainId);\n\n // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`\n let l2_to_l1_message_hash_from_ts =\n 0x0081edf209e087ad31b3fd24263698723d57190bd1d6e9fe056fc0c0a68ee661;\n\n assert_eq(hash, l2_to_l1_message_hash_from_ts);\n}\n\n#[test]\nunconstrained fn poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version() {\n let inputs = BoundedVec::::from_array([1, 2, 3]);\n let separator = 42;\n\n // Hash using bounded vec version\n let bounded_result = poseidon2_hash_with_separator_bounded_vec(inputs, separator);\n\n // Hash using regular version\n let regular_result = poseidon2_hash_with_separator([1, 2, 3], separator);\n\n // Results should match\n assert_eq(bounded_result, regular_result);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr","function_locations":[{"start":1253,"name":"sha256_to_field"},{"start":1605,"name":"private_functions_root_from_siblings"},{"start":2202,"name":"compute_siloed_note_hash"},{"start":5031,"name":"compute_unique_note_hash"},{"start":5247,"name":"compute_note_hash_nonce"},{"start":5663,"name":"compute_note_nonce_and_unique_note_hash"},{"start":5899,"name":"compute_siloed_nullifier"},{"start":6116,"name":"create_protocol_nullifier"},{"start":6480,"name":"compute_log_tag"},{"start":6651,"name":"compute_siloed_private_log_first_field"},{"start":6882,"name":"compute_siloed_private_log"},{"start":7142,"name":"compute_contract_class_log_hash"},{"start":7333,"name":"compute_app_siloed_secret_key"},{"start":7628,"name":"compute_l2_to_l1_message_hash"},{"start":8709,"name":"accumulate_sha256"},{"start":9037,"name":"poseidon2_hash"},{"start":9228,"name":"poseidon2_hash_with_separator"},{"start":9714,"name":"poseidon2_hash_subarray"},{"start":10126,"name":"poseidon2_hash_with_separator_bounded_vec"},{"start":10487,"name":"poseidon2_hash_bytes"},{"start":11063,"name":"subarray_hash_matches_fixed"},{"start":11462,"name":"subarray_hash_matches_variable"},{"start":11878,"name":"smoke_sha256_to_field"},{"start":13280,"name":"unique_siloed_note_hash_matches_typescript"},{"start":14502,"name":"siloed_nullifier_matches_typescript"},{"start":14882,"name":"siloed_private_log_first_field_matches_typescript"},{"start":15292,"name":"empty_l2_to_l1_message_hash_matches_typescript"},{"start":15743,"name":"l2_to_l1_message_hash_matches_typescript"},{"start":16359,"name":"poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version"}]},"357":{"source":"// Log levels matching the JS logger:\n\n// global SILENT_LOG_LEVEL: u8 = 0;\nglobal FATAL_LOG_LEVEL: u8 = 1;\nglobal ERROR_LOG_LEVEL: u8 = 2;\nglobal WARN_LOG_LEVEL: u8 = 3;\nglobal INFO_LOG_LEVEL: u8 = 4;\nglobal VERBOSE_LOG_LEVEL: u8 = 5;\nglobal DEBUG_LOG_LEVEL: u8 = 6;\nglobal TRACE_LOG_LEVEL: u8 = 7;\n\n// --- Per-level log functions (no format args) ---\n\npub fn fatal_log(msg: str) {\n fatal_log_format(msg, []);\n}\n\npub fn error_log(msg: str) {\n error_log_format(msg, []);\n}\n\npub fn warn_log(msg: str) {\n warn_log_format(msg, []);\n}\n\npub fn info_log(msg: str) {\n info_log_format(msg, []);\n}\n\npub fn verbose_log(msg: str) {\n verbose_log_format(msg, []);\n}\n\npub fn debug_log(msg: str) {\n debug_log_format(msg, []);\n}\n\npub fn trace_log(msg: str) {\n trace_log_format(msg, []);\n}\n\n// --- Per-level log functions (with format args) ---\n\npub fn fatal_log_format(msg: str, args: [Field; N]) {\n log_format(FATAL_LOG_LEVEL, msg, args);\n}\n\npub fn error_log_format(msg: str, args: [Field; N]) {\n log_format(ERROR_LOG_LEVEL, msg, args);\n}\n\npub fn warn_log_format(msg: str, args: [Field; N]) {\n log_format(WARN_LOG_LEVEL, msg, args);\n}\n\npub fn info_log_format(msg: str, args: [Field; N]) {\n log_format(INFO_LOG_LEVEL, msg, args);\n}\n\npub fn verbose_log_format(msg: str, args: [Field; N]) {\n log_format(VERBOSE_LOG_LEVEL, msg, args);\n}\n\npub fn debug_log_format(msg: str, args: [Field; N]) {\n log_format(DEBUG_LOG_LEVEL, msg, args);\n}\n\npub fn trace_log_format(msg: str, args: [Field; N]) {\n log_format(TRACE_LOG_LEVEL, msg, args);\n}\n\nfn log_format(log_level: u8, msg: str, args: [Field; N]) {\n // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe\n // to call.\n unsafe { log_oracle_wrapper(log_level, msg, args) };\n}\n\nunconstrained fn log_oracle_wrapper(\n log_level: u8,\n msg: str,\n args: [Field; N],\n) {\n log_oracle(log_level, msg, N, args);\n}\n\n// While the length parameter might seem unnecessary given that we have N, we keep it around because at the AVM\n// bytecode level we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally\n// take that route. The AVM transpiler maps this oracle to the DEBUGLOG opcode, which reads the fields size from memory.\n#[oracle(aztec_utl_log)]\nunconstrained fn log_oracle(\n log_level: u8,\n msg: str,\n length: u32,\n args: [Field; N],\n) {}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/logging.nr","function_locations":[{"start":395,"name":"fatal_log"},{"start":473,"name":"error_log"},{"start":550,"name":"warn_log"},{"start":626,"name":"info_log"},{"start":705,"name":"verbose_log"},{"start":785,"name":"debug_log"},{"start":863,"name":"trace_log"},{"start":1033,"name":"fatal_log_format"},{"start":1161,"name":"error_log_format"},{"start":1288,"name":"warn_log_format"},{"start":1414,"name":"info_log_format"},{"start":1543,"name":"verbose_log_format"},{"start":1673,"name":"debug_log_format"},{"start":1801,"name":"trace_log_format"},{"start":1934,"name":"log_format"},{"start":2248,"name":"log_oracle_wrapper"},{"start":2801,"name":"log_oracle"}]},"376":{"source":"use crate::constants::TWO_POW_64;\nuse crate::traits::{Deserialize, Serialize};\nuse std::meta::derive;\n// NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr\n// It exists as we sometimes need to perform custom absorption, but the stdlib version\n// has a private absorb() method (it's also designed to just be a hasher)\n// Can be removed when standalone noir poseidon lib exists: See noir#6679\n// TODO: Poseidon is stand-alone now\n\nglobal RATE: u32 = 3;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct Poseidon2Sponge {\n pub cache: [Field; 3],\n pub state: [Field; 4],\n pub cache_size: u32,\n pub squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2Sponge {\n #[no_predicates]\n pub fn hash(input: [Field; N], message_size: u32) -> Field {\n Poseidon2Sponge::hash_internal(input, message_size, message_size != N)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2Sponge {\n let mut result =\n Poseidon2Sponge { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n for i in 0..RATE {\n // We effectively zero-pad the cache by only adding to the state\n // cache that is less than the specified `cache_size`\n if i < self.cache_size {\n self.state[i] += self.cache[i];\n }\n }\n self.state = std::hash::poseidon2_permutation(self.state);\n }\n\n pub fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n pub fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal(\n input: [Field; N],\n in_len: u32,\n is_variable_length: bool,\n ) -> Field {\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n for i in 0..input.len() {\n if i < in_len {\n sponge.absorb(input[i]);\n }\n }\n\n sponge.squeeze()\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr","function_locations":[{"start":798,"name":"Poseidon2Sponge::hash"},{"start":938,"name":"Poseidon2Sponge::new"},{"start":1151,"name":"Poseidon2Sponge::perform_duplex"},{"start":1592,"name":"Poseidon2Sponge::absorb"},{"start":2126,"name":"Poseidon2Sponge::squeeze"},{"start":2544,"name":"Poseidon2Sponge::hash_internal"}]},"395":{"source":"use crate::utils::field::field_from_bytes;\n\npub trait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n #[inline_always]\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for bool {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u8 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u16 {\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u32 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u64 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u128 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for str {\n #[inline_always]\n fn to_field(self) -> Field {\n assert(N < 32, \"String doesn't fit in a field, consider using Serialize instead\");\n field_from_bytes(self.as_bytes(), true)\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/traits/to_field.nr","function_locations":[{"start":176,"name":"::to_field"},{"start":276,"name":"::to_field"},{"start":382,"name":"::to_field"},{"start":468,"name":"::to_field"},{"start":575,"name":"::to_field"},{"start":682,"name":"::to_field"},{"start":790,"name":"::to_field"},{"start":912,"name":">::to_field"}]},"403":{"source":"pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n\n// Convert a 32 byte array to a field element by truncating the final byte\npub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..15 {\n // covers bytes 16..30 (31 is truncated and ignored)\n low = low + (bytes32[15 + 15 - i] as Field) * v;\n v = v * 256;\n // covers bytes 0..14\n high = high + (bytes32[14 - i] as Field) * v;\n }\n // covers byte 15\n low = low + (bytes32[15] as Field) * v;\n\n low + high * v\n}\n\npub fn min(f1: Field, f2: Field) -> Field {\n if f1.lt(f2) {\n f1\n } else {\n f2\n }\n}\n\n// TODO: write doc-comments and tests for these magic constants.\n\nglobal KNOWN_NON_RESIDUE: Field = 5; // This is a non-residue in Noir's native Field.\nglobal C1: u32 = 28;\nglobal C3: Field = 40770029410420498293352137776570907027550720424234931066070132305055;\nglobal C5: Field = 19103219067921713944291392827692070036145651957329286315305642004821462161904;\n\n// @dev: only use this for _huge_ exponents y, when writing a constrained function.\n// If you're only exponentiating by a small value, first consider writing-out the multiplications by hand.\n// Only after you've measured the gates of that approach, consider using the native Field::pow_32 function.\n// Only if your exponent is larger than 32 bits, resort to using this function.\npub fn pow(x: Field, y: Field) -> Field {\n let mut r = 1 as Field;\n let b: [bool; 254] = y.to_le_bits();\n\n for i in 0..254 {\n r *= r;\n r *= (b[254 - 1 - i] as Field) * x + (1 - b[254 - 1 - i] as Field);\n }\n\n r\n}\n\n/// Returns Option::some(sqrt) if there is a square root, and Option::none() if there isn't.\npub fn sqrt(x: Field) -> Option {\n // Safety: if the hint returns the square root of x, then we simply square it\n // check the result equals x. If x is not square, we return a value that\n // enables us to prove that fact (see the `else` clause below).\n let (is_sq, maybe_sqrt) = unsafe { __sqrt(x) };\n\n if is_sq {\n let sqrt = maybe_sqrt;\n validate_sqrt_hint(x, sqrt);\n Option::some(sqrt)\n } else {\n let not_sqrt_hint = maybe_sqrt;\n validate_not_sqrt_hint(x, not_sqrt_hint);\n Option::none()\n }\n}\n\n// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.\nunconstrained fn is_square(x: Field) -> bool {\n let v = pow(x, -1 / 2);\n v * (v - 1) == 0\n}\n\n// Tonelli-Shanks algorithm for computing the square root of a Field element.\n// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field\n// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),\n// and C5 = ZETA^C2, where ZETA is a non-square element of Field.\n// These are pre-computed above as globals.\nunconstrained fn tonelli_shanks_sqrt(x: Field) -> Field {\n let mut z = pow(x, C3);\n let mut t = z * z * x;\n z *= x;\n let mut b = t;\n let mut c = C5;\n\n for i in 0..(C1 - 1) {\n for _j in 1..(C1 - i - 1) {\n b *= b;\n }\n\n z *= if b == 1 { 1 } else { c };\n\n c *= c;\n\n t *= if b == 1 { 1 } else { c };\n\n b = t;\n }\n\n z\n}\n\n// NB: this doesn't return an option, because in the case of there _not_ being a square root, we still want to return a field element that allows us to then assert in the _constrained_ sqrt function that there is no sqrt.\nunconstrained fn __sqrt(x: Field) -> (bool, Field) {\n let is_sq = is_square(x);\n if is_sq {\n let sqrt = tonelli_shanks_sqrt(x);\n (true, sqrt)\n } else {\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // sq * sq = sq // 1 * 1 = 1\n // non-sq * non-sq = sq // -1 * -1 = 1\n // sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n let not_sqrt = tonelli_shanks_sqrt(demo_x_not_square);\n (false, not_sqrt)\n }\n}\n\nfn validate_sqrt_hint(x: Field, hint: Field) {\n assert(hint * hint == x, f\"The claimed_sqrt {hint} is not the sqrt of x {x}\");\n}\n\nfn validate_not_sqrt_hint(x: Field, hint: Field) {\n // We need this assertion, because x = 0 would pass the other assertions in this\n // function, and we don't want people to be able to prove that 0 is not square!\n assert(x != 0, \"0 has a square root; you cannot claim it is not square\");\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n //\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // 1. sq * sq = sq // 1 * 1 = 1\n // 2. non-sq * non-sq = sq // -1 * -1 = 1\n // 3. sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n //\n // We want to demonstrate that this below multiplication falls under bullet-point (2):\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n // I.e. we want to demonstrate that `demo_x_not_square` has Legendre symbol 1\n // (i.e. that it is a square), so we prove that it is square below.\n // Why do we want to prove that it has LS 1?\n // Well, since it was computed with a known-non-residue, its squareness implies we're\n // in case 2 (something multiplied by a known-non-residue yielding a result which\n // has a LS of 1), which implies that x must be a non-square. The unconstrained\n // function gave us the sqrt of demo_x_not_square, so all we need to do is\n // assert its squareness:\n assert(\n hint * hint == demo_x_not_square,\n f\"The hint {hint} does not demonstrate that {x} is not a square\",\n );\n}\n\n#[test]\nunconstrained fn bytes_field_test() {\n // Tests correctness of field_from_bytes_32_trunc against existing methods\n // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7\n let inputs = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167,\n ];\n let field = field_from_bytes(inputs, true);\n let return_bytes: [u8; 31] = field.to_be_bytes();\n assert_eq(inputs, return_bytes);\n // 32 bytes - we remove the final byte, and check it matches the field\n let inputs2 = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158,\n ];\n let field2 = field_from_bytes_32_trunc(inputs2);\n let return_bytes2: [u8; 31] = field2.to_be_bytes();\n\n assert_eq(return_bytes2, return_bytes);\n assert_eq(field2, field);\n}\n\n#[test]\nunconstrained fn max_field_test() {\n // Tests the hardcoded value in constants.nr vs underlying modulus\n // NB: We can't use 0-1 in constants.nr as it will be transpiled incorrectly to ts and sol constants files\n let max_value = crate::constants::MAX_FIELD_VALUE;\n assert_eq(max_value, 0 - 1);\n // modulus == 0 is tested elsewhere, so below is more of a sanity check\n let max_bytes: [u8; 32] = max_value.to_be_bytes();\n let mod_bytes = std::field::modulus_be_bytes();\n for i in 0..31 {\n assert_eq(max_bytes[i], mod_bytes[i]);\n }\n assert_eq(max_bytes[31], mod_bytes[31] - 1);\n}\n\n#[test]\nunconstrained fn sqrt_valid_test() {\n let x = 16; // examples: 16, 9, 25, 81\n let result = sqrt(x);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), x);\n}\n\n#[test]\nunconstrained fn sqrt_invalid_test() {\n let x = KNOWN_NON_RESIDUE; // has no square root in the field\n let result = sqrt(x);\n assert(result.is_none());\n}\n\n#[test]\nunconstrained fn sqrt_zero_test() {\n let result = sqrt(0);\n assert(result.is_some());\n assert_eq(result.unwrap(), 0);\n}\n\n#[test]\nunconstrained fn sqrt_one_test() {\n let result = sqrt(1);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), 1);\n}\n\n#[test]\nunconstrained fn field_from_bytes_empty_test() {\n let empty: [u8; 0] = [];\n let result = field_from_bytes(empty, true);\n assert_eq(result, 0);\n\n let result_le = field_from_bytes(empty, false);\n assert_eq(result_le, 0);\n}\n\n#[test]\nunconstrained fn field_from_bytes_little_endian_test() {\n // Test little-endian conversion: [0x01, 0x02] should be 0x0201 = 513\n let bytes = [0x01, 0x02];\n let result_le = field_from_bytes(bytes, false);\n assert_eq(result_le, 0x0201);\n\n // Compare with big-endian: [0x01, 0x02] should be 0x0102 = 258\n let result_be = field_from_bytes(bytes, true);\n assert_eq(result_be, 0x0102);\n}\n\n#[test]\nunconstrained fn pow_test() {\n assert_eq(pow(2, 0), 1);\n assert_eq(pow(2, 1), 2);\n assert_eq(pow(2, 10), 1024);\n assert_eq(pow(3, 5), 243);\n assert_eq(pow(0, 5), 0);\n assert_eq(pow(1, 100), 1);\n}\n\n#[test]\nunconstrained fn min_test() {\n assert_eq(min(5, 10), 5);\n assert_eq(min(10, 5), 5);\n assert_eq(min(7, 7), 7);\n assert_eq(min(0, 1), 0);\n}\n\n#[test]\nunconstrained fn sqrt_has_two_roots_test() {\n // Every square has two roots: r and -r (i.e., p - r)\n // sqrt(16) can return 4 or -4\n let x = 16;\n let result = sqrt(x).unwrap();\n assert(result * result == x);\n // The other root is -result\n let other_root = 0 - result;\n assert(other_root * other_root == x);\n // Verify they are different (unless x = 0)\n assert(result != other_root);\n\n // Same for 9: roots are 3 and -3\n let y = 9;\n let result_y = sqrt(y).unwrap();\n assert(result_y * result_y == y);\n let other_root_y = 0 - result_y;\n assert(other_root_y * other_root_y == y);\n assert(result_y != other_root_y);\n}\n\n#[test]\nunconstrained fn sqrt_negative_one_test() {\n let x = 0 - 1;\n let result = sqrt(x);\n assert(result.unwrap() == 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636);\n}\n\n#[test]\nunconstrained fn validate_sqrt_hint_valid_test() {\n // 4 is a valid sqrt of 16\n validate_sqrt_hint(16, 4);\n // -4 is also a valid sqrt of 16\n validate_sqrt_hint(16, 0 - 4);\n // 0 is a valid sqrt of 0\n validate_sqrt_hint(0, 0);\n // 1 is a valid sqrt of 1\n validate_sqrt_hint(1, 1);\n // -1 is also a valid sqrt of 1\n validate_sqrt_hint(1, 0 - 1);\n}\n\n#[test(should_fail_with = \"is not the sqrt of x\")]\nunconstrained fn validate_sqrt_hint_invalid_test() {\n // 5 is not a valid sqrt of 16\n validate_sqrt_hint(16, 5);\n}\n\n#[test]\nunconstrained fn validate_not_sqrt_hint_valid_test() {\n // 5 (KNOWN_NON_RESIDUE) is not a square.\n let x = KNOWN_NON_RESIDUE;\n let hint = tonelli_shanks_sqrt(x * KNOWN_NON_RESIDUE);\n validate_not_sqrt_hint(x, hint);\n}\n\n#[test(should_fail_with = \"0 has a square root\")]\nunconstrained fn validate_not_sqrt_hint_zero_test() {\n // 0 has a square root, so we cannot claim it is not square\n validate_not_sqrt_hint(0, 0);\n}\n\n#[test(should_fail_with = \"does not demonstrate that\")]\nunconstrained fn validate_not_sqrt_hint_wrong_hint_test() {\n // Provide a wrong hint for a non-square\n let x = KNOWN_NON_RESIDUE;\n validate_not_sqrt_hint(x, 123);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr","function_locations":[{"start":79,"name":"field_from_bytes"},{"start":553,"name":"field_from_bytes_32_trunc"},{"start":1054,"name":"min"},{"start":1899,"name":"pow"},{"start":2233,"name":"sqrt"},{"start":2915,"name":"is_square"},{"start":3343,"name":"tonelli_shanks_sqrt"},{"start":3951,"name":"__sqrt"},{"start":4795,"name":"validate_sqrt_hint"},{"start":4932,"name":"validate_not_sqrt_hint"},{"start":6570,"name":"bytes_field_test"},{"start":7553,"name":"max_field_test"},{"start":8177,"name":"sqrt_valid_test"},{"start":8379,"name":"sqrt_invalid_test"},{"start":8548,"name":"sqrt_zero_test"},{"start":8685,"name":"sqrt_one_test"},{"start":8854,"name":"field_from_bytes_empty_test"},{"start":9107,"name":"field_from_bytes_little_endian_test"},{"start":9492,"name":"pow_test"},{"start":9715,"name":"min_test"},{"start":9889,"name":"sqrt_has_two_roots_test"},{"start":10562,"name":"sqrt_negative_one_test"},{"start":10768,"name":"validate_sqrt_hint_valid_test"},{"start":11199,"name":"validate_sqrt_hint_invalid_test"},{"start":11331,"name":"validate_not_sqrt_hint_valid_test"},{"start":11611,"name":"validate_not_sqrt_hint_zero_test"},{"start":11828,"name":"validate_not_sqrt_hint_wrong_hint_test"}]},"409":{"source":"pub struct Reader {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Reader {\n pub fn new(data: [Field; N]) -> Self {\n Self { data, offset: 0 }\n }\n\n pub fn read(&mut self) -> Field {\n let result = self.data[self.offset];\n self.offset += 1;\n result\n }\n\n pub fn read_u32(&mut self) -> u32 {\n self.read() as u32\n }\n\n pub fn read_u64(&mut self) -> u64 {\n self.read() as u64\n }\n\n pub fn read_bool(&mut self) -> bool {\n self.read() != 0\n }\n\n pub fn read_array(&mut self) -> [Field; K] {\n let mut result = [0; K];\n for i in 0..K {\n result[i] = self.data[self.offset + i];\n }\n self.offset += K;\n result\n }\n\n pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T {\n let result = deserialise(self.read_array());\n result\n }\n\n pub fn read_struct_array(\n &mut self,\n deserialise: fn([Field; K]) -> T,\n mut result: [T; C],\n ) -> [T; C] {\n for i in 0..C {\n result[i] = self.read_struct(deserialise);\n }\n result\n }\n\n pub fn peek_offset(&mut self, offset: u32) -> Field {\n self.data[self.offset + offset]\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) {\n assert_eq(self.offset, self.data.len(), \"Reader did not read all data\");\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/reader.nr","function_locations":[{"start":144,"name":"Reader::new"},{"start":222,"name":"Reader::read"},{"start":355,"name":"Reader::read_u32"},{"start":429,"name":"Reader::read_u64"},{"start":505,"name":"Reader::read_bool"},{"start":598,"name":"Reader::read_array"},{"start":855,"name":"Reader::read_struct"},{"start":1094,"name":"Reader::read_struct_array"},{"start":1263,"name":"Reader::peek_offset"},{"start":1362,"name":"Reader::advance_offset"},{"start":1426,"name":"Reader::finish"}]},"410":{"source":"use crate::{reader::Reader, writer::Writer};\n\n/// Trait for serializing Noir types into arrays of Fields.\n///\n/// An implementation of the Serialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait (and Deserialize) are\n/// typically used to communicate between Noir and TypeScript (via oracles and function arguments).\n///\n/// # On Following Noir's Intrinsic Serialization\n/// When calling a Noir function from TypeScript (TS), first the function arguments are serialized into an array\n/// of fields. This array is then included in the initial witness. Noir's intrinsic serialization is then used\n/// to deserialize the arguments from the witness. When the same Noir function is called from Noir this Serialize trait\n/// is used instead of the serialization in TS. For this reason we need to have a match between TS serialization,\n/// Noir's intrinsic serialization and the implementation of this trait. If there is a mismatch, the function calls\n/// fail with an arguments hash mismatch error message.\n///\n/// # Associated Constants\n/// * `N` - The length of the output Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Serialize for str {\n/// let N: u32 = N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// let bytes = self.as_bytes();\n/// for i in 0..bytes.len() {\n/// writer.write(bytes[i] as Field);\n/// }\n/// }\n/// }\n/// ```\n#[derive_via(derive_serialize)]\npub trait Serialize {\n let N: u32;\n\n fn serialize(self) -> [Field; Self::N];\n\n fn stream_serialize(self, writer: &mut Writer);\n}\n\n/// Generates a `Serialize` trait implementation for a struct type.\n///\n/// # Parameters\n/// - `s`: The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A quoted code block containing the trait implementation\n///\n/// # Example\n/// For a struct defined as:\n/// ```\n/// struct Log {\n/// fields: [Field; N],\n/// length: u32\n/// }\n/// ```\n///\n/// This function generates code equivalent to:\n/// ```\n/// impl Serialize for Log {\n/// let N: u32 = <[Field; N] as Serialize>::N + ::N;\n///\n/// fn serialize(self) -> [Field; Self::N] {\n/// let mut writer: Writer = Writer::new();\n/// self.stream_serialize(&mut writer);\n/// writer.finish()\n/// }\n///\n/// #[inline_always]\n/// fn stream_serialize(self, writer: &mut Writer) {\n/// Serialize::stream_serialize(self.fields, writer);\n/// Serialize::stream_serialize(self.length, writer);\n/// }\n/// }\n/// ```\npub comptime fn derive_serialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n\n // We care only about the name and type so we drop the last item of the tuple\n let params = nested_struct.0.fields(nested_struct.1).map(|(name, typ, _)| (name, typ));\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Serialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_serialize_clause = get_where_trait_clause(s, quote {Serialize});\n\n let params_len_quote = get_params_len_quote(params);\n\n let function_body = params\n .map(|(name, _typ): (Quoted, Type)| {\n quote {\n $crate::serialization::Serialize::stream_serialize(self.$name, writer);\n }\n })\n .join(quote {});\n\n quote {\n impl$generics_declarations $crate::serialization::Serialize for $typ\n $where_serialize_clause\n {\n let N: u32 = $params_len_quote;\n\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n $crate::serialization::Serialize::stream_serialize(self, &mut writer);\n writer.finish()\n }\n\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n $function_body\n }\n }\n }\n}\n\n/// Trait for deserializing Noir types from arrays of Fields.\n///\n/// An implementation of the Deserialize trait has to follow Noir's intrinsic serialization (each member of a struct\n/// converted directly into one or more Fields without any packing or compression). This trait is typically used when\n/// deserializing return values from function calls in Noir. Since the same function could be called from TypeScript\n/// (TS), in which case the TS deserialization would get used, we need to have a match between the 2.\n///\n/// # Associated Constants\n/// * `N` - The length of the input Field array, known at compile time\n///\n/// # Example\n/// ```\n/// impl Deserialize for str {\n/// let N: u32 = M;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let mut bytes = [0 as u8; M];\n/// for i in 0..M {\n/// bytes[i] = reader.read() as u8;\n/// }\n/// str::::from(bytes)\n/// }\n/// }\n/// ```\n#[derive_via(derive_deserialize)]\npub trait Deserialize {\n let N: u32;\n\n fn deserialize(fields: [Field; Self::N]) -> Self;\n\n fn stream_deserialize(reader: &mut Reader) -> Self;\n}\n\n/// Generates a `Deserialize` trait implementation for a given struct `s`.\n///\n/// # Arguments\n/// * `s` - The struct type definition to generate the implementation for\n///\n/// # Returns\n/// A `Quoted` block containing the generated trait implementation\n///\n/// # Requirements\n/// Each struct member type must implement the `Deserialize` trait (it gets used in the generated code).\n///\n/// # Example\n/// For a struct like:\n/// ```\n/// struct MyStruct {\n/// x: AztecAddress,\n/// y: Field,\n/// }\n/// ```\n///\n/// This generates:\n/// ```\n/// impl Deserialize for MyStruct {\n/// let N: u32 = ::N + ::N;\n///\n/// fn deserialize(fields: [Field; Self::N]) -> Self {\n/// let mut reader = Reader::new(fields);\n/// let result = Self::stream_deserialize(&mut reader);\n/// reader.finish();\n/// result\n/// }\n///\n/// #[inline_always]\n/// fn stream_deserialize(reader: &mut Reader) -> Self {\n/// let x = ::stream_deserialize(reader);\n/// let y = ::stream_deserialize(reader);\n/// Self { x, y }\n/// }\n/// }\n/// ```\npub comptime fn derive_deserialize(s: TypeDefinition) -> Quoted {\n let typ = s.as_type();\n let nested_struct = typ.as_data_type().unwrap();\n let params = nested_struct.0.fields(nested_struct.1);\n\n // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause\n // for the `Deserialize` trait.\n let generics_declarations = get_generics_declarations(s);\n let where_deserialize_clause = get_where_trait_clause(s, quote {Deserialize});\n\n // The following will give us:\n // ::N + ::N + ...\n // (or 0 if the struct has no members)\n let right_hand_side_of_definition_of_n = if params.len() > 0 {\n params\n .map(|(_, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n <$param_type as $crate::serialization::Deserialize>::N\n }\n })\n .join(quote {+})\n } else {\n quote {0}\n };\n\n // For structs containing a single member, we can enhance performance by directly deserializing the input array,\n // bypassing the need for loop-based array construction. While this optimization yields significant benefits in\n // Brillig where the loops are expected to not be optimized, it is not relevant in ACIR where the loops are\n // expected to be optimized away.\n let function_body = if params.len() > 1 {\n // This generates deserialization code for each struct member and concatenates them together.\n let deserialization_of_struct_members = params\n .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| {\n quote {\n let $param_name = <$param_type as Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote {});\n\n // We join the struct member names with a comma to be used in the `Self { ... }` syntax\n // This will give us e.g. `a, b, c` for a struct with three fields named `a`, `b`, and `c`.\n let struct_members = params\n .map(|(param_name, _, _): (Quoted, Type, Quoted)| quote { $param_name })\n .join(quote {,});\n\n quote {\n $deserialization_of_struct_members\n\n Self { $struct_members }\n }\n } else if params.len() == 1 {\n let param_name = params[0].0;\n quote {\n Self { $param_name: $crate::serialization::Deserialize::stream_deserialize(reader) }\n }\n } else {\n quote {\n Self {}\n }\n };\n\n quote {\n impl$generics_declarations $crate::serialization::Deserialize for $typ\n $where_deserialize_clause\n {\n let N: u32 = $right_hand_side_of_definition_of_n;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $function_body\n }\n }\n }\n}\n\n/// Generates a quoted expression that computes the total serialized length of function parameters.\n///\n/// # Parameters\n/// * `params` - An array of tuples where each tuple contains a quoted parameter name and its Type. The type needs\n/// to implement the Serialize trait.\n///\n/// # Returns\n/// A quoted expression that evaluates to:\n/// * `0` if there are no parameters\n/// * `(::N + ::N + ...)` for one or more parameters\ncomptime fn get_params_len_quote(params: [(Quoted, Type)]) -> Quoted {\n if params.len() == 0 {\n quote { 0 }\n } else {\n let params_quote_without_parentheses = params\n .map(|(_, param_type): (Quoted, Type)| {\n quote {\n <$param_type as $crate::serialization::Serialize>::N\n }\n })\n .join(quote {+});\n quote { ($params_quote_without_parentheses) }\n }\n}\n\ncomptime fn get_generics_declarations(s: TypeDefinition) -> Quoted {\n let generics = s.generics();\n\n if generics.len() > 0 {\n let generics_declarations_items = generics\n .map(|(name, maybe_integer_typ)| {\n // The second item in the generics tuple is an Option of an integer type that is Some only if\n // the generic is numeric.\n if maybe_integer_typ.is_some() {\n // The generic is numeric, so we return a quote defined as e.g. \"let N: u32\"\n let integer_type = maybe_integer_typ.unwrap();\n quote {let $name: $integer_type}\n } else {\n // The generic is not numeric, so we return a quote containing the name of the generic (e.g. \"T\")\n quote {$name}\n }\n })\n .join(quote {,});\n quote {<$generics_declarations_items>}\n } else {\n // The struct doesn't have any generics defined, so we just return an empty quote.\n quote {}\n }\n}\n\ncomptime fn get_where_trait_clause(s: TypeDefinition, trait_name: Quoted) -> Quoted {\n let generics = s.generics();\n\n // The second item in the generics tuple is an Option of an integer type that is Some only if the generic is\n // numeric.\n let non_numeric_generics =\n generics.filter(|(_, maybe_integer_typ)| maybe_integer_typ.is_none());\n\n if non_numeric_generics.len() > 0 {\n let non_numeric_generics_declarations =\n non_numeric_generics.map(|(name, _)| quote {$name: $trait_name}).join(quote {,});\n quote {where $non_numeric_generics_declarations}\n } else {\n // There are no non-numeric generics, so we return an empty quote.\n quote {}\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/serialization.nr","function_locations":[{"start":3018,"name":"derive_serialize"},{"start":7206,"name":"derive_deserialize"},{"start":10928,"name":"get_params_len_quote"},{"start":11387,"name":"get_generics_declarations"},{"start":12469,"name":"get_where_trait_clause"}]},"412":{"source":"use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};\nuse std::embedded_curve_ops::EmbeddedCurvePoint;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\nglobal BOOL_SERIALIZED_LEN: u32 = 1;\nglobal U8_SERIALIZED_LEN: u32 = 1;\nglobal U16_SERIALIZED_LEN: u32 = 1;\nglobal U32_SERIALIZED_LEN: u32 = 1;\nglobal U64_SERIALIZED_LEN: u32 = 1;\nglobal U128_SERIALIZED_LEN: u32 = 1;\nglobal FIELD_SERIALIZED_LEN: u32 = 1;\nglobal I8_SERIALIZED_LEN: u32 = 1;\nglobal I16_SERIALIZED_LEN: u32 = 1;\nglobal I32_SERIALIZED_LEN: u32 = 1;\nglobal I64_SERIALIZED_LEN: u32 = 1;\n\nimpl Serialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> bool {\n reader.read() != 0\n }\n}\n\nimpl Serialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8\n }\n}\n\nimpl Serialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16\n }\n}\n\nimpl Serialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32\n }\n}\n\nimpl Serialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64\n }\n}\n\nimpl Serialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u128\n }\n}\n\nimpl Serialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self);\n }\n}\n\nimpl Deserialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read()\n }\n}\n\nimpl Serialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u8 as Field);\n }\n}\n\nimpl Deserialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u8 as i8\n }\n}\n\nimpl Serialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u16 as Field);\n }\n}\n\nimpl Deserialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u16 as i16\n }\n}\n\nimpl Serialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u32 as Field);\n }\n}\n\nimpl Deserialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u32 as i32\n }\n}\n\nimpl Serialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self as u64 as Field);\n }\n}\n\nimpl Deserialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n reader.read() as u64 as i64\n }\n}\n\nimpl Serialize for [T; M]\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n for i in 0..M {\n self[i].stream_serialize(writer);\n }\n }\n}\n\nimpl Deserialize for [T; M]\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut result: [T; M] = std::mem::zeroed();\n for i in 0..M {\n result[i] = T::stream_deserialize(reader);\n }\n result\n }\n}\n\nimpl Serialize for Option\nwhere\n T: Serialize,\n{\n let N: u32 = ::N + 1;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write_bool(self.is_some());\n if self.is_some() {\n self.unwrap_unchecked().stream_serialize(writer);\n } else {\n writer.advance_offset(::N);\n }\n }\n}\n\nimpl Deserialize for Option\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n if reader.read_bool() {\n Option::some(::stream_deserialize(reader))\n } else {\n reader.advance_offset(::N);\n Option::none()\n }\n }\n}\n\nglobal SCALAR_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurveScalar {\n\n let N: u32 = SCALAR_SIZE;\n\n fn serialize(self) -> [Field; SCALAR_SIZE] {\n [self.lo, self.hi]\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.lo);\n writer.write(self.hi);\n }\n}\n\nimpl Deserialize for EmbeddedCurveScalar {\n let N: u32 = SCALAR_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { lo: fields[0], hi: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { lo: reader.read(), hi: reader.read() }\n }\n}\n\nglobal POINT_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn serialize(self) -> [Field; Self::N] {\n [self.x, self.y]\n }\n\n fn stream_serialize(self, writer: &mut Writer) {\n writer.write(self.x);\n writer.write(self.y);\n }\n}\n\nimpl Deserialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { x: fields[0], y: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n Self { x: reader.read(), y: reader.read() }\n }\n}\n\nimpl Deserialize for str {\n let N: u32 = M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);\n str::::from(u8_arr)\n }\n}\n\nimpl Serialize for str {\n let N: u32 = M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.as_bytes().stream_serialize(writer);\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Deserialize for BoundedVec\nwhere\n T: Deserialize,\n{\n let N: u32 = ::N * M + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n let mut new_bounded_vec: BoundedVec = BoundedVec::new();\n let payload_len = Self::N - 1;\n\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n let len = reader.peek_offset(payload_len) as u32;\n\n for i in 0..M {\n if i < len {\n new_bounded_vec.push(::stream_deserialize(reader));\n }\n }\n\n // +1 for the length of the BoundedVec\n reader.advance_offset((M - len) * ::N + 1);\n\n new_bounded_vec\n }\n}\n\n// This may cause issues if used as program input, because noir disallows empty arrays for program input.\n// I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint\n// if someone does run into this in the future.\nimpl Deserialize for () {\n let N: u32 = 0;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(_reader: &mut Reader) -> Self {\n ()\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl Serialize for BoundedVec\nwhere\n T: Serialize,\n{\n let N: u32 = ::N * M + 1; // +1 for the length of the BoundedVec\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.storage().stream_serialize(writer);\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n writer.write_u32(self.len() as u32);\n }\n}\n\n// Create a slice of the given length with each element made from `f(i)` where `i` is the current index\ncomptime fn make_slice(length: u32, f: fn[Env](u32) -> T) -> [T] {\n let mut slice = @[];\n for i in 0..length {\n slice = slice.push_back(f(i));\n }\n slice\n}\n\n// Implements Serialize and Deserialize for an arbitrary tuple type\ncomptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {\n // `T0`, `T1`, `T2`\n let type_names = make_slice(length, |i| f\"T{i}\".quoted_contents());\n\n // `result0`, `result1`, `result2`\n let result_names = make_slice(length, |i| f\"result{i}\".quoted_contents());\n\n // `T0, T1, T2`\n let field_generics = type_names.join(quote [,]);\n\n // `::N + ::N + ::N`\n let full_size_serialize = type_names\n .map(|type_name| quote {\n <$type_name as Serialize>::N\n })\n .join(quote [+]);\n\n // `::N + ::N + ::N`\n let full_size_deserialize = type_names\n .map(|type_name| quote {\n <$type_name as Deserialize>::N\n })\n .join(quote [+]);\n\n // `T0: Serialize, T1: Serialize, T2: Serialize,`\n let serialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Serialize,\n })\n .join(quote []);\n\n // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`\n let deserialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Deserialize,\n })\n .join(quote []);\n\n // Statements to serialize each field\n let serialized_fields = type_names\n .mapi(|i, _type_name| quote {\n $crate::serialization::Serialize::stream_serialize(self.$i, writer);\n })\n .join(quote []);\n\n // Statements to deserialize each field\n let deserialized_fields = type_names\n .mapi(|i, type_name| {\n let result_name = result_names[i];\n quote {\n let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote []);\n let deserialize_results = result_names.join(quote [,]);\n\n quote {\n impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {\n let N: u32 = $full_size_serialize;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer = $crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut $crate::writer::Writer) {\n\n $serialized_fields\n }\n }\n\n impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {\n let N: u32 = $full_size_deserialize;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n \n #[inline_always]\n fn stream_deserialize(reader: &mut $crate::reader::Reader) -> Self {\n $deserialized_fields\n ($deserialize_results)\n }\n }\n }\n}\n\n// Keeping these manual impls. They are more efficient since they do not\n// require copying sub-arrays from any serialized arrays.\nimpl Serialize for (T1,)\nwhere\n T1: Serialize,\n{\n let N: u32 = ::N;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: crate::writer::Writer = crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize(self, writer: &mut Writer) {\n self.0.stream_serialize(writer);\n }\n}\n\nimpl Deserialize for (T1,)\nwhere\n T1: Deserialize,\n{\n let N: u32 = ::N;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize(reader: &mut Reader) -> Self {\n (::stream_deserialize(reader),)\n }\n}\n\n#[impl_serialize_for_tuple(2)]\n#[impl_serialize_for_tuple(3)]\n#[impl_serialize_for_tuple(4)]\n#[impl_serialize_for_tuple(5)]\n#[impl_serialize_for_tuple(6)]\nmod impls {\n use crate::serialization::{Deserialize, Serialize};\n}\n\n#[test]\nunconstrained fn bounded_vec_serialization() {\n // Test empty BoundedVec\n let empty_vec: BoundedVec = BoundedVec::from_array([]);\n let serialized = empty_vec.serialize();\n let deserialized = BoundedVec::::deserialize(serialized);\n assert_eq(empty_vec, deserialized);\n assert_eq(deserialized.len(), 0);\n\n // Test partially filled BoundedVec\n let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);\n let serialized = partial_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(partial_vec, deserialized);\n assert_eq(deserialized.len(), 1);\n assert_eq(deserialized.get(0), [1, 2]);\n\n // Test full BoundedVec\n let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);\n let serialized = full_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(full_vec, deserialized);\n assert_eq(deserialized.len(), 3);\n assert_eq(deserialized.get(0), [1, 2]);\n assert_eq(deserialized.get(1), [3, 4]);\n assert_eq(deserialized.get(2), [5, 6]);\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/type_impls.nr","function_locations":[{"start":693,"name":"::serialize"},{"start":914,"name":"::stream_serialize"},{"start":1082,"name":"::deserialize"},{"start":1328,"name":"::stream_deserialize"},{"start":1470,"name":"::serialize"},{"start":1691,"name":"::stream_serialize"},{"start":1855,"name":"::deserialize"},{"start":2101,"name":"::stream_deserialize"},{"start":2246,"name":"::serialize"},{"start":2467,"name":"::stream_serialize"},{"start":2633,"name":"::deserialize"},{"start":2879,"name":"::stream_deserialize"},{"start":3025,"name":"::serialize"},{"start":3246,"name":"::stream_serialize"},{"start":3412,"name":"::deserialize"},{"start":3658,"name":"::stream_deserialize"},{"start":3804,"name":"::serialize"},{"start":4025,"name":"::stream_serialize"},{"start":4191,"name":"::deserialize"},{"start":4437,"name":"::stream_deserialize"},{"start":4585,"name":"::serialize"},{"start":4806,"name":"::stream_serialize"},{"start":4974,"name":"::deserialize"},{"start":5220,"name":"::stream_deserialize"},{"start":5371,"name":"::serialize"},{"start":5592,"name":"::stream_serialize"},{"start":5753,"name":"::deserialize"},{"start":5999,"name":"::stream_deserialize"},{"start":6136,"name":"::serialize"},{"start":6357,"name":"::stream_serialize"},{"start":6527,"name":"::deserialize"},{"start":6773,"name":"::stream_deserialize"},{"start":6924,"name":"::serialize"},{"start":7145,"name":"::stream_serialize"},{"start":7318,"name":"::deserialize"},{"start":7564,"name":"::stream_deserialize"},{"start":7717,"name":"::serialize"},{"start":7938,"name":"::stream_serialize"},{"start":8111,"name":"::deserialize"},{"start":8357,"name":"::stream_deserialize"},{"start":8510,"name":"::serialize"},{"start":8731,"name":"::stream_serialize"},{"start":8904,"name":"::deserialize"},{"start":9150,"name":"::stream_deserialize"},{"start":9350,"name":"::serialize"},{"start":9571,"name":"::stream_serialize"},{"start":9831,"name":"::deserialize"},{"start":10077,"name":"::stream_deserialize"},{"start":10389,"name":">::serialize"},{"start":10610,"name":">::stream_serialize"},{"start":10997,"name":">::deserialize"},{"start":11243,"name":">::stream_deserialize"},{"start":11621,"name":"::serialize"},{"start":11744,"name":"::stream_serialize"},{"start":11944,"name":"::deserialize"},{"start":12090,"name":"::stream_deserialize"},{"start":12297,"name":"::serialize"},{"start":12397,"name":"::stream_serialize"},{"start":12593,"name":"::deserialize"},{"start":12737,"name":"::stream_deserialize"},{"start":12916,"name":">::deserialize"},{"start":13162,"name":">::stream_deserialize"},{"start":13395,"name":">::serialize"},{"start":13616,"name":">::stream_serialize"},{"start":13997,"name":">::deserialize"},{"start":14243,"name":">::stream_deserialize"},{"start":15299,"name":"::deserialize"},{"start":15546,"name":"::stream_deserialize"},{"start":15911,"name":">::serialize"},{"start":16132,"name":">::stream_serialize"},{"start":16617,"name":"make_slice"},{"start":16867,"name":"impl_serialize_for_tuple"},{"start":20158,"name":"::serialize"},{"start":20409,"name":"::stream_serialize"},{"start":20616,"name":"::deserialize"},{"start":20877,"name":"::stream_deserialize"},{"start":21226,"name":"bounded_vec_serialization"}]},"413":{"source":"pub struct Writer {\n data: [Field; N],\n offset: u32,\n}\n\nimpl Writer {\n pub fn new() -> Self {\n Self { data: [0; N], offset: 0 }\n }\n\n pub fn write(&mut self, value: Field) {\n self.data[self.offset] = value;\n self.offset += 1;\n }\n\n pub fn write_u32(&mut self, value: u32) {\n self.write(value as Field);\n }\n\n pub fn write_u64(&mut self, value: u64) {\n self.write(value as Field);\n }\n\n pub fn write_bool(&mut self, value: bool) {\n self.write(value as Field);\n }\n\n pub fn write_array(&mut self, value: [Field; K]) {\n for i in 0..K {\n self.data[i + self.offset] = value[i];\n }\n self.offset += K;\n }\n\n pub fn write_struct(&mut self, value: T, serialize: fn(T) -> [Field; K]) {\n self.write_array(serialize(value));\n }\n\n pub fn write_struct_array(\n &mut self,\n value: [T; C],\n serialize: fn(T) -> [Field; K],\n ) {\n for i in 0..C {\n self.write_struct(value[i], serialize);\n }\n }\n\n pub fn advance_offset(&mut self, offset: u32) {\n self.offset += offset;\n }\n\n pub fn finish(self) -> [Field; N] {\n assert_eq(self.offset, self.data.len(), \"Writer did not write all data\");\n self.data\n }\n}\n","path":"/Users/maximvezenov/Documents/dev/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/writer.nr","function_locations":[{"start":128,"name":"Writer::new"},{"start":220,"name":"Writer::write"},{"start":339,"name":"Writer::write_u32"},{"start":428,"name":"Writer::write_u64"},{"start":519,"name":"Writer::write_bool"},{"start":629,"name":"Writer::write_array"},{"start":841,"name":"Writer::write_struct"},{"start":1040,"name":"Writer::write_struct_array"},{"start":1185,"name":"Writer::advance_offset"},{"start":1263,"name":"Writer::finish"}]}}} \ No newline at end of file From c848a3be3b08fbab2679fcbabf4b69af1d909f67 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 7 May 2026 15:43:06 -0400 Subject: [PATCH 5/6] make fix --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 965aca159722..065fcc43871b 100644 --- a/Makefile +++ b/Makefile @@ -301,7 +301,6 @@ aztec-nr: noir bb-cpp-native noir-projects-txe-tests: $(call test,$@,noir-projects/aztec-nr) $(call test,$@,noir-projects/noir-contracts) - $(call test,$@,noir-projects/noir-contracts-comp-failures) # Noir Projects - Aggregate target (builds all sub-projects) noir-projects: noir-protocol-circuits mock-protocol-circuits noir-contracts aztec-nr From 3c82d771cd459ae4edd0cbf36e2e1dca49844cee Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Fri, 8 May 2026 10:34:55 -0400 Subject: [PATCH 6/6] commit cargo lock --- noir-projects/contract-snapshots/.gitignore | 1 - noir-projects/contract-snapshots/Cargo.lock | 483 ++++++++++++++++++++ 2 files changed, 483 insertions(+), 1 deletion(-) create mode 100644 noir-projects/contract-snapshots/Cargo.lock diff --git a/noir-projects/contract-snapshots/.gitignore b/noir-projects/contract-snapshots/.gitignore index e7fa33123dd6..ab3f4c8d559c 100644 --- a/noir-projects/contract-snapshots/.gitignore +++ b/noir-projects/contract-snapshots/.gitignore @@ -1,2 +1 @@ /**/target/ -Cargo.lock diff --git a/noir-projects/contract-snapshots/Cargo.lock b/noir-projects/contract-snapshots/Cargo.lock new file mode 100644 index 000000000000..255d09d74e94 --- /dev/null +++ b/noir-projects/contract-snapshots/Cargo.lock @@ -0,0 +1,483 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "console" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys", +] + +[[package]] +name = "contract-snapshots" +version = "0.1.0" +dependencies = [ + "insta", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "insta" +version = "1.47.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e" +dependencies = [ + "console", + "once_cell", + "similar", + "tempfile", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"