From e8735e42ca9c6037cbbb36988015347ca8857ece Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Tue, 12 May 2026 18:11:02 -0300 Subject: [PATCH] update --- docs/specs.md | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/docs/specs.md b/docs/specs.md index db386c68..759d85f9 100644 --- a/docs/specs.md +++ b/docs/specs.md @@ -182,22 +182,6 @@ impl Commitment { } ``` -Two special constants are derived from the default account and the null account ID `[0; 32]`: - -```rust -/// DUMMY_COMMITMENT = Commitment::new(&AccountId([0; 32]), &Account::default()) -/// Concretely: SHA256(COMMITMENT_PREFIX || [0]*32 || [0]*32 || [0]*16 || [0]*16 || SHA256([])) -pub const DUMMY_COMMITMENT: Commitment = Commitment([ - 55, 228, 215, 207, 112, 221, 239, 49, 238, 79, 71, 135, 155, 15, 184, 45, 104, 74, 51, 211, - 238, 42, 160, 243, 15, 124, 253, 62, 3, 229, 90, 27, -]); - -pub const DUMMY_COMMITMENT_HASH: [u8; 32] = [ - 250, 237, 192, 113, 155, 101, 119, 30, 235, 183, 20, 84, 26, 32, 196, 229, 154, 74, 254, 249, - 129, 241, 118, 39, 41, 253, 141, 171, 184, 71, 8, 41, -]; -``` - ### Nullifier A private account's commitment is nullified each time the account's state is updated. There are two methods for computing a nullifier: @@ -239,7 +223,7 @@ impl Nullifier { ### Nullifier public key derivation -The nullifier public key is derived from the nullifier secret key via a pure hash function (no elliptic-curve operation): +The nullifier public key is derived from the nullifier secret key via a pure hash function: $$\mathsf{Npk} = \mathsf{SHA256}(\text{"LEE/keys"} \;||\; \mathsf{nsk} \;||\; [7] \;||\; [0; 23])$$ @@ -692,6 +676,32 @@ The `CommitmentSet` exposes: The `NullifierSet` is a plain ordered set. + +### Dummy commitment and dummy commitment hash + +Two special constants are derived from the default account and the null account ID `[0; 32]`: + +```rust +/// DUMMY_COMMITMENT = Commitment::new(&AccountId([0; 32]), &Account::default()) +/// Concretely: SHA256(COMMITMENT_PREFIX || [0]*32 || [0]*32 || [0]*16 || [0]*16 || SHA256([])) +pub const DUMMY_COMMITMENT: Commitment = Commitment([ + 55, 228, 215, 207, 112, 221, 239, 49, 238, 79, 71, 135, 155, 15, 184, 45, 104, 74, 51, 211, + 238, 42, 160, 243, 15, 124, 253, 62, 3, 229, 90, 27, +]); + +pub const DUMMY_COMMITMENT_HASH: [u8; 32] = [ + 250, 237, 192, 113, 155, 101, 119, 30, 235, 183, 20, 84, 26, 32, 196, 229, 154, 74, 254, 249, + 129, 241, 118, 39, 41, 253, 141, 171, 184, 71, 8, 41, +]; +``` + +`DUMMY_COMMITMENT` is the commitment of the default account (`Account::default()`) under the null account ID (`[0; 32]`). It is not a real user account: no keys exist that could spend it, so it can never be nullified. + +At genesis, the `CommitmentSet` is initialized by inserting `DUMMY_COMMITMENT` as its first entry. This bootstraps the Merkle tree before any real private accounts exist and gives the set a well-defined root from the very first state. Because the Merkle tree hashes each leaf as `SHA256(value)`, the root of a tree containing only `DUMMY_COMMITMENT` is `SHA256(DUMMY_COMMITMENT)` — which is exactly `DUMMY_COMMITMENT_HASH`. As a result, `DUMMY_COMMITMENT_HASH` is permanently present in the `CommitmentSet`'s `root_history` from genesis onward. + +**Role in initialization nullifiers.** Every nullifier submitted in a `PrivacyPreservingTransaction` must be paired with a `CommitmentSetDigest`. For update nullifiers this is the Merkle root that was current when the sender computed their membership proof. For **init nullifiers** — emitted when a private account is created for the first time (`PrivateAuthorizedInit`, `PrivateUnauthorized`, `PrivatePdaInit`) — no prior commitment exists to be spent, so there is no natural Merkle root to cite. Rather than special-casing this in the sequencer's acceptance logic, init nullifiers uniformly use `DUMMY_COMMITMENT_HASH` as their digest. Since `DUMMY_COMMITMENT_HASH` is always in `root_history`, the standard `root_history.contains(digest)` check accepts them without any extra branching — the same validation path covers both init and update nullifiers. + + ## Built-in programs NSSA v0.3 supports the following built-in programs, loaded at genesis. They are immutable and identified by unique `ProgramId` values.