Repository navigation
Conversation
Every protocol version rotates the contract address domain separator so an
address can never exist on two rollup instances. v4 shipped V1 and v5 shipped
V2; next (v6) still carried V2, so v6 addresses could collide with v5 ones.
Replace DOM_SEP__CONTRACT_ADDRESS_V2 (4099338721) with
DOM_SEP__CONTRACT_ADDRESS_V3 = 993442748 = hash_to_u32("az_dom_sep",
"contract_address_v3"), as checked by constants_tests.nr, and propagate it:
the AVM address-derivation PIL and its generated relation, the C++ AVM
simulation/tracegen/constraining sources, the constants-codegen selections,
the protocol circuit test vectors and contract fixtures, and the labs consumers
(a new labs-patches entry: derivation.ts, aztec-nr's separator list, address
snapshots and the standard-contract address tables). The protocol contracts'
derived addresses move with the separator, so the genesis roots and the C++
genesis seed vector were regenerated with regenerate_genesis_constants.sh; the
six L1 checkpoint fixtures still need the --fixtures pass.
Labs patch recording, in the unversioned developer migration notes, that every contract address on v6 differs from v5 (the address domain separator is rotated per protocol version) and the standard contracts' canonical addresses old to new.
jest's inline snapshot writer mangled derivation.test.ts (a comment line was spliced into the preceding statement, breaking compilation) and dropped blank lines in contract_address.test.ts. Restore both files to their upstream content with only the three new snapshot values applied.
…parator The protocol contracts' derived addresses move with the separator, so the genesis archive root the checkpoint fixtures start from changed. Regenerated with noir-projects/fnd/scripts/regenerate_genesis_constants.sh --fixtures; --check reports the genesis constants up to date.
Resolutions: - constants.nr: next's GENESIS_* values, V3 rename re-applied. All three genesis roots still need re-measuring on this tree. - genesis_protocol_nullifiers.hpp: now native-packages/wsdb/cpp, new namespace. Took next's seed vector; needs re-measuring. - l1-contracts checkpoint fixtures: took next's; need regenerating. - labs-patches: next upstreamed the two patches this branch renumbered; the separator and migration-note patches move to 0011/0012 on the tail of next's series. - native-packages/wsdb/scripts/constants-codegen/cpp.json: next's second copy of the C++ selection list also selects the separator.
The separator patch carried the pre-bump blob id for derivation.test.ts, so `git am --3way` needed a preimage that a --depth 1 submodule clone does not have: apply failed on a fresh checkout. Re-exported against the gitlink, so a straight apply works.
Measured with regenerate_genesis_constants.sh --fixtures against a build of this tree; --check afterwards reports up to date. Exactly one of the six protocol registration nullifiers moves with the separator: the class nullifier of ContractInstanceRegistry, whose bytecode embeds AztecAddress::compute. The other five, including all three instance nullifiers (siloed by the magic addresses 1/2/3), are unchanged. wsdb's constants selection stays on V2: native-packages/wsdb builds against the published release in foundation.pin, whose constants.nr has no V3, and no wsdb source reads the separator.
next added labs-patches/0011 for the Glamsterdam L1 gas constants, so the separator and migration-note patches move to 0012/0013.
Re-run after the Glamsterdam L1 gas constants landed on next; the genesis roots and the seed vector are unchanged by that, only the fixtures' gas fees move. regenerate_genesis_constants.sh --check: up to date.
HandshakeRegistry reaches get_public_keys, which asserts account == AztecAddress::compute(public_keys, partial_address), so the address domain separator is compiled into its bytecode. Its pinned artifact has to be refreshed with the separator or it derives v5 addresses inside a v6 tree and rejects every account; the e2e prover run fails on exactly that assertion. Re-pinning recompiles all four standard contracts, so MultiCallEntrypoint's artifact hash and private functions root move too - unrelated to the separator, and a consequence of the pinned build predating the current toolchain. Its canonical address moves with them, and the migration note carries both new addresses.
Written by the e2e prover dump (AZTEC_GENERATE_TEST_DATA=1 FAKE_PROOFS=1 yarn test:e2e single-node/prover/server/full.test). The init and inner fixtures pinned addresses derived under the old separator, so the two circuits CI executes aborted in validate_contract_address; all sixteen circuits in the bootstrap's circuits_to_execute list now execute.
world_state.test.cpp seeds a tree from genesis_protocol_nullifiers() and asserts the roots it produces. Those expectations came from the GENESIS_* macros in common/aztec_constants.hpp, which is generated from the release named in foundation.pin rather than from this tree, so the seeds and the roots they are compared against have different sources and disagree whenever the genesis moves here first - which it cannot avoid doing, since the pin can only advance to a release that already contains the new values. regenerate_genesis_constants.sh now writes the three roots alongside the seeds it measures them from, --check holds them to the measurement, and the test reads them from there. constants.nr stays the protocol's source of truth.
…with the v3 separator
The last failure in 25623's run that spalladino's 0016 does not cover: seven of the eight handshake_registry_contract recipient_signature tests fail on verify()'s opening assert_eq(recipient, AztecAddress::compute(...)). Independently cross-checked against 0016: recomputing both PXE AddressStore addresses and the key-store address with the old separator reproduces each pinned value exactly, and under v3 they give exactly the values in 0016, including the complete_address_index reordering that follows from the new addresses' sort order.
AztecBot
force-pushed
the
cb/v3-separator-stale-address-fixtures
branch
from
October 7, 2026 23:39
2f4fa81 to
8db4a1e
Compare
Base automatically changed from
mc/bump-contract-address-domain-separator-v3
to
next
October 8, 2026 01:22
Collaborator
Author
|
Closing as redundant. Everything on this branch is on Created by claudebox · group: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Into #25521. Carries @spalladino's two commits from #25622 unchanged and adds the one failure they don't cover, so merging this lands everything and closes that PR.
The pattern
Each is a test pinning an address derived from inputs the separator doesn't change, so the pin — and only the pin — moves. Four so far, in the order CI surfaced them:
0015protocol-contracts/fixtures/ContractInstancePublishedEventData.hex+ its event snapshot0016key-store/src/key_store.test.tsinline snapshots; PXEAddressStore.json+KeyStore.json0017handshake_registry_contract'srecipient_signaturefixture0017— the remaining failureRecipientSignature::verifyopens by binding the returned keys to the address:The fixture's
recipientwas derived under the old separator, so seven of the eightrecipient_signaturetests fail on that line — every one that gets past it.interactive_signature_rejects_wrong_recipientpasses, because it is the one that expects this mismatch. The schnorr signature is over[chain_id, version, registry, eph_pk_x]and never commits to the address, so only the one constant moves:0x1b94108a…d15b→0x1866b3a2…f2c4Cross-check of
0016Rather than take the new values on trust I re-derived all three from the fixtures' own fields, with an independent Poseidon2-BN254 + Grumpkin implementation built from barretenberg's parameters and self-tested against
poseidon2.test.cpp::HashConsistencyCheck. The check that matters is the backwards one — recomputing with the old separator has to reproduce each pinned value exactly, which is what proves the derivation inputs are right:0x0a3120bd…39400x085dc217…a7b3✓ matches0016complete_addresses[0]0x2369ead0…ce440x20c1641e…493a✓ matches0016complete_addresses[1]0x1fc97e4d…ba630x23210e69…05aa✓ matches0016recipient0x1b94108a…d15b0x1866b3a2…f2c4(this PR)The
complete_address_indexreordering in0016is also right: the map is keyed by the address string, and under v30x20c1641e…sorts before0x23210e69…, so thenum:0/num:1values swap against the keys. For the record the serializedCompleteAddresslayout isaddress, npk_m_hash, ivpk.x, ivpk.y, ovpk, tpk, mspk, fbpk, partial_address.I had pushed a narrower version of the PXE fix before picking up
0016; it was wrong — it replaced onlycomplete_addresses[0]'s address, leaving[1]stale and the index map mis-sorted.0016is the correct one and this branch now carries it verbatim.Not verified locally
No test was run here.
nargois not present in this container and rebuilding it is blocked bycargo-binstallfailing to reachindex.crates.io(403 onapi.github.com/graphqlthrough the proxy), and the labs jest workspace needs thelabs-use-localmarker commit that rebuild would produce.labs-patches/bootstrap.sh checkpasses on all 17 patches; the rest is CI's.Created by claudebox · group:
slackbot· requested by Mike (@iAmMichaelConnor) · Slack thread