docs(notes): clarify purpose, serial number, and nullifier terms#3016
docs(notes): clarify purpose, serial number, and nullifier terms#3016BrianSeong99 wants to merge 2 commits into
Conversation
c161041 to
d6eed41
Compare
Address the outstanding items from the Notes page review and align terminology with the current (v0.15) protocol: - Purpose & scope: enumerate the three roles of a note (asset transfer, account notification via note presence, and account state change via the note's storage) rather than implying notes are only for asset transfers. - Serial number: replace the one-line explanation with the commitment/nullifier framing, introducing both concepts before describing how the serial number guarantees uniqueness and protects privacy. Uses "commitment" terminology throughout. - Nullifier: define each term in the nullifier formula (SERIAL_NUM, SCRIPT_ROOT, STORAGE_COMMITMENT, ASSET_COMMITMENT, METADATA, ATTACHMENTS_COMMITMENT), grounded in Nullifier::new, and fix a remaining "note's hash" reference to "note's commitment". - Note tag: correct the SWAP tag example from "2 bits" to "1 bit" of the note's type, reflecting the NoteType 1-bit encoding introduced in v0.15.0. The original "define vault_hash" item is obsolete: the nullifier formula was rewritten and vault_hash no longer appears on the page. Note tag composition is already documented under Note discovery.
d6eed41 to
ad32821
Compare
|
|
||
| - **Transferring assets** between accounts. | ||
| - **Notifying an account**, through the mere presence of a note addressed to it. | ||
| - **Changing an account's state**, through the data in the note's [storage](#storage), which the consuming account's code can act on. |
There was a problem hiding this comment.
Nit: This makes it sound like notes transfer data to an account passively, and the account acts on them. But the note script is usually the one that "acts on the data in the storage".
I'd also suggest replacing "changing an account's state" with "invoking an account's public procedures" which better captures the idea that a note cannot just arbitrarily change an account, but must go through the account's interface - so note and account both have something to say in this process.
| - **Notifying an account**, through the mere presence of a note addressed to it. | ||
| - **Changing an account's state**, through the data in the note's [storage](#storage), which the consuming account's code can act on. |
There was a problem hiding this comment.
I'm not sure that points 2 and 3 are really distinct use cases. Notifying an account essentially only happens when the note is consumed, in which case this is covered by point 3.
| - **Commitment**: a commitment to the `Note`'s data (including the serial number) that can be stored publicly without revealing the note's details. It represents the note in the notes database, which is how private notes are recorded on-chain. | ||
| - **Nullifier**: a value derived from the `Note`'s data (including the serial number) that uniquely marks the note as consumed, without allowing the note's data to be reconstructed. |
There was a problem hiding this comment.
- We recently renamed "note commitment" to "note ID".
- A nullifier is also a commitment to the note, just purposefully computed differently than the note ID, so that one isn't derivable from the other.
- It doesn't feel ideal that we introduce these important note concepts under "serial number". Seems like we should restructure this to introduce things so they build on top of each other. Serial number is lower in the hierarchy than note ID and nullifier. Maybe we should first introduce serial number and then explain its purpose in the note ID and nullifier section (and linking to this from here so there is a reference). I think a good part of this is already explained in
#note-nullifier-ensuring-private-consumption, so I'd suggest extending this to mention that the serial number helps ensure uniqueness.
| With that context, the serial number serves two purposes: | ||
|
|
||
| - **Uniqueness**: the added randomness ensures each note's commitment is unique even when two notes hold identical assets, scripts, and inputs, preventing collisions in the notes database. | ||
| - **Privacy**: the serial number is the secret link between a note's commitment and its nullifier. If an attacker learns the serial number of a private note, they can recompute its nullifier from the commitment and detect when the note is spent — linking its creation to its consumption. The serial number of a private note must therefore be kept secret; if leaked, privacy is compromised even when the rest of the note's data remains hidden. |
There was a problem hiding this comment.
the serial number is the secret link between a note's commitment and its nullifier
I don't find this accurate, as the link between note ID and nullifier is that the same inputs are used, just hashed together differently. The serial number is just one part of this.
If an attacker learns the serial number of a private note, they can recompute its nullifier from the commitment
I'm not sure this works, or maybe I don't understand it. A leaked serial number could compromise privacy, but, afaict, only if certain other key properties are also known like storage and assets commitment. Without these, the nullifier cannot be computed and guessing or deriving them should be pretty hard in most circumstances.
| - To compute the nullifier, one must know all components of the `Note`: serial_num, script_root, storage_commitment, assets_commitment, metadata, and attachments_commitment. | ||
|
|
||
| That means if a `Note` is private and the operator stores only the note's hash, only those with the `Note` details know if this `Note` has been consumed already. Zcash first [introduced](https://zcash.github.io/orchard/design/nullifiers.html#nullifiers) this approach. | ||
| That means if a `Note` is private and the operator stores only the note's commitment, only those with the `Note` details know if this `Note` has been consumed already. Zcash first [introduced](https://zcash.github.io/orchard/design/nullifiers.html#nullifiers) this approach. |
There was a problem hiding this comment.
| That means if a `Note` is private and the operator stores only the note's commitment, only those with the `Note` details know if this `Note` has been consumed already. Zcash first [introduced](https://zcash.github.io/orchard/design/nullifiers.html#nullifiers) this approach. | |
| That means if a `Note` is private and the operator stores only the note's ID, only those with the `Note` details know if this `Note` has been consumed already. Zcash first [introduced](https://zcash.github.io/orchard/design/nullifiers.html#nullifiers) this approach. |
Addresses #1825.
Summary
Implements the outstanding items from the Notes page review (
docs/src/note.md), re-scoped against the current state of the page and aligned with current (v0.15) protocol terminology.Changes
SERIAL_NUM,SCRIPT_ROOT,STORAGE_COMMITMENT,ASSET_COMMITMENT,METADATA,ATTACHMENTS_COMMITMENT), grounded inNullifier::new(crates/miden-protocol/src/note/nullifier.rs), each cross-linked to its section.NoteTypeencoding introduced in v0.15.0.Scope notes
vault_hashno longer appears on the page (nowASSET_COMMITMENTet al.). The re-scoped item defines the formula's actual terms, which were previously undefined.