# Note Attestation Specification The goal of this specification is to enable users of shielded tokens to prove, in a permissionless manner, that their shielded tokens have not interacted with tokens present on a blacklist. Multiple blacklists are supported and the specification makes no restrictions on who can be a blacklist provider. # Token contract changes ## Shield tagging Every shield interaction that generates a note will produce a unique `shieldId: u32` value. i.e. a counter incrementing from 0. This is tracked by the token contract via a storage variable `numShields: u32` ## The `TokenNote` data structure The current `TokenNote` struct contains the following: ``` struct TokenNote { // the amount of tokens in the note amount: SafeU120, // the provider of secrets for the nullifier. The owner (recipient) to ensure that the note // can be privately spent. When nullifier secret and encryption private key is same // we can simply use the owner for this one. owner: AztecAddress, // randomness of the note to hide contents. randomness: Field, // the note header (contract_address, nonce, storage_slot) // included in the note such that it becomes part of encrypted logs for later use. header: NoteHeader, } ``` This specification would add a `PartitionTable` struct as a member of `TokenNote` ## PartitionTable A `PartitionTable` struct contains the following: 1. `sheilds`: A fixed-size list of `{shieldId: u32, value: SafeU120}` tuples 2. `attestations`: a fixed-size list of `attestor: AztecAddress` 3. A `blockNumber` of the youngest deposit in the list 4. `isTableCleared: bool`, describes whether the list of shields has been cleared ## Join-split interactions When combining notes, the following rules are applied: * If `isTableCleared = true` for any input note, `isTableCleared = true` for all output notes and `shields` is empty * If `isTableCleared = false` for all input notes, the `shields` entries for all output notes are consistent with the `sheilds` entries for all input notes * If `blockNumber` for all output notes is the max value of `blockNumber` for all input notes * The `attestations` list for output notes is the set *intersection* of input note `attestations` Note: the above rules do not perfectly preserve information. It is possible to come up with more advanced rules that drop less information (e.g. supporting partially cleared partition tables), but at the cost of higher complexity. Note: the reference implementation should provide an unconstrained function that describes how the input `shields` list maps to the output `shields` list. A basic solution will work for the MVP (e.g. a simple `for` loop that populates output note `shield` entries until a target note value has been reached) ## Unshielding When calling `unshield`, the list of `attestations` in the note is optionally broadcast via events. This will require modifying the `unshield` interface to add a boolean that describes whether these events should be broadcast. ## Token contract interface changes ``` fn request_attestation(note: TokenNote, attestor: AztecAddress) -> bool; fn has_attestation(note: TokenNote, attestors: [AztecAddress]) -> bool; ``` If `request_attestation` returns true, an attestation is added to `TokenNote::attestations` The `has_attestation` method can be used by contracts to validate whether a given note posesses an attestation from a list of attestors. # Attestor Contract Interface: ``` pub fn add_to_blacklist(token_address: AztecAddress, deposit_id: u32); pub fn remove_from_blacklist(token_address: AztecAddress, deposit_id: u32); fn request_attestation(table: PartitionTable, attestor: AztecAddress) -> bool; ``` The Attestor contract tracks blacklisted deposit IDs. Attestations are dispensed if a note's partition table does not intersect with the blacklist. The blacklist must be accessible from private functions. A possible solution is to store the blacklist as an indexed merkle tree. Race conditions that arise from updating the tree can be deferred and considered out-of-scope for the MPV. The `request_attestation` method requires a set-non-intersection check that is of independent interest and should be implemented as a 3rd party library.