Repository navigation
feat(bridge): derive, keep and recover private USDCx mint nonces (veil #166 port) - #85
Open
iamalwaysuncomfortable wants to merge 8 commits into
Open
iamalwaysuncomfortable wants to merge 8 commits into
iamalwaysuncomfortable wants to merge 8 commits into
Conversation
…ounter-loss guidance
This branch has not been deployed
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.
Python port of Veil PR ProvableHQ/veil#166 (with the #208 follow-up fixes folded in): a private xReserve USDC → USDCx deposit from the bridge's own Aleo account derives, keeps and recovers its secret nonce the way the Shield wallet does, so
quote → execute → wait → completeneeds nosecret_nonceanywhere. An explicitsecret_nonce=still wins on every verb and touches no store.What it adds
aleo_bridge.private_mint— Shield'sshielded-usdcx-secret-noncederivation (Poseidon8.hash_to_scalar([wrapper_x, network_domain, view_key, counter]), BHP256 recipient commitment), verified byte-exact against the six shield-core vectors vendored from Veil (tests/fixtures/shield-core-private-mint.json, with_source).PrivateMintIdentity(itsreprnever shows the scalar), a three-methodPrivateMintIdentityStoreprotocol,FilePrivateMintIdentityStore(atomic 0600 writes, a.counterfile consumed before derivation so a failed derivation or save never recycles a counter, and a.lockinode via the journal's existing cross-processflock) andMemoryPrivateMintIdentityStore(explicit opt-in only).reserve_identity,peek_secret_nonce,find_identity, andrecover_identity, which re-derives counters from zero when the store lacks a commitment, so losing the identities file costs a scan (about one second at the default 10,000-counter limit), not the funds. One resolver,resolve_secret_nonce, holds the whole policy and every verb calls it.Bridge(private_mint_identities=…)— optional. When aFileCheckpointStoreis bound (from_profile, orBRIDGE_CHECKPOINT_DIR), the default is a hidden.private-mint-identities.jsoninside the journal directory, which the journal's*.jsonlisting already skips. No store and no nonce is aConfigurationErrornaming both fixes, never a quiet0scalaron a funds-moving path.Lifecycle.
executereserves an identity right before the deposit (not at quote time, so price refreshes cost nothing andPlanand the checkpoint format are unchanged);resumereads the commitment back out of the checkpointed hook data andcompleteout of the attested payload, look it up or re-derive it, and refuse before any RPC on a malformed hook or a stored identity naming another recipient. A private quote stays read-only: it previews the next counter's nonce when it can and prices with a placeholder otherwise;executeis the gate. Tier-2xreserve.private_mint(att, recipient)resolves the same way;eth.deposit_usdckeeps its explicit scalar parameter.Agent tools / MCP.
secret_nonceis optional on quote/execute/resume/complete; the pre-checks accept a derivable bridge;how_to_fixnames both fixes.Docs. README private-recipient section rewritten caller-first (derived default, then "bring your own nonce"), recovery notes, the examples (the private-recipient and journal-recovery scripts treat
BRIDGE_MINT_SECRET_NONCEas an override), and the generated agent guide.Design calls
walletPreparedDeposit/privateMintNonceInputpath (no Aleo wallet adapter in Python), Veil'scircleoption object, the external-commitment path, and lock-directory / dead-process reclamation (oneflockinstead). The #208 corrections are satisfied by design: no in-memory default store, no stale-lock races, reservation immediately before the deposit.Plan,Receipt,Checkpoint,Progress) are unchanged; newBridgearguments are trailing keywords;checkpoint._counter_lock/FileCheckpointStore._writekeep their names over the shared_fshelpers.quote/private_mintdefaults changed from"0scalar"toNone, and a deposit made undereth.deposit_usdc's unchanged0scalardefault still completes without a nonce (the lookup recognises that commitment first), so pre-existing Tier-2 pairings keep working.Validation
bridge-sdk: 1265 hermetic tests pass (-m "not slow"), pyright strict 0 errors,codegen/gen_context.py --checkclean. New:test_private_mint_derivation.py(KATs, domains, malformed hooks, redacted repr),test_private_mint_store.py(monotonic counters, 0600 + atomic files, counter survives losing the identities file, consumed before a failed derivation, two instances on one path, 8-thread concurrency, peek, scan recovery and its limit, recipient mismatch, malformed files raise instead of resetting, scan speed),test_private_mint_resolver.py,test_private_mint_lifecycle.py(execute/quote/resume/complete/Tier-2 incl. the0scalarcompatibility case); agent tests updated.test_testnet_evm_xreserve_deposit_derivedbeside the explicit-nonce case — 3 Sepolia USDC deposited with nosecret_nonce, the executing client dropped, a new client recovered the checkpoint from disk, Circle attested,private_mintcompleted with the derived nonce and delivered (passed in 21m29s on 2026-10-29;.private-mint-identities.json+.countercreated at 0600 in the live journal directory).