1- /**
2- * @title AuthRegistry Contract
3- * @notice Manages authorization of public actions through authentication witnesses (authwits)
4- * @dev This contract allows users to approve/reject public actions that can be performed on their behalf by other
5- * addresses
6- */
1+ /// A contract that manages public authentication witnesses (authwits) on the Aztec network.
2+ ///
3+ /// In Aztec, private authwits are verified by account contracts directly (via oracles on the user's device). Public
4+ /// authwits, however, require this onchain registry because local oracles cannot be used for global execution. Users pre-approve
5+ /// actions by storing `message_hash -> true` mappings via `set_authorized`, and consumer contracts verify and
6+ /// atomically revoke these approvals via `consume`.
7+ ///
8+ /// The `message_hash` includes the consumer address, chain ID, and protocol version, preventing cross-chain and
9+ /// cross-contract replay. Each approval can only be consumed once. Users can also enable `reject_all` as an emergency
10+ /// kill switch to invalidate all outstanding approvals at once.
11+ ///
12+ /// A private-to-public bridge is provided via `set_authorized_private`: a user signs a private authwit, and any party
13+ /// holding it can call this function to insert the corresponding public approval.
14+ ///
15+ /// Note that there is no expiration time enforced on the approved actions in this contract as this can be achieved by
16+ /// including an expiration timestamp in the `message` (`message_hash` preimage) and having the consumer contract
17+ /// constrain that value.
718pub contract AuthRegistry {
819 use aztec:: {
920 authwit:: auth ::{
@@ -22,19 +33,16 @@ pub contract AuthRegistry {
2233 };
2334
2435 struct Storage <Context > {
25- /// Map of addresses that have rejected all actions
36+ /// Per-address flag that, when true, causes all `consume` calls for that address to revert. Provides an
37+ /// emergency "mass revocation" mechanism. Does not delete existing approvals - if later set back to false,
38+ /// unconsumed approvals become consumable again.
2639 reject_all : Map <AztecAddress , PublicMutable <bool , Context >, Context >,
27- /// Nested map of approvers to their authorized message hashes
28- /// First key is the approver address, second key is the message hash, value is authorization status
40+ /// Per-user, per-message authorization status. `approved_actions[user][message_hash]` is set to true by
41+ /// `set_authorized` and atomically revoked by `consume` to prevent replay.
2942 approved_actions : Map <AztecAddress , Map <Field , PublicMutable <bool , Context >, Context >, Context >,
3043 }
3144
32- /**
33- * Updates the `authorized` value for `msg_sender` for `message_hash`.
34- *
35- * @param message_hash The message hash being authorized
36- * @param authorize True if the caller is authorized to perform the message hash, false otherwise
37- */
45+ /// Approves or revokes a `message_hash` for the caller.
3846 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
3947 unconstrained fn set_authorized (message_hash : Field , authorize : bool ) {
4048 // MACRO CODE START
@@ -51,13 +59,8 @@ pub contract AuthRegistry {
5159 storage .approved_actions .at (avm:: sender ()).at (message_hash ).write (authorize );
5260 }
5361
54- /**
55- * Updates the `reject_all` value for `msg_sender`.
56- *
57- * When `reject_all` is `true` any `consume` on `msg_sender` will revert.
58- *
59- * @param reject True if all actions should be rejected, false otherwise
60- */
62+ /// Enables or disables mass rejection of all authwits for the caller. When enabled, all `consume` calls for the
63+ /// caller's address will revert regardless of individual approvals.
6164 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
6265 unconstrained fn set_reject_all (reject : bool ) {
6366 // MACRO CODE START
@@ -73,16 +76,19 @@ pub contract AuthRegistry {
7376 storage .reject_all .at (avm:: sender ()).write (reject );
7477 }
7578
76- /**
77- * Consumes an `inner_hash` on behalf of `on_behalf_of` if the caller is authorized to do so.
78- *
79- * Will revert even if the caller is authorized if `reject_all` is set to true for `on_behalf_of`.
80- * This is to support "mass-revoke".
81- *
82- * @param on_behalf_of The address on whose behalf the action is being consumed
83- * @param inner_hash The inner_hash of the authwit
84- * @return `IS_VALID_SELECTOR` if the action was consumed, revert otherwise
85- */
79+ /// Consumes (verifies and atomically revokes) an authorization on behalf of `on_behalf_of`.
80+ ///
81+ /// Called by consumer contracts (e.g. Token) to verify a user has authorized an action. This function:
82+ /// 1. Checks that `on_behalf_of` has not enabled `reject_all`.
83+ /// 2. Recomputes the `message_hash` from the caller (consumer), chain ID, version, and `inner_hash`, binding the
84+ /// approval to this specific consumer contract.
85+ /// 3. Verifies the message was approved and atomically revokes it to prevent replay.
86+ ///
87+ /// Returns `IS_VALID_SELECTOR` (0x47dacd73) on success instead of a boolean. This follows the EIP-1271 pattern:
88+ /// a failed or malformed call would return the default zero value, which is indistinguishable from `false`. By
89+ /// requiring a specific magic value, the caller can reliably distinguish a successful validation from a failed
90+ /// call. The function also reverts on failure as a first line of defense, making the magic return value a
91+ /// defense-in-depth measure against subtle integration bugs on the caller side.
8692 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
8793 unconstrained fn consume (on_behalf_of : AztecAddress , inner_hash : Field ) -> pub Field {
8894 // MACRO CODE START
@@ -96,8 +102,11 @@ pub contract AuthRegistry {
96102 let storage : Storage <PublicContext > = Storage ::init (context );
97103 // MACRO CODE END
98104
105+ // reject_all is checked first so it takes precedence over individual approvals.
99106 assert_eq (false , storage .reject_all .at (on_behalf_of ).read (), "rejecting all" );
100107
108+ // The msg_sender here is the consumer contract, not the original user. This binds
109+ // the approval to a specific consumer, preventing cross-contract replay.
101110 let message_hash = compute_authwit_message_hash (
102111 context .maybe_msg_sender ().unwrap (),
103112 context .chain_id (),
@@ -106,24 +115,23 @@ pub contract AuthRegistry {
106115 );
107116
108117 let authorized = storage .approved_actions .at (on_behalf_of ).at (message_hash ).read ();
109-
110118 assert_eq (true , authorized , "unauthorized" );
119+ // Revoke the approval to prevent replay.
111120 storage .approved_actions .at (on_behalf_of ).at (message_hash ).write (false );
112121
113122 IS_VALID_SELECTOR
114123 }
115124
116- /**
117- * Updates a public authwit using a private authwit
118- *
119- * Useful for the case where you want someone else to insert a public authwit for you.
120- * For example, if Alice wants Bob to insert an authwit in public, such that they can execute
121- * a trade, Alice can create a private authwit, and Bob can call this function with it.
122- *
123- * @param approver The address of the approver (Alice in the example)
124- * @param message_hash The message hash to authorize
125- * @param authorize True if the message hash should be authorized, false otherwise
126- */
125+ /// Bridges a private authwit into a public authorization entry.
126+ ///
127+ /// Allows any party to insert a public approval on behalf of `approver`, provided they present a valid private
128+ /// authwit from that approver. Useful when e.g. Alice wants Bob to insert a public authwit for her so they can
129+ /// execute a trade - Alice signs a private authwit and Bob calls this function.
130+ ///
131+ /// This function:
132+ /// 1. Verifies the approver's private authwit via `assert_current_call_valid_authwit` (static call + nullifier
133+ /// emission to prevent replay).
134+ /// 2. Enqueues a public call to `_set_authorized` to write the approval during the public phase.
127135 #[aztec::macros::internals_functions_generation::abi_attributes::abi_private]
128136 fn set_authorized_private (
129137 inputs : aztec::context::inputs::PrivateContextInputs ,
@@ -143,12 +151,10 @@ pub contract AuthRegistry {
143151
144152 // MACRO CODE END
145153
146- // 3 corresponds to the number of arguments of the function
154+ // The generic parameter `3` is the number of function arguments (approver, message_hash, authorize).
147155 assert_current_call_valid_authwit ::<3 >(&mut context , approver );
148156
149- // Enqueue call to _set_authorized
150- // Note: This was originally just `self.enqueue_self._set_authorized(approver, message_hash, authorize);`
151- // before de-macroification.
157+ // Enqueue a public call to _set_authorized to write the approval into public storage.
152158 {
153159 let enqueue_params : [Field ; 3 ] =
154160 [approver .to_field (), message_hash , authorize .to_field ()];
@@ -169,14 +175,8 @@ pub contract AuthRegistry {
169175 // MACRO CODE END
170176 }
171177
172- /**
173- * Internal function to update the `authorized` value for `approver` for `messageHash`.
174- * Used along with `set_authorized_private` to update the public authwit.
175- *
176- * @param approver The address of the approver
177- * @param message_hash The message hash being authorized
178- * @param authorize True if the caller is authorized to perform the message hash, false otherwise
179- */
178+ /// A function that writes an authorization entry for an arbitrary `approver`. Only callable by this contract
179+ /// itself (`#[only_self]`), ensuring it is only reachable through the validated `set_authorized_private` flow.
180180 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
181181 #[aztec::macros::internals_functions_generation::abi_attributes::abi_only_self]
182182 unconstrained fn _set_authorized (approver : AztecAddress , message_hash : Field , authorize : bool ) {
@@ -193,7 +193,6 @@ pub contract AuthRegistry {
193193 );
194194 let storage : Storage <PublicContext > = Storage ::init (context );
195195
196- // Originally injected by the #[only_self] macro
197196 assert (
198197 avm:: sender () == context .this_address (),
199198 "Function _set_authorized can only be called by the same contract" ,
@@ -203,12 +202,7 @@ pub contract AuthRegistry {
203202 storage .approved_actions .at (approver ).at (message_hash ).write (authorize );
204203 }
205204
206- /**
207- * Fetches the `reject_all` value for `on_behalf_of`.
208- *
209- * @param on_behalf_of The address to check
210- * @return True if all actions are rejected, false otherwise
211- */
205+ /// Returns whether `on_behalf_of` has enabled the `reject_all` flag.
212206 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
213207 #[aztec::macros::internals_functions_generation::abi_attributes::abi_view]
214208 unconstrained fn is_reject_all (on_behalf_of : AztecAddress ) -> pub bool {
@@ -222,20 +216,14 @@ pub contract AuthRegistry {
222216 );
223217 let storage : Storage <PublicContext > = Storage ::init (context );
224218
225- // Originally injected by the #[view] macro
226219 assert (context .is_static_call (), "Function is_reject_all can only be called statically" );
227220 // MACRO CODE END
228221
229222 storage .reject_all .at (on_behalf_of ).read ()
230223 }
231224
232- /**
233- * Fetches the `authorized` value for `on_behalf_of` for `message_hash`.
234- *
235- * @param on_behalf_of The address on whose behalf the action is being consumed
236- * @param message_hash The message hash to check
237- * @return True if the caller is authorized to perform the action, false otherwise
238- */
225+ /// Returns whether a specific `message_hash` is currently approved for `on_behalf_of`.
226+ /// Does NOT check the `reject_all` flag - also check `is_reject_all` for a complete picture.
239227 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
240228 #[aztec::macros::internals_functions_generation::abi_attributes::abi_view]
241229 unconstrained fn is_consumable (on_behalf_of : AztecAddress , message_hash : Field ) -> pub bool {
@@ -249,16 +237,13 @@ pub contract AuthRegistry {
249237 );
250238 let storage : Storage <PublicContext > = Storage ::init (context );
251239
252- // Originally injected by the #[view] macro
253240 assert (context .is_static_call (), "Function is_consumable can only be called statically" );
254241 // MACRO CODE END
255242
256243 storage .approved_actions .at (on_behalf_of ).at (message_hash ).read ()
257244 }
258245
259- /**
260- * Just like `is_consumable`, but a utility function and not public.
261- */
246+ /// Utility version of `is_consumable`
262247 #[aztec::macros::internals_functions_generation::abi_attributes::abi_utility]
263248 unconstrained fn utility_is_consumable (
264249 on_behalf_of : AztecAddress ,
@@ -274,20 +259,24 @@ pub contract AuthRegistry {
274259 storage .approved_actions .at (on_behalf_of ).at (message_hash ).read ()
275260 }
276261
277- // // THE REST OF THE CODE IN THIS CONTRACT WAS ORIGINALLY INJECTED BY THE #[aztec] MACRO.
262+ // THE REST OF THE CODE IN THIS CONTRACT WAS ORIGINALLY INJECTED BY THE #[aztec] MACRO.
278263
279- // Function selectors computed at comptime from function signatures
280264 global SET_AUTHORIZED_SELECTOR : Field =
281265 comptime { FunctionSelector ::from_signature ("set_authorized(Field,bool)" ).to_field () };
266+
282267 global SET_REJECT_ALL_SELECTOR : Field =
283268 comptime { FunctionSelector ::from_signature ("set_reject_all(bool)" ).to_field () };
269+
284270 global CONSUME_SELECTOR : Field =
285271 comptime { FunctionSelector ::from_signature ("consume((Field),Field)" ).to_field () };
272+
286273 global _SET_AUTHORIZED_SELECTOR : Field = comptime {
287274 FunctionSelector ::from_signature ("_set_authorized((Field),Field,bool)" ).to_field ()
288275 };
276+
289277 global IS_REJECT_ALL_SELECTOR : Field =
290278 comptime { FunctionSelector ::from_signature ("is_reject_all((Field))" ).to_field () };
279+
291280 global IS_CONSUMABLE_SELECTOR : Field =
292281 comptime { FunctionSelector ::from_signature ("is_consumable((Field),Field)" ).to_field () };
293282
@@ -365,7 +354,6 @@ pub contract AuthRegistry {
365354 }
366355 }
367356
368- // Parameter structs for ABI
369357 pub struct _set_authorized_parameters {
370358 pub _approver : AztecAddress ,
371359 pub _message_hash : Field ,
@@ -406,7 +394,6 @@ pub contract AuthRegistry {
406394 pub _message_hash : Field ,
407395 }
408396
409- // ABI structs
410397 #[abi(functions)]
411398 pub struct _set_authorized_abi {
412399 parameters : _set_authorized_parameters ,
0 commit comments