# DelayedPublicMutable
DelayedPublicMutable (formerly SharedMutable) is a state variable pattern in Aztec.nr used for having dynamic state shared between the public and private context. DelayedPublicMutable exists because of the nature of using public state in private functions (aka specific ZK circuits) - without a special pattern, we can't guarantee dynamic public state is valid during execution in the private context.
The solution DelayedPublicMutable presents is to provide a scheduled change mechanism with mandatory delays that ensures values read in the private context cannot be changed before transaction inclusion. This enables a predictable window for which private proofs remain valid by trading immediate mutability for guaranteed validity of asynchonous execution in the private context.
## Inclusion Window
Say the delay timespan is 1 hour, and a state change was scheduled 30 minutes ago. This means the time horizon is 30 minutes, and any transaction reading this value in the private context will need to include a `include_by_timestamp` 30 minutes from now. If no value change has been scheduled, it is only safe to set the `include_by_timestamp` up to (in this case) 1 hour from transaction submission. `include_by_timestamp` is computed by calling DelayedPublicMutable and cannot be mutated by the user.
This presents a challenge for balancing authoritative control and user experience, specifically with respect to a token blacklist. If the delay for a new value to be set is too short, users will end up setting short-dated `include_by_timestamp` values. If blockspace is competitive, this could result in transactions being dropped when the inclusion time elapses. Conversely, if a malicious actor has tokens and (for instance) Circle applies their address (or other identifying qualities like ZK Passport IDK) to a blacklist, doing so through a DelayedPublicMutable schedule will indicate to the malicious entity that they must immediately exfiltrate the tokens to avoid the impending seizure. Fuctionally, assuming the value of the malicious transaction is large enough, the malicious entity will simply set a very high transaction fee to ensure the transaction is mined before the scheduled update to the blacklist occurs.
**For this reason, DelayedPublicMutable is most likely an impotent security measure as a urgent blacklist against hackers.** With a shorter delay span set, it is however likely sufficient for imposing longer term sanctions against specific entities, though again it cannot prevent exfiltration of funds with any efficacy.
### Mitigations
Whitelisting rather than blacklisting may be one way to gain authoritative control over funds. While this doesn't solve any component of the delay itself, Circle could be 100% sure that all actors within the ecosystem had performed some level of authentication based on the demands of the whitelist (ZK Passport, first-party attestations of KYC, etc)
A highly undesirable but perfectly secure solution would be to use DelayedPublicMutable in tandem with a PublicMutable freeze function. The appeal of DelayedPublicMutable is to maintan a sparse merkle tree of blacklisted addresses, and each transaction would prove non-inclusion in this tree in perfect secrecy. We could choose to expose the fact we are dealing with the (USDC) contract by enqueuing a public call that checks that a PublicMutable `frozen` variable is set to `false`. In the event of systemic risk that the DelayedPublicMutable function cannot immediately mitigate, the public `freeze` variable could be temporarily set to `true` until the scheduled value change comes into effect. Of course, this paralyzes the entire token ecosystem and is again highly undesirable, however if regulatory scrutiny is unhappy with DelayedPublicMutable security, this solution provides the tools to satiate any LEO request to stop funds. There may be a more intelligent construction around this pattern that I am not thinking of also - this is my thoughts so far
## Privacy considerations
Use of a DelayedPublicMutable state will include a validity check `include_by_timestamp`. If the validity check is for 24 hours from now, it can be inferred that the transaction interacted with *some* contract that has a 24 hour DelayedPublicMutable setting. Additionally, if a scheduled state change has occured and there are (for example) 15 hours left, it can become much easier to identity that a specific transaction likely interacted with a certain contract. This is because the delay is known publicly, so it will be obvious when the timestamps line up like so.
This can be mitigated in a couple of ways:
1. Setting arbitrary `include_by_timestamp` values, so long as they are within the time horizon. You'll still leak that you're using some contract with a DelayedPublicMutable, and the set of all possible contracts this timestamp could apply to is limited, however this adds some obscurity compared to setting the `include_by_timestamp` at the maximum possible value
2. Sharing a DelayedPublicMutable value across contracts. Specifically for blacklists, if all token contracts call to a blacklist contract sharing delays & state, then the set of possible contracts for any `include_by_timestamp` becomes much larger. If USDC does not share a blacklist with any other contracts and a `include_by_timestamp` matches the delay perfectly, it may be clear that a transaction is dealing with USDC. However, if USDC and 99 other tokens share the same DelayedPublicMutable blacklist variable, there is no intrinsic proof as to which token is being called when a `include_by_timestamp` matches the delay.
### Additional Reading
[DelayedPublicMutable (SharedMutable) ReadMe](https://github.com/AztecProtocol/aztec-packages/blob/next/docs/versioned_docs/version-v1.1.2/developers/reference/smart_contract_reference/storage/shared_state.md#sharedmutable)
[DelayedPublicMutable Code](https://github.com/AztecProtocol/aztec-packages/tree/a7e30e7312344d20d68c46e9de44e9a201465c63/noir-projects/noir-protocol-circuits/crates/types/src/delayed_public_mutable)
[Example Implementation of DelayedPublicMutable](https://github.com/AztecProtocol/aztec-packages/blob/a7e30e7312344d20d68c46e9de44e9a201465c63/noir-projects/noir-contracts/contracts/app/auth_contract/src/main.nr#L23)
### Nullifier Idea
0. On USDC on Aztec, there exists a centralized entity `Circle` that has the capability to receive encrypted logs on aztec
1. In order for `User` to use USDC on Aztec, they must call `register`
a. Samples a random `secret` value
b. `User` sends encrypted log of `nullifier_note` `{ secret, pubkey }` to `Circle`
c. `User` stores `nullifier_note` in a note for themselves - the secret is bound to the address
2. When `User` wants to transact with USDC they must prove nullifier non inclusion
a. Compute the nullifier by hashing `nullifier_note` (`nullifier = Hash(secret, pubkey)`)
b. Check nullifier non-inclusion in the private context with `context.historical_header.prove_nullifier_non_inclusion(nullifier)`
c. Continue with normal token logic
3. When `Circle` wants to blacklist `User`, they can emit the nullifier
a. `User`'s `nullifier_note` was also broadcast to `Circle` so they can select the User they want to ban
b. Compute the nullifier by hashing `nullifier_note` (`nullifier = Hash(secret, pubkey)`)
c. Emit the nullifier with `context.push_nullifier(nullifier)`
4. Once `Circle` has emitted the nullifier, `User` will be permanently unable to construct a private proof that satisfies `context.historical_header.prove_nullifier_non_inclusion(nullifier)`
a. This is almost instant and undetectable - if a malicious actor is the sequencer for that block, they could theoretically front run this but that happens on EVM too so it is as effective as a transparent/public blockchain blacklist
b. This is an irrevocable action - `User` will never be able to use this address again and funds will be lost to this address. There should potentially be additional measures to recover funds and redress blacklisting with new addresses
#### Summarized
Registration:
- Users generate a secret value when first using USDC
- This is a permissionless, 1-time action
- They are forced to send this secret to Circle via encrypted logs
- User's address is permanently bound to this secret
Normal Usage:
- Every USDC transaction must prove "my secret hasn't been nullified"
- This happens privately - no one knows which secret is being checked
Blacklisting:
- Circle publishes the nullifier of the banned user's secret
- That user can never again prove their secret is valid
- Effect is immediate and permanent
- Nullifiers are indistinguishable - they could be from any action on the entire network