Skip to main content

aztec_core/
constants.rs

1//! Well-known protocol contract addresses and domain separators.
2//!
3//! These addresses and constants are deterministic and identical across all Aztec networks.
4
5use crate::types::{AztecAddress, Fr};
6
7/// Well-known protocol contract addresses.
8pub mod protocol_contract_address {
9    use super::*;
10
11    /// The Fee Juice contract — manages fee token balances and claims.
12    pub fn fee_juice() -> AztecAddress {
13        AztecAddress(Fr::from(5u64))
14    }
15
16    /// The PublicChecks protocol contract.
17    pub fn public_checks() -> AztecAddress {
18        AztecAddress(Fr::from(6u64))
19    }
20
21    /// The AuthRegistry protocol contract — manages public authorization witnesses.
22    pub fn auth_registry() -> AztecAddress {
23        AztecAddress(Fr::from(1u64))
24    }
25
26    /// The Contract Instance Deployer — registers contract instances on-chain.
27    pub fn contract_instance_deployer() -> AztecAddress {
28        AztecAddress(Fr::from(2u64))
29    }
30
31    /// The Contract Instance Registry — canonical public deployment registry.
32    pub fn contract_instance_registry() -> AztecAddress {
33        contract_instance_deployer()
34    }
35
36    /// The Contract Class Registerer — publishes contract classes on-chain.
37    pub fn contract_class_registerer() -> AztecAddress {
38        AztecAddress(Fr::from(3u64))
39    }
40
41    /// The Contract Class Registry — canonical class publication registry.
42    pub fn contract_class_registry() -> AztecAddress {
43        contract_class_registerer()
44    }
45
46    /// The Multi-Call Entrypoint — batches multiple calls in one tx.
47    pub fn multi_call_entrypoint() -> AztecAddress {
48        AztecAddress(Fr::from(4u64))
49    }
50
51    /// Sentinel msg sender address used by protocol nullifiers.
52    ///
53    /// Upstream `NULL_MSG_SENDER_CONTRACT_ADDRESS = AztecAddress::from_field(-1)`.
54    pub fn null_msg_sender() -> AztecAddress {
55        AztecAddress(
56            Fr::from_hex("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000")
57                .expect("valid null msg sender address"),
58        )
59    }
60}
61
62/// Domain separators used in Poseidon2 hashing throughout the protocol.
63///
64/// These must match the TS constants in `constants.gen.ts`.
65pub mod domain_separator {
66    /// Domain separator for authwit inner hash.
67    ///
68    /// TS: `DomainSeparator.AUTHWIT_INNER = 221354163`
69    pub const AUTHWIT_INNER: u32 = 221_354_163;
70
71    /// Domain separator for authwit outer hash.
72    ///
73    /// TS: `DomainSeparator.AUTHWIT_OUTER = 3283595782`
74    pub const AUTHWIT_OUTER: u32 = 3_283_595_782;
75
76    /// Domain separator for function args hashing.
77    ///
78    /// TS: `DomainSeparator.FUNCTION_ARGS = 3576554347`
79    pub const FUNCTION_ARGS: u32 = 3_576_554_347;
80
81    /// Domain separator for public function calldata hashing.
82    ///
83    /// TS: `DomainSeparator.PUBLIC_CALLDATA = 2760353947`
84    pub const PUBLIC_CALLDATA: u32 = 2_760_353_947;
85    /// Domain separator for private tx hashes.
86    ///
87    /// TS: `DomainSeparator.PRIVATE_TX_HASH = 1971680439`
88    pub const PRIVATE_TX_HASH: u32 = 1_971_680_439;
89    /// Domain separator for public tx hashes.
90    ///
91    /// TS: `DomainSeparator.PUBLIC_TX_HASH = 1630108851`
92    pub const PUBLIC_TX_HASH: u32 = 1_630_108_851;
93
94    /// Domain separator for tx request hashes.
95    ///
96    /// TS: `DomainSeparator.TX_REQUEST = 3763737512`
97    pub const TX_REQUEST: u32 = 3_763_737_512;
98
99    /// Domain separator for the protocol contracts tuple hash.
100    ///
101    /// TS: `DomainSeparator.PROTOCOL_CONTRACTS = 3904434327`
102    pub const PROTOCOL_CONTRACTS: u32 = 3_904_434_327;
103
104    /// Domain separator for public keys hash computation.
105    pub const PUBLIC_KEYS_HASH: u32 = 777_457_226;
106
107    /// Domain separator for partial address / salted initialization hash.
108    pub const PARTIAL_ADDRESS: u32 = 2_103_633_018;
109
110    /// Domain separator for contract class ID computation.
111    pub const CONTRACT_CLASS_ID: u32 = 3_923_495_515;
112
113    /// Domain separator for private function leaf hashing.
114    pub const PRIVATE_FUNCTION_LEAF: u32 = 1_389_398_688;
115
116    /// Domain separator for public bytecode commitment.
117    pub const PUBLIC_BYTECODE: u32 = 260_313_585;
118
119    /// Domain separator for initialization hash computation.
120    pub const INITIALIZER: u32 = 385_396_519;
121
122    /// Domain separator for contract address V1 derivation.
123    pub const CONTRACT_ADDRESS_V1: u32 = 1_788_365_517;
124
125    /// Master nullifier hiding key derivation.
126    ///
127    /// TS: `DomainSeparator.NHK_M = 242137788`
128    pub const NHK_M: u32 = 242_137_788;
129
130    /// Master incoming viewing secret key derivation.
131    ///
132    /// TS: `DomainSeparator.IVSK_M = 2747825907`
133    pub const IVSK_M: u32 = 2_747_825_907;
134
135    /// Master outgoing viewing secret key derivation.
136    ///
137    /// TS: `DomainSeparator.OVSK_M = 4272201051`
138    pub const OVSK_M: u32 = 4_272_201_051;
139
140    /// Master tagging secret key derivation.
141    ///
142    /// TS: `DomainSeparator.TSK_M = 1546190975`
143    pub const TSK_M: u32 = 1_546_190_975;
144
145    /// Secret hash (for L1-L2 messages and TransparentNote).
146    ///
147    /// TS: `DomainSeparator.SECRET_HASH = 4199652938`
148    pub const SECRET_HASH: u32 = 4_199_652_938;
149
150    /// Message nullifier (for L1-to-L2 message consumption proofs).
151    ///
152    /// TS: `DomainSeparator.MESSAGE_NULLIFIER = 3754509616`
153    pub const MESSAGE_NULLIFIER: u32 = 3_754_509_616;
154
155    /// Domain separator for signature payload hashing (entrypoint encoding).
156    ///
157    /// TS: `DomainSeparator.SIGNATURE_PAYLOAD = 463525807`
158    pub const SIGNATURE_PAYLOAD: u32 = 463_525_807;
159
160    /// Domain separator for siloing note hashes with a contract address.
161    ///
162    /// TS: `DomainSeparator.SILO_NOTE_HASH = 1864988894`
163    pub const SILO_NOTE_HASH: u32 = 1_864_988_894;
164
165    /// Domain separator for siloing nullifiers with a contract address.
166    ///
167    /// TS: `DomainSeparator.SILO_NULLIFIER = 3956568061`
168    pub const SILO_NULLIFIER: u32 = 3_956_568_061;
169
170    /// Domain separator for unique note hash computation.
171    pub const UNIQUE_NOTE_HASH: u32 = 226_850_429;
172
173    /// Domain separator for note hash nonce computation.
174    pub const NOTE_HASH_NONCE: u32 = 1_721_808_740;
175
176    /// Domain separator for siloed note hash (inner silo step).
177    pub const SILOED_NOTE_HASH: u32 = 3_361_878_420;
178
179    /// Domain separator for siloed nullifier (inner silo step).
180    pub const SILOED_NULLIFIER: u32 = 57_496_191;
181
182    /// Domain separator for private log first field siloing.
183    pub const PRIVATE_LOG_FIRST_FIELD: u32 = 2_769_976_252;
184
185    /// Domain separator for note nullifier derivation.
186    ///
187    /// TS: `DomainSeparator.NOTE_NULLIFIER = 50789342`
188    pub const NOTE_NULLIFIER: u32 = 50_789_342;
189}
190
191// ---------------------------------------------------------------------------
192// Per-transaction limits (from constants.gen.ts)
193// ---------------------------------------------------------------------------
194
195/// Maximum note hashes per transaction.
196pub const MAX_NOTE_HASHES_PER_TX: usize = 64;
197/// Maximum nullifiers per transaction.
198pub const MAX_NULLIFIERS_PER_TX: usize = 64;
199/// Maximum private logs per transaction.
200pub const MAX_PRIVATE_LOGS_PER_TX: usize = 64;
201/// Maximum L2-to-L1 messages per transaction.
202pub const MAX_L2_TO_L1_MSGS_PER_TX: usize = 8;
203/// Maximum enqueued public calls per transaction.
204pub const MAX_ENQUEUED_CALLS_PER_TX: usize = 32;
205/// Maximum contract class logs per transaction.
206pub const MAX_CONTRACT_CLASS_LOGS_PER_TX: usize = 1;
207/// Size of a contract class log in field elements.
208pub const CONTRACT_CLASS_LOG_SIZE_IN_FIELDS: usize = 3023;
209
210// Per-call limits
211/// Maximum note hashes per call.
212pub const MAX_NOTE_HASHES_PER_CALL: usize = 16;
213/// Maximum nullifiers per call.
214pub const MAX_NULLIFIERS_PER_CALL: usize = 16;
215/// Maximum private call stack length per call.
216pub const MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL: usize = 8;
217/// Maximum enqueued calls per call.
218pub const MAX_ENQUEUED_CALLS_PER_CALL: usize = 32;
219/// Maximum L2-to-L1 messages per call.
220pub const MAX_L2_TO_L1_MSGS_PER_CALL: usize = 8;
221/// Maximum private logs per call.
222pub const MAX_PRIVATE_LOGS_PER_CALL: usize = 16;
223/// Maximum contract class logs per call.
224pub const MAX_CONTRACT_CLASS_LOGS_PER_CALL: usize = 1;
225
226// Read request limits
227/// Maximum note hash read requests per transaction.
228pub const MAX_NOTE_HASH_READ_REQUESTS_PER_TX: usize = 64;
229/// Maximum nullifier read requests per transaction.
230pub const MAX_NULLIFIER_READ_REQUESTS_PER_TX: usize = 64;
231/// Maximum key validation requests per transaction.
232pub const MAX_KEY_VALIDATION_REQUESTS_PER_TX: usize = 64;
233/// Maximum note hash read requests per call.
234pub const MAX_NOTE_HASH_READ_REQUESTS_PER_CALL: usize = 16;
235/// Maximum nullifier read requests per call.
236pub const MAX_NULLIFIER_READ_REQUESTS_PER_CALL: usize = 16;
237/// Maximum key validation requests per call.
238pub const MAX_KEY_VALIDATION_REQUESTS_PER_CALL: usize = 16;
239
240/// Maximum calldata fields across all enqueued public calls.
241pub const MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS: usize = 12_288;
242
243// Private log size
244/// Size of a private log in field elements.
245pub const PRIVATE_LOG_SIZE_IN_FIELDS: usize = 16;
246
247// ---------------------------------------------------------------------------
248// Tree heights
249// ---------------------------------------------------------------------------
250
251/// Note hash tree height.
252pub const NOTE_HASH_TREE_HEIGHT: usize = 42;
253/// Nullifier tree height.
254pub const NULLIFIER_TREE_HEIGHT: usize = 42;
255/// Public data tree height.
256pub const PUBLIC_DATA_TREE_HEIGHT: usize = 40;
257/// L1-to-L2 message tree height.
258pub const L1_TO_L2_MSG_TREE_HEIGHT: usize = 36;
259/// Maximum L1-to-L2 messages per rollup checkpoint.
260pub const NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP: usize = 1024;
261/// L1-to-L2 message subtree height (for subtree insertion proofs).
262pub const L1_TO_L2_MSG_SUBTREE_HEIGHT: usize = 10;
263/// Archive tree height.
264pub const ARCHIVE_HEIGHT: usize = 30;
265/// VK tree height.
266pub const VK_TREE_HEIGHT: usize = 8;
267/// Canonical protocol contract tuple length.
268pub const MAX_PROTOCOL_CONTRACTS: usize = 11;
269
270/// Canonical VK tree root for the pinned Aztec 4.1.3 protocol artifacts.
271///
272/// This matches `aztec compute-genesis-values` and upstream
273/// `getVKTreeRoot()` from `aztec-packages`.
274pub fn current_vk_tree_root() -> Fr {
275    Fr::from_hex("0x1dd2644a17d1ddd8831287a78c5a1033b7ae35cdf2a3db833608856c062fc2ba")
276        .expect("valid canonical VK tree root")
277}
278
279// ---------------------------------------------------------------------------
280// Proof lengths
281// ---------------------------------------------------------------------------
282
283/// ChonkProof field count.
284pub const CHONK_PROOF_LENGTH: usize = 1935;
285/// Recursive proof field count.
286pub const RECURSIVE_PROOF_LENGTH: usize = 449;
287
288// ---------------------------------------------------------------------------
289// Gas constants
290// ---------------------------------------------------------------------------
291
292/// DA gas overhead per transaction.
293pub const TX_DA_GAS_OVERHEAD: u64 = 96;
294/// L2 gas overhead for transactions with public calls.
295pub const PUBLIC_TX_L2_GAS_OVERHEAD: u64 = 540_000;
296/// L2 gas overhead for private-only transactions.
297pub const PRIVATE_TX_L2_GAS_OVERHEAD: u64 = 440_000;
298/// Fixed AVM startup L2 gas.
299pub const FIXED_AVM_STARTUP_L2_GAS: u64 = 20_000;
300
301/// L2 gas per note hash.
302pub const L2_GAS_PER_NOTE_HASH: u64 = 9_200;
303/// L2 gas per nullifier.
304pub const L2_GAS_PER_NULLIFIER: u64 = 16_000;
305/// L2 gas per L2-to-L1 message.
306pub const L2_GAS_PER_L2_TO_L1_MSG: u64 = 5_200;
307/// L2 gas per private log.
308pub const L2_GAS_PER_PRIVATE_LOG: u64 = 2_500;
309/// L2 gas per contract class log.
310pub const L2_GAS_PER_CONTRACT_CLASS_LOG: u64 = 73_000;
311
312/// Bytes per field element for DA cost.
313pub const DA_BYTES_PER_FIELD: u64 = 32;
314/// DA gas per byte.
315pub const DA_GAS_PER_BYTE: u64 = 1;
316/// DA gas per field element.
317pub const DA_GAS_PER_FIELD: u64 = 32;
318
319/// Maximum processable L2 gas.
320pub const MAX_PROCESSABLE_L2_GAS: u64 = 6_540_000;
321/// Maximum processable DA gas per checkpoint.
322pub const MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT: u64 = 786_432;
323
324/// Default L2 gas limit.
325pub const DEFAULT_L2_GAS_LIMIT: u64 = 6_540_000;
326/// Default teardown L2 gas limit.
327pub const DEFAULT_TEARDOWN_L2_GAS_LIMIT: u64 = 1_000_000;
328/// Default DA gas limit.
329pub const DEFAULT_DA_GAS_LIMIT: u64 = 786_432;
330/// Default teardown DA gas limit.
331pub const DEFAULT_TEARDOWN_DA_GAS_LIMIT: u64 = 393_216;
332
333/// Maximum transaction lifetime in seconds.
334pub const MAX_TX_LIFETIME: u64 = 86_400;
335
336// ---------------------------------------------------------------------------
337// Size constants for deployment computations
338// ---------------------------------------------------------------------------
339
340/// Height of the private functions Merkle tree.
341pub const FUNCTION_TREE_HEIGHT: usize = 7;
342
343/// Maximum number of field elements in packed public bytecode.
344pub const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: usize = 3000;
345
346/// Magic prefix for `ContractClassRegistry` emitted class-publication logs.
347pub fn contract_class_published_magic_value() -> Fr {
348    Fr::from_hex("0x20f5895a4e837356c2d551743df6bf642756dcd93cd31cbd37c556c90bf7f244")
349        .expect("valid contract class published magic value")
350}
351
352/// Magic prefix for `ContractInstanceRegistry` emitted instance-publication logs.
353pub fn contract_instance_published_magic_value() -> Fr {
354    Fr::from_hex("0x174c6b3d0fd14728e4fc5e53f7b262ab943546a7e125e2ed5e9fde3cf0b3e22f")
355        .expect("valid contract instance published magic value")
356}
357
358/// Maximum height of the artifact function tree.
359pub const ARTIFACT_FUNCTION_TREE_MAX_HEIGHT: usize = 7;
360
361/// Bytecode capsule slot used by the Contract Class Registry.
362pub fn contract_class_registry_bytecode_capsule_slot() -> Fr {
363    Fr::from_hex("0x1f61038721b052d5389449bf44f73c817146aedfab1ef13d37f16ce928df1fb7")
364        .expect("valid contract class registry capsule slot constant")
365}
366
367#[cfg(test)]
368#[allow(clippy::expect_used)]
369mod tests {
370    use super::*;
371
372    #[test]
373    fn fee_juice_address_is_5() {
374        let addr = protocol_contract_address::fee_juice();
375        assert_eq!(addr, AztecAddress(Fr::from(5u64)));
376    }
377
378    #[test]
379    fn auth_registry_address_is_1() {
380        let addr = protocol_contract_address::auth_registry();
381        assert_eq!(addr, AztecAddress(Fr::from(1u64)));
382    }
383
384    #[test]
385    fn domain_separator_values_match_ts() {
386        assert_eq!(domain_separator::AUTHWIT_INNER, 221_354_163);
387        assert_eq!(domain_separator::AUTHWIT_OUTER, 3_283_595_782);
388        assert_eq!(domain_separator::FUNCTION_ARGS, 3_576_554_347);
389        assert_eq!(domain_separator::PUBLIC_CALLDATA, 2_760_353_947);
390        assert_eq!(domain_separator::PUBLIC_KEYS_HASH, 777_457_226);
391        assert_eq!(domain_separator::PARTIAL_ADDRESS, 2_103_633_018);
392        assert_eq!(domain_separator::CONTRACT_CLASS_ID, 3_923_495_515);
393        assert_eq!(domain_separator::PRIVATE_FUNCTION_LEAF, 1_389_398_688);
394        assert_eq!(domain_separator::PUBLIC_BYTECODE, 260_313_585);
395        assert_eq!(domain_separator::INITIALIZER, 385_396_519);
396        assert_eq!(domain_separator::CONTRACT_ADDRESS_V1, 1_788_365_517);
397        // Key derivation separators
398        assert_eq!(domain_separator::NHK_M, 242_137_788);
399        assert_eq!(domain_separator::IVSK_M, 2_747_825_907);
400        assert_eq!(domain_separator::OVSK_M, 4_272_201_051);
401        assert_eq!(domain_separator::TSK_M, 1_546_190_975);
402        assert_eq!(domain_separator::SECRET_HASH, 4_199_652_938);
403        assert_eq!(domain_separator::SIGNATURE_PAYLOAD, 463_525_807);
404    }
405
406    #[test]
407    fn protocol_contract_addresses() {
408        assert_eq!(
409            protocol_contract_address::contract_instance_deployer(),
410            AztecAddress(Fr::from(2u64))
411        );
412        assert_eq!(
413            protocol_contract_address::contract_class_registerer(),
414            AztecAddress(Fr::from(3u64))
415        );
416        assert_eq!(
417            protocol_contract_address::multi_call_entrypoint(),
418            AztecAddress(Fr::from(4u64))
419        );
420    }
421
422    #[test]
423    fn size_constants() {
424        assert_eq!(super::FUNCTION_TREE_HEIGHT, 7);
425        assert_eq!(super::MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, 3000);
426        assert_eq!(super::ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, 7);
427        assert_eq!(super::MAX_PROCESSABLE_L2_GAS, 6_540_000);
428    }
429
430    #[test]
431    fn tx_limit_constants() {
432        assert_eq!(super::MAX_NOTE_HASHES_PER_TX, 64);
433        assert_eq!(super::MAX_NULLIFIERS_PER_TX, 64);
434        assert_eq!(super::MAX_PRIVATE_LOGS_PER_TX, 64);
435        assert_eq!(super::MAX_L2_TO_L1_MSGS_PER_TX, 8);
436        assert_eq!(super::MAX_ENQUEUED_CALLS_PER_TX, 32);
437        assert_eq!(super::MAX_CONTRACT_CLASS_LOGS_PER_TX, 1);
438        assert_eq!(super::CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, 3023);
439        assert_eq!(super::CHONK_PROOF_LENGTH, 1935);
440    }
441
442    #[test]
443    fn gas_constants() {
444        assert_eq!(super::L2_GAS_PER_NOTE_HASH, 9_200);
445        assert_eq!(super::L2_GAS_PER_NULLIFIER, 16_000);
446        assert_eq!(super::DA_GAS_PER_FIELD, 32);
447        assert_eq!(super::PRIVATE_TX_L2_GAS_OVERHEAD, 440_000);
448        assert_eq!(super::PUBLIC_TX_L2_GAS_OVERHEAD, 540_000);
449    }
450
451    #[test]
452    fn kernel_domain_separators() {
453        assert_eq!(domain_separator::UNIQUE_NOTE_HASH, 226_850_429);
454        assert_eq!(domain_separator::NOTE_HASH_NONCE, 1_721_808_740);
455        assert_eq!(domain_separator::SILOED_NOTE_HASH, 3_361_878_420);
456        assert_eq!(domain_separator::SILOED_NULLIFIER, 57_496_191);
457        assert_eq!(domain_separator::PRIVATE_LOG_FIRST_FIELD, 2_769_976_252);
458    }
459
460    #[test]
461    fn capsule_slot_constant_matches_ts() {
462        assert_eq!(
463            contract_class_registry_bytecode_capsule_slot(),
464            Fr::from_hex("0x1f61038721b052d5389449bf44f73c817146aedfab1ef13d37f16ce928df1fb7")
465                .expect("valid slot")
466        );
467    }
468}