From 5ffdb0b165a2b22cc99c5cbd5749eb74b415ef49 Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Sat, 28 Mar 2026 20:13:58 +0000 Subject: [PATCH 01/10] Add draft NSM1 structured memo protocol ZIP --- zips/draft-frontiercompute-nsm1.md | 276 +++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 zips/draft-frontiercompute-nsm1.md diff --git a/zips/draft-frontiercompute-nsm1.md b/zips/draft-frontiercompute-nsm1.md new file mode 100644 index 000000000..970cf73d7 --- /dev/null +++ b/zips/draft-frontiercompute-nsm1.md @@ -0,0 +1,276 @@ +ZIP: ??? +Title: Structured Memo Protocol for Application-Layer Attestation (NSM1) +Owners: Frontier Compute +Credits: Zk-nd3r +Status: Draft +Category: Standards Track +Created: 2026-03-28 +License: MIT +Discussions-To: +Pull-Request: + +## Terminology + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", +"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and +"OPTIONAL" in this document are to be interpreted as described in BCP 14 +when, and only when, they appear in all capitals, as shown here. + +## Abstract + +This ZIP specifies a structured memo envelope for protocol events committed to +Zcash shielded transactions. The envelope carries a version byte, event type, +cohort identifier, payload hash, timestamp, optional serial hash, and +human-readable note. It is designed for application protocols that need compact +on-chain commitments while keeping participant-identifying data off-chain. + +This draft is based on the deployed `NSM1` memo protocol currently used by the +Nordic Shield lifecycle attestation system. In that deployment, event payloads +are hashed with BLAKE2b-256 using the personalization string +`NordicShield_`, inserted into an append-only Merkle tree, and periodically +anchored to Zcash using a memo of type `0x09`. + +## Motivation + +Zcash shielded memos are expressive enough to carry structured application +commitments, but the ecosystem lacks a compact convention for representing +typed lifecycle events that can be independently recomputed by external +verifiers. + +Applications that track ownership, deployment, billing, transfer, and exit +events need: + +- deterministic hash construction +- stable event typing +- a memo format that can be parsed without application-specific heuristics +- a way to commit large event histories without writing full plaintext records + to the chain + +This ZIP standardizes the memo structure and event commitment rules used by one +such deployment so that other builders can implement compatible tooling, +verification, and future extensions. + +## Requirements + +An implementation of this ZIP: + +- MUST treat the memo payload as a binary structure before any wallet-specific + memo encoding. +- MUST encode integers in big-endian byte order. +- MUST NOT place participant PII directly in the memo payload. +- MUST derive event payload hashes deterministically from the underlying event + fields. +- MUST preserve event insertion order when deriving Merkle roots. +- MUST allow verifiers to recompute both the event leaf hash and the anchored + root from public artifacts plus application-provided witness data. + +## Specification + +### Memo Envelope + +Before memo encoding, the binary payload format is: + +```text +byte 0 : version = 0x01 +byte 1 : type = 0x01..0x0c +bytes 2..5 : cohort_id = u32 big-endian +bytes 6..37 : payload_hash = 32 bytes +bytes 38..45: timestamp = u64 big-endian unix seconds +bytes 46..77: serial_hash = 32 bytes, or 32 zero bytes when unused +bytes 78..n : note = UTF-8 human-readable note, optional +``` + +For human-readable transport, the memo envelope SHOULD be rendered as: + +```text +NSM1:{type}:{payload} +``` + +where: + +- `NSM1` is the protocol marker +- `{type}` is the two-digit lowercase hexadecimal event type +- `{payload}` is the hexadecimal encoding of the full binary layout above + +### Event Types + +This draft defines the following event type assignments: + +| Type | Name | Payload definition | Status | +| --- | --- | --- | --- | +| `0x01` | `PROGRAM_ENTRY` | `BLAKE2b_32(wallet_hash)` | Deployed | +| `0x02` | `OWNERSHIP_ATTEST` | `BLAKE2b_32(wallet_hash || serial_number)` | Deployed | +| `0x03` | `CONTRACT_ANCHOR` | `BLAKE2b_32(serial_number || contract_sha256)` | Deployed | +| `0x04` | `DEPLOYMENT` | `BLAKE2b_32(serial_number || facility_id || timestamp_be)` | Deployed | +| `0x05` | `HOSTING_PAYMENT` | `BLAKE2b_32(serial_number || month_be || year_be)` | Deployed | +| `0x06` | `SHIELD_RENEWAL` | `BLAKE2b_32(wallet_hash || year_be)` | Deployed | +| `0x07` | `TRANSFER` | `BLAKE2b_32(old_wallet || new_wallet || serial_number)` | Deployed | +| `0x08` | `EXIT` | `BLAKE2b_32(wallet_hash || serial_number || timestamp_be)` | Deployed | +| `0x09` | `MERKLE_ROOT` | raw 32-byte Merkle root | Deployed | +| `0x0A` | `STAKING_DEPOSIT` | `BLAKE2b_32(wallet_hash || amount_zat_be || validator_id)` | Reserved | +| `0x0B` | `STAKING_WITHDRAW` | `BLAKE2b_32(wallet_hash || amount_zat_be)` | Reserved | +| `0x0C` | `STAKING_REWARD` | `BLAKE2b_32(wallet_hash || epoch_be || reward_zat_be)` | Reserved | + +Implementations of the deployed `NSM1` flow currently use the first nine event +types in production. The staking event types are reserved and MUST NOT be +assumed stable until separately activated. + +### Hash Construction + +Unless otherwise specified, event payload hashes use BLAKE2b with: + +- digest length: 32 bytes +- personalization: `NordicShield_` + +The hash input for each event type is defined in the table above. The +`MERKLE_ROOT` event is a special case whose payload hash is the 32-byte Merkle +root itself, without an additional BLAKE2b compression step. + +For event types that carry a serial number, the `serial_hash` memo field MUST +be: + +```text +BLAKE2b_32(serial_number) +``` + +with the same personalization string `NordicShield_`. + +If no serial number is applicable, `serial_hash` MUST be 32 zero bytes. + +### Merkle Tree Commitments + +Applications using this memo protocol SHOULD aggregate event payload hashes into +an append-only binary Merkle tree. For the deployed `NSM1` protocol: + +- each event produces one leaf +- leaves are ordered by insertion sequence +- parent nodes are `BLAKE2b_32(left || right)` +- Merkle node personalization is `NordicShield_MRK` +- if a level has odd cardinality, the final node is duplicated + +An inclusion proof consists of: + +- leaf hash +- sibling hashes +- sibling positions +- derived Merkle root +- anchor transaction identifier +- anchor block height + +### On-Chain Anchoring + +When anchoring a Merkle root to Zcash: + +- the event type MUST be `0x09` +- the payload hash MUST be the raw current Merkle root +- the memo SHOULD be encoded as `NSM1:09:{payload}` + +The deployed `NSM1` implementation broadcasts shielded memo commitments using +`zingo-cli`. The current deployment anchors every 10 events or every 24 hours, +whichever occurs first. + +### Verification Procedure + +To verify a committed event, a verifier: + +1. recomputes the event payload hash from the application fields +2. reconstructs the memo payload and event leaf hash +3. walks the Merkle proof path to derive the root +4. retrieves the referenced anchor transaction +5. confirms that the memo contains the same `0x09` root commitment +6. confirms that the transaction is mined on the intended chain + +## Rationale + +This design separates protocol semantics from wallet transport. + +The binary layout is fixed-width for all critical fields so parsers can extract +event type, cohort identifier, and proof-relevant material without needing to +understand any free-form note text. BLAKE2b-256 is used for compactness and +performance. Personalization strings provide domain separation between event +payload hashing and Merkle internal-node hashing. + +Anchoring Merkle roots rather than full event records minimizes chain load while +preserving independent verifiability. The memo remains short and constant-sized +for the root-commitment case even as the underlying event history grows. + +## Privacy Considerations + +This protocol is intended to avoid writing participant-identifying plaintext +data to chain. Implementations MUST ensure that `wallet_hash`, `serial_hash`, +contract digests, and other memo inputs are derived values rather than directly +identifying customer records. + +The optional note field may leak application metadata if misused. Protocols +using this ZIP SHOULD either omit the note field or constrain it to operational +strings that do not identify participants. + +## Security Considerations + +This protocol provides integrity and auditability, not confidentiality of the +underlying application database. Security depends on: + +- correct construction of event hashes +- correct Merkle insertion ordering +- correct association between proof bundles and the anchored root that covers + them +- correct wallet-side retrieval of the mined memo-bearing transaction + +This ZIP does not address: + +- fraudulent off-chain data entry before hashing +- theft of the key used to authorize anchor transactions +- application-level authorization of transfers or exits + +The deployed `NSM1` stack currently uses single-operator anchor signing, with a +separate FROST migration design under development for threshold authorization of +future root anchors. + +## Backwards Compatibility + +This ZIP codifies the deployed version-`0x01` `NSM1` format. Existing proof +bundles remain valid as long as verifiers preserve the original event hash +construction, Merkle hashing rules, and anchor transaction references. + +Future incompatible memo layouts MUST use a new version byte and SHOULD use a +distinct human-readable protocol marker. + +## Reference Implementation + +Reference implementations are available at: + +- [Frontier-Compute/zec-pay](https://github.com/Frontier-Compute/zec-pay), which implements the deployed `NSM1` memo protocol, Merkle tree maintenance, proof bundle generation, and root anchoring flow. +- [Frontier-Compute/nsm1-verify](https://github.com/Frontier-Compute/nsm1-verify), which provides a standalone Rust and WASM verifier for NSM1 leaf hashes and Merkle proofs. + +In the deployed `zec-pay` implementation: + +- event payload hashes are computed with BLAKE2b-256 and personalization `NordicShield_` +- Merkle internal nodes use personalization `NordicShield_MRK` +- root anchors are transmitted as `NSM1:09:{root}` + +## Test Vectors + +A companion test vector package SHOULD provide: + +- one event hash vector for each deployed event type `0x01` through `0x09` +- the exact input fields used to derive the payload hash +- the expected `leaf_hash` +- the hash personalization strings used + +The deployed `NSM1` implementation publishes those vectors separately as: + +- [Frontier-Compute/zec-pay/TEST_VECTORS.md](https://github.com/Frontier-Compute/zec-pay/blob/main/TEST_VECTORS.md) +- [TEST_VECTORS.md](./TEST_VECTORS.md) + +## Acknowledgements + +This draft draws on the deployed Nordic Shield `NSM1` protocol and the Zcash +shielded memo and Orchard tooling ecosystem. + +## References + +[^zip-guide]: [ZIP guide](https://zips.z.cash/zip-guide). + +[^zec-pay]: [Frontier-Compute/zec-pay](https://github.com/Frontier-Compute/zec-pay). + +[^nsm1-verify]: [Frontier-Compute/nsm1-verify](https://github.com/Frontier-Compute/nsm1-verify). From 59bdfad64d93c63e1c4edec05364a334266985c5 Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Sun, 29 Mar 2026 17:49:06 +0000 Subject: [PATCH 02/10] Privacy section: direct wording --- zips/draft-frontiercompute-nsm1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zips/draft-frontiercompute-nsm1.md b/zips/draft-frontiercompute-nsm1.md index 970cf73d7..33b9aad64 100644 --- a/zips/draft-frontiercompute-nsm1.md +++ b/zips/draft-frontiercompute-nsm1.md @@ -196,7 +196,7 @@ for the root-commitment case even as the underlying event history grows. ## Privacy Considerations -This protocol is intended to avoid writing participant-identifying plaintext +This protocol avoids writing participant-identifying plaintext data to chain. Implementations MUST ensure that `wallet_hash`, `serial_hash`, contract digests, and other memo inputs are derived values rather than directly identifying customer records. From 488723cb38d2707a36c88a721c57e98901edbc7a Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Sun, 29 Mar 2026 19:30:10 +0000 Subject: [PATCH 03/10] Add ZIP 302 relationship, fix repo references, reframe as attestation format --- zips/draft-frontiercompute-nsm1.md | 50 ++++++++++++++++++------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/zips/draft-frontiercompute-nsm1.md b/zips/draft-frontiercompute-nsm1.md index 33b9aad64..43b5c7ff0 100644 --- a/zips/draft-frontiercompute-nsm1.md +++ b/zips/draft-frontiercompute-nsm1.md @@ -18,11 +18,10 @@ when, and only when, they appear in all capitals, as shown here. ## Abstract -This ZIP specifies a structured memo envelope for protocol events committed to -Zcash shielded transactions. The envelope carries a version byte, event type, -cohort identifier, payload hash, timestamp, optional serial hash, and -human-readable note. It is designed for application protocols that need compact -on-chain commitments while keeping participant-identifying data off-chain. +This ZIP specifies an application-layer attestation format for lifecycle events +committed to Zcash shielded transactions. It defines event typing, BLAKE2b hash +construction rules, Merkle tree aggregation, and a verification procedure for +on-chain commitments that keep participant-identifying data off-chain. This draft is based on the deployed `NSM1` memo protocol currently used by the Nordic Shield lifecycle attestation system. In that deployment, event payloads @@ -30,25 +29,36 @@ are hashed with BLAKE2b-256 using the personalization string `NordicShield_`, inserted into an append-only Merkle tree, and periodically anchored to Zcash using a memo of type `0x09`. +## Relationship to ZIP 302 + +This ZIP defines application-layer attestation semantics. The memo container +format is specified separately by ZIP 302 (Structured Memos, PR #638). When +ZIP 302 is deployed, NSM1 attestation payloads SHOULD be encoded as a ZIP 302 +part type. Until then, the binary layout below serves as a transitional +encoding within the raw 512-byte memo field. + +The parts of this ZIP that are independent of the container are: the event type +registry, hash construction rules, Merkle tree aggregation, and the +verification procedure. + ## Motivation -Zcash shielded memos are expressive enough to carry structured application -commitments, but the ecosystem lacks a compact convention for representing -typed lifecycle events that can be independently recomputed by external -verifiers. +Zcash shielded memos can carry structured application commitments, but the +ecosystem lacks a convention for typed lifecycle events that can be +independently recomputed by external verifiers. Applications that track ownership, deployment, billing, transfer, and exit events need: - deterministic hash construction - stable event typing -- a memo format that can be parsed without application-specific heuristics +- a payload format that can be parsed without application-specific heuristics - a way to commit large event histories without writing full plaintext records to the chain -This ZIP standardizes the memo structure and event commitment rules used by one -such deployment so that other builders can implement compatible tooling, -verification, and future extensions. +This ZIP standardizes the event commitment rules used by one such deployment +so that other builders can implement compatible tooling, verification, and +future extensions. ## Requirements @@ -66,9 +76,9 @@ An implementation of this ZIP: ## Specification -### Memo Envelope +### Binary Payload Layout -Before memo encoding, the binary payload format is: +Before memo encoding (or ZIP 302 part encoding), the binary payload is: ```text byte 0 : version = 0x01 @@ -80,7 +90,7 @@ bytes 46..77: serial_hash = 32 bytes, or 32 zero bytes when unused bytes 78..n : note = UTF-8 human-readable note, optional ``` -For human-readable transport, the memo envelope SHOULD be rendered as: +For human-readable transport, the payload SHOULD be rendered as: ```text NSM1:{type}:{payload} @@ -239,10 +249,10 @@ distinct human-readable protocol marker. Reference implementations are available at: -- [Frontier-Compute/zec-pay](https://github.com/Frontier-Compute/zec-pay), which implements the deployed `NSM1` memo protocol, Merkle tree maintenance, proof bundle generation, and root anchoring flow. +- [Frontier-Compute/nsm1](https://github.com/Frontier-Compute/nsm1), which implements the deployed `NSM1` memo protocol, Merkle tree maintenance, proof bundle generation, and root anchoring flow. - [Frontier-Compute/nsm1-verify](https://github.com/Frontier-Compute/nsm1-verify), which provides a standalone Rust and WASM verifier for NSM1 leaf hashes and Merkle proofs. -In the deployed `zec-pay` implementation: +In the deployed `nsm1` implementation: - event payload hashes are computed with BLAKE2b-256 and personalization `NordicShield_` - Merkle internal nodes use personalization `NordicShield_MRK` @@ -259,7 +269,7 @@ A companion test vector package SHOULD provide: The deployed `NSM1` implementation publishes those vectors separately as: -- [Frontier-Compute/zec-pay/TEST_VECTORS.md](https://github.com/Frontier-Compute/zec-pay/blob/main/TEST_VECTORS.md) +- [Frontier-Compute/nsm1/TEST_VECTORS.md](https://github.com/Frontier-Compute/nsm1/blob/main/TEST_VECTORS.md) - [TEST_VECTORS.md](./TEST_VECTORS.md) ## Acknowledgements @@ -271,6 +281,6 @@ shielded memo and Orchard tooling ecosystem. [^zip-guide]: [ZIP guide](https://zips.z.cash/zip-guide). -[^zec-pay]: [Frontier-Compute/zec-pay](https://github.com/Frontier-Compute/zec-pay). +[^nsm1]: [Frontier-Compute/nsm1](https://github.com/Frontier-Compute/nsm1). [^nsm1-verify]: [Frontier-Compute/nsm1-verify](https://github.com/Frontier-Compute/nsm1-verify). From 70be5cf8f8fa555c15ac46828a4f45054f6ef2a4 Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Mon, 30 Mar 2026 12:23:16 -0700 Subject: [PATCH 04/10] rename protocol from NSM1 to ZAP1 --- ...-nsm1.md => draft-frontiercompute-zap1.md} | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) rename zips/{draft-frontiercompute-nsm1.md => draft-frontiercompute-zap1.md} (87%) diff --git a/zips/draft-frontiercompute-nsm1.md b/zips/draft-frontiercompute-zap1.md similarity index 87% rename from zips/draft-frontiercompute-nsm1.md rename to zips/draft-frontiercompute-zap1.md index 43b5c7ff0..5a456f83f 100644 --- a/zips/draft-frontiercompute-nsm1.md +++ b/zips/draft-frontiercompute-zap1.md @@ -1,5 +1,5 @@ ZIP: ??? -Title: Structured Memo Protocol for Application-Layer Attestation (NSM1) +Title: Structured Memo Protocol for Application-Layer Attestation (ZAP1) Owners: Frontier Compute Credits: Zk-nd3r Status: Draft @@ -23,7 +23,7 @@ committed to Zcash shielded transactions. It defines event typing, BLAKE2b hash construction rules, Merkle tree aggregation, and a verification procedure for on-chain commitments that keep participant-identifying data off-chain. -This draft is based on the deployed `NSM1` memo protocol currently used by the +This draft is based on the deployed `ZAP1` memo protocol currently used by the Nordic Shield lifecycle attestation system. In that deployment, event payloads are hashed with BLAKE2b-256 using the personalization string `NordicShield_`, inserted into an append-only Merkle tree, and periodically @@ -33,7 +33,7 @@ anchored to Zcash using a memo of type `0x09`. This ZIP defines application-layer attestation semantics. The memo container format is specified separately by ZIP 302 (Structured Memos, PR #638). When -ZIP 302 is deployed, NSM1 attestation payloads SHOULD be encoded as a ZIP 302 +ZIP 302 is deployed, ZAP1 attestation payloads SHOULD be encoded as a ZIP 302 part type. Until then, the binary layout below serves as a transitional encoding within the raw 512-byte memo field. @@ -93,12 +93,12 @@ bytes 78..n : note = UTF-8 human-readable note, optional For human-readable transport, the payload SHOULD be rendered as: ```text -NSM1:{type}:{payload} +ZAP1:{type}:{payload} ``` where: -- `NSM1` is the protocol marker +- `ZAP1` is the protocol marker - `{type}` is the two-digit lowercase hexadecimal event type - `{payload}` is the hexadecimal encoding of the full binary layout above @@ -121,7 +121,7 @@ This draft defines the following event type assignments: | `0x0B` | `STAKING_WITHDRAW` | `BLAKE2b_32(wallet_hash || amount_zat_be)` | Reserved | | `0x0C` | `STAKING_REWARD` | `BLAKE2b_32(wallet_hash || epoch_be || reward_zat_be)` | Reserved | -Implementations of the deployed `NSM1` flow currently use the first nine event +Implementations of the deployed `ZAP1` flow currently use the first nine event types in production. The staking event types are reserved and MUST NOT be assumed stable until separately activated. @@ -150,7 +150,7 @@ If no serial number is applicable, `serial_hash` MUST be 32 zero bytes. ### Merkle Tree Commitments Applications using this memo protocol SHOULD aggregate event payload hashes into -an append-only binary Merkle tree. For the deployed `NSM1` protocol: +an append-only binary Merkle tree. For the deployed `ZAP1` protocol: - each event produces one leaf - leaves are ordered by insertion sequence @@ -173,9 +173,9 @@ When anchoring a Merkle root to Zcash: - the event type MUST be `0x09` - the payload hash MUST be the raw current Merkle root -- the memo SHOULD be encoded as `NSM1:09:{payload}` +- the memo SHOULD be encoded as `ZAP1:09:{payload}` -The deployed `NSM1` implementation broadcasts shielded memo commitments using +The deployed `ZAP1` implementation broadcasts shielded memo commitments using `zingo-cli`. The current deployment anchors every 10 events or every 24 hours, whichever occurs first. @@ -232,13 +232,13 @@ This ZIP does not address: - theft of the key used to authorize anchor transactions - application-level authorization of transfers or exits -The deployed `NSM1` stack currently uses single-operator anchor signing, with a +The deployed `ZAP1` stack currently uses single-operator anchor signing, with a separate FROST migration design under development for threshold authorization of future root anchors. ## Backwards Compatibility -This ZIP codifies the deployed version-`0x01` `NSM1` format. Existing proof +This ZIP codifies the deployed version-`0x01` `ZAP1` format. Existing proof bundles remain valid as long as verifiers preserve the original event hash construction, Merkle hashing rules, and anchor transaction references. @@ -249,14 +249,14 @@ distinct human-readable protocol marker. Reference implementations are available at: -- [Frontier-Compute/nsm1](https://github.com/Frontier-Compute/nsm1), which implements the deployed `NSM1` memo protocol, Merkle tree maintenance, proof bundle generation, and root anchoring flow. -- [Frontier-Compute/nsm1-verify](https://github.com/Frontier-Compute/nsm1-verify), which provides a standalone Rust and WASM verifier for NSM1 leaf hashes and Merkle proofs. +- [Frontier-Compute/zap1](https://github.com/Frontier-Compute/zap1), which implements the deployed `ZAP1` memo protocol, Merkle tree maintenance, proof bundle generation, and root anchoring flow. +- [Frontier-Compute/zap1-verify](https://github.com/Frontier-Compute/zap1-verify), which provides a standalone Rust and WASM verifier for ZAP1 leaf hashes and Merkle proofs. -In the deployed `nsm1` implementation: +In the deployed `zap1` implementation: - event payload hashes are computed with BLAKE2b-256 and personalization `NordicShield_` - Merkle internal nodes use personalization `NordicShield_MRK` -- root anchors are transmitted as `NSM1:09:{root}` +- root anchors are transmitted as `ZAP1:09:{root}` ## Test Vectors @@ -267,20 +267,20 @@ A companion test vector package SHOULD provide: - the expected `leaf_hash` - the hash personalization strings used -The deployed `NSM1` implementation publishes those vectors separately as: +The deployed `ZAP1` implementation publishes those vectors separately as: -- [Frontier-Compute/nsm1/TEST_VECTORS.md](https://github.com/Frontier-Compute/nsm1/blob/main/TEST_VECTORS.md) +- [Frontier-Compute/zap1/TEST_VECTORS.md](https://github.com/Frontier-Compute/zap1/blob/main/TEST_VECTORS.md) - [TEST_VECTORS.md](./TEST_VECTORS.md) ## Acknowledgements -This draft draws on the deployed Nordic Shield `NSM1` protocol and the Zcash +This draft draws on the deployed Nordic Shield `ZAP1` protocol and the Zcash shielded memo and Orchard tooling ecosystem. ## References [^zip-guide]: [ZIP guide](https://zips.z.cash/zip-guide). -[^nsm1]: [Frontier-Compute/nsm1](https://github.com/Frontier-Compute/nsm1). +[^zap1]: [Frontier-Compute/zap1](https://github.com/Frontier-Compute/zap1). -[^nsm1-verify]: [Frontier-Compute/nsm1-verify](https://github.com/Frontier-Compute/nsm1-verify). +[^zap1-verify]: [Frontier-Compute/zap1-verify](https://github.com/Frontier-Compute/zap1-verify). From 6634cce1ada6c8b1440afd4f6f0d6271e1df5cce Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Wed, 1 Apr 2026 16:56:00 +0000 Subject: [PATCH 05/10] update repo links to zap1, remove Nordic Shield product name --- zips/draft-frontiercompute-zap1.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zips/draft-frontiercompute-zap1.md b/zips/draft-frontiercompute-zap1.md index 5a456f83f..ef0909537 100644 --- a/zips/draft-frontiercompute-zap1.md +++ b/zips/draft-frontiercompute-zap1.md @@ -23,8 +23,7 @@ committed to Zcash shielded transactions. It defines event typing, BLAKE2b hash construction rules, Merkle tree aggregation, and a verification procedure for on-chain commitments that keep participant-identifying data off-chain. -This draft is based on the deployed `ZAP1` memo protocol currently used by the -Nordic Shield lifecycle attestation system. In that deployment, event payloads +This draft is based on the deployed `ZAP1` memo protocol (formerly `NSM1`). In the reference deployment, event payloads are hashed with BLAKE2b-256 using the personalization string `NordicShield_`, inserted into an append-only Merkle tree, and periodically anchored to Zcash using a memo of type `0x09`. @@ -274,7 +273,7 @@ The deployed `ZAP1` implementation publishes those vectors separately as: ## Acknowledgements -This draft draws on the deployed Nordic Shield `ZAP1` protocol and the Zcash +This draft draws on the deployed `ZAP1` protocol (formerly `NSM1`) and the Zcash shielded memo and Orchard tooling ecosystem. ## References From 1c6969e3974a3f7b579ab051d6e2e1fc6007967b Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Fri, 3 Apr 2026 01:33:44 +0000 Subject: [PATCH 06/10] address daira review: rename note->label, separate ZAP1 payload from Zcash memo terminology --- zips/draft-frontiercompute-zap1.md | 38 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/zips/draft-frontiercompute-zap1.md b/zips/draft-frontiercompute-zap1.md index ef0909537..0e3ff19e5 100644 --- a/zips/draft-frontiercompute-zap1.md +++ b/zips/draft-frontiercompute-zap1.md @@ -1,5 +1,5 @@ ZIP: ??? -Title: Structured Memo Protocol for Application-Layer Attestation (ZAP1) +Title: Structured Attestation Protocol for Application-Layer Lifecycle Events (ZAP1) Owners: Frontier Compute Credits: Zk-nd3r Status: Draft @@ -23,18 +23,18 @@ committed to Zcash shielded transactions. It defines event typing, BLAKE2b hash construction rules, Merkle tree aggregation, and a verification procedure for on-chain commitments that keep participant-identifying data off-chain. -This draft is based on the deployed `ZAP1` memo protocol (formerly `NSM1`). In the reference deployment, event payloads +This draft is based on the deployed `ZAP1` attestation protocol (formerly `NSM1`). In the reference deployment, event payloads are hashed with BLAKE2b-256 using the personalization string `NordicShield_`, inserted into an append-only Merkle tree, and periodically -anchored to Zcash using a memo of type `0x09`. +anchored to Zcash using a transaction with type byte `0x09`. ## Relationship to ZIP 302 -This ZIP defines application-layer attestation semantics. The memo container -format is specified separately by ZIP 302 (Structured Memos, PR #638). When +This ZIP defines application-layer attestation semantics. The carrier format +is specified separately by ZIP 302 (Structured Memos, PR #638). When ZIP 302 is deployed, ZAP1 attestation payloads SHOULD be encoded as a ZIP 302 part type. Until then, the binary layout below serves as a transitional -encoding within the raw 512-byte memo field. +encoding within the raw 512-byte shielded memo field. The parts of this ZIP that are independent of the container are: the event type registry, hash construction rules, Merkle tree aggregation, and the @@ -63,10 +63,10 @@ future extensions. An implementation of this ZIP: -- MUST treat the memo payload as a binary structure before any wallet-specific +- MUST treat the attestation payload as a binary structure before any wallet-specific memo encoding. - MUST encode integers in big-endian byte order. -- MUST NOT place participant PII directly in the memo payload. +- MUST NOT place participant PII directly in the attestation payload. - MUST derive event payload hashes deterministically from the underlying event fields. - MUST preserve event insertion order when deriving Merkle roots. @@ -77,7 +77,7 @@ An implementation of this ZIP: ### Binary Payload Layout -Before memo encoding (or ZIP 302 part encoding), the binary payload is: +Before shielded memo encoding (or ZIP 302 part encoding), the binary attestation payload is: ```text byte 0 : version = 0x01 @@ -86,7 +86,7 @@ bytes 2..5 : cohort_id = u32 big-endian bytes 6..37 : payload_hash = 32 bytes bytes 38..45: timestamp = u64 big-endian unix seconds bytes 46..77: serial_hash = 32 bytes, or 32 zero bytes when unused -bytes 78..n : note = UTF-8 human-readable note, optional +bytes 78..n : label = UTF-8 human-readable label, optional ``` For human-readable transport, the payload SHOULD be rendered as: @@ -135,7 +135,7 @@ The hash input for each event type is defined in the table above. The `MERKLE_ROOT` event is a special case whose payload hash is the 32-byte Merkle root itself, without an additional BLAKE2b compression step. -For event types that carry a serial number, the `serial_hash` memo field MUST +For event types that carry a serial number, the `serial_hash` payload field MUST be: ```text @@ -148,7 +148,7 @@ If no serial number is applicable, `serial_hash` MUST be 32 zero bytes. ### Merkle Tree Commitments -Applications using this memo protocol SHOULD aggregate event payload hashes into +Applications using this attestation protocol SHOULD aggregate event payload hashes into an append-only binary Merkle tree. For the deployed `ZAP1` protocol: - each event produces one leaf @@ -183,7 +183,7 @@ whichever occurs first. To verify a committed event, a verifier: 1. recomputes the event payload hash from the application fields -2. reconstructs the memo payload and event leaf hash +2. reconstructs the attestation payload and event leaf hash 3. walks the Merkle proof path to derive the root 4. retrieves the referenced anchor transaction 5. confirms that the memo contains the same `0x09` root commitment @@ -195,7 +195,7 @@ This design separates protocol semantics from wallet transport. The binary layout is fixed-width for all critical fields so parsers can extract event type, cohort identifier, and proof-relevant material without needing to -understand any free-form note text. BLAKE2b-256 is used for compactness and +understand any free-form label text. BLAKE2b-256 is used for compactness and performance. Personalization strings provide domain separation between event payload hashing and Merkle internal-node hashing. @@ -207,11 +207,11 @@ for the root-commitment case even as the underlying event history grows. This protocol avoids writing participant-identifying plaintext data to chain. Implementations MUST ensure that `wallet_hash`, `serial_hash`, -contract digests, and other memo inputs are derived values rather than directly +contract digests, and other payload inputs are derived values rather than directly identifying customer records. -The optional note field may leak application metadata if misused. Protocols -using this ZIP SHOULD either omit the note field or constrain it to operational +The optional `label` field may leak application metadata if misused. Protocols +using this ZIP SHOULD either omit the `label` field or constrain it to operational strings that do not identify participants. ## Security Considerations @@ -241,14 +241,14 @@ This ZIP codifies the deployed version-`0x01` `ZAP1` format. Existing proof bundles remain valid as long as verifiers preserve the original event hash construction, Merkle hashing rules, and anchor transaction references. -Future incompatible memo layouts MUST use a new version byte and SHOULD use a +Future incompatible payload layouts MUST use a new version byte and SHOULD use a distinct human-readable protocol marker. ## Reference Implementation Reference implementations are available at: -- [Frontier-Compute/zap1](https://github.com/Frontier-Compute/zap1), which implements the deployed `ZAP1` memo protocol, Merkle tree maintenance, proof bundle generation, and root anchoring flow. +- [Frontier-Compute/zap1](https://github.com/Frontier-Compute/zap1), which implements the deployed `ZAP1` attestation protocol, Merkle tree maintenance, proof bundle generation, and root anchoring flow. - [Frontier-Compute/zap1-verify](https://github.com/Frontier-Compute/zap1-verify), which provides a standalone Rust and WASM verifier for ZAP1 leaf hashes and Merkle proofs. In the deployed `zap1` implementation: From aa39becff83234c37b0a8510a3082fd593f90634 Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Fri, 3 Apr 2026 20:22:23 +0000 Subject: [PATCH 07/10] add governance types to event table, fix staking field order --- zips/draft-frontiercompute-zap1.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/zips/draft-frontiercompute-zap1.md b/zips/draft-frontiercompute-zap1.md index 0e3ff19e5..32a04c0ac 100644 --- a/zips/draft-frontiercompute-zap1.md +++ b/zips/draft-frontiercompute-zap1.md @@ -81,7 +81,7 @@ Before shielded memo encoding (or ZIP 302 part encoding), the binary attestation ```text byte 0 : version = 0x01 -byte 1 : type = 0x01..0x0c +byte 1 : type = 0x01..0x0f bytes 2..5 : cohort_id = u32 big-endian bytes 6..37 : payload_hash = 32 bytes bytes 38..45: timestamp = u64 big-endian unix seconds @@ -117,12 +117,15 @@ This draft defines the following event type assignments: | `0x08` | `EXIT` | `BLAKE2b_32(wallet_hash || serial_number || timestamp_be)` | Deployed | | `0x09` | `MERKLE_ROOT` | raw 32-byte Merkle root | Deployed | | `0x0A` | `STAKING_DEPOSIT` | `BLAKE2b_32(wallet_hash || amount_zat_be || validator_id)` | Reserved | -| `0x0B` | `STAKING_WITHDRAW` | `BLAKE2b_32(wallet_hash || amount_zat_be)` | Reserved | -| `0x0C` | `STAKING_REWARD` | `BLAKE2b_32(wallet_hash || epoch_be || reward_zat_be)` | Reserved | +| `0x0B` | `STAKING_WITHDRAW` | `BLAKE2b_32(wallet_hash || amount_zat_be || validator_id)` | Reserved | +| `0x0C` | `STAKING_REWARD` | `BLAKE2b_32(wallet_hash || amount_zat_be || epoch_be)` | Reserved | +| `0x0D` | `GOVERNANCE_PROPOSAL` | `BLAKE2b_32(wallet_hash || proposal_id || proposal_hash)` | Reserved | +| `0x0E` | `GOVERNANCE_VOTE` | `BLAKE2b_32(wallet_hash || proposal_id || vote_commitment)` | Reserved | +| `0x0F` | `GOVERNANCE_RESULT` | `BLAKE2b_32(wallet_hash || proposal_id || result_hash)` | Reserved | Implementations of the deployed `ZAP1` flow currently use the first nine event -types in production. The staking event types are reserved and MUST NOT be -assumed stable until separately activated. +types in production. The staking and governance event types are reserved and +MUST NOT be assumed stable until separately activated. ### Hash Construction From cd38c84d468ee5c20354cbd593e81d35978b874c Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Wed, 8 Apr 2026 09:44:00 -0700 Subject: [PATCH 08/10] fix zip header fields, add BCP14 ref, qualify memo terms, define field sizes --- zips/draft-frontiercompute-zap1.md | 54 ++++++++++++++++++------------ 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/zips/draft-frontiercompute-zap1.md b/zips/draft-frontiercompute-zap1.md index 32a04c0ac..49fd738af 100644 --- a/zips/draft-frontiercompute-zap1.md +++ b/zips/draft-frontiercompute-zap1.md @@ -6,8 +6,8 @@ Status: Draft Category: Standards Track Created: 2026-03-28 License: MIT -Discussions-To: -Pull-Request: +Discussions-To: +Pull-Request: ## Terminology @@ -31,7 +31,7 @@ anchored to Zcash using a transaction with type byte `0x09`. ## Relationship to ZIP 302 This ZIP defines application-layer attestation semantics. The carrier format -is specified separately by ZIP 302 (Structured Memos, PR #638). When +is specified separately by ZIP 302 [^zip-0302] (Structured Memos, PR #638). When ZIP 302 is deployed, ZAP1 attestation payloads SHOULD be encoded as a ZIP 302 part type. Until then, the binary layout below serves as a transitional encoding within the raw 512-byte shielded memo field. @@ -64,7 +64,7 @@ future extensions. An implementation of this ZIP: - MUST treat the attestation payload as a binary structure before any wallet-specific - memo encoding. + shielded memo encoding. - MUST encode integers in big-endian byte order. - MUST NOT place participant PII directly in the attestation payload. - MUST derive event payload hashes deterministically from the underlying event @@ -77,7 +77,7 @@ An implementation of this ZIP: ### Binary Payload Layout -Before shielded memo encoding (or ZIP 302 part encoding), the binary attestation payload is: +Before shielded shielded memo encoding (or ZIP 302 part encoding), the binary attestation payload is: ```text byte 0 : version = 0x01 @@ -128,11 +128,26 @@ types in production. The staking and governance event types are reserved and MUST NOT be assumed stable until separately activated. ### Hash Construction +nField sizes for hash inputs: + +- `wallet_hash`: 32 bytes (application-derived identifier) +- `serial_number`: 32 bytes +- `contract_sha256`: 32 bytes +- `facility_id`: 32 bytes (zero-padded if shorter) +- `timestamp_be`: u64 big-endian (8 bytes) +- `month_be`: u16 big-endian (2 bytes) +- `year_be`: u16 big-endian (2 bytes) +- `amount_zat_be`: u64 big-endian (8 bytes) +- `epoch_be`: u32 big-endian (4 bytes) +- `validator_id`: 32 bytes +- `proposal_id`: 32 bytes +- `proposal_hash`, `vote_commitment`, `result_hash`: 32 bytes each +- `old_wallet`, `new_wallet`: 32 bytes each Unless otherwise specified, event payload hashes use BLAKE2b with: - digest length: 32 bytes -- personalization: `NordicShield_` +- personalization: `NordicShield_` (13 bytes, zero-padded to 16 bytes per BLAKE2b spec) The hash input for each event type is defined in the table above. The `MERKLE_ROOT` event is a special case whose payload hash is the 32-byte Merkle @@ -175,7 +190,7 @@ When anchoring a Merkle root to Zcash: - the event type MUST be `0x09` - the payload hash MUST be the raw current Merkle root -- the memo SHOULD be encoded as `ZAP1:09:{payload}` +- the shielded memo field SHOULD be encoded as `ZAP1:09:{payload}` The deployed `ZAP1` implementation broadcasts shielded memo commitments using `zingo-cli`. The current deployment anchors every 10 events or every 24 hours, @@ -189,7 +204,7 @@ To verify a committed event, a verifier: 2. reconstructs the attestation payload and event leaf hash 3. walks the Merkle proof path to derive the root 4. retrieves the referenced anchor transaction -5. confirms that the memo contains the same `0x09` root commitment +5. confirms that the shielded memo field contains the same `0x09` root commitment 6. confirms that the transaction is mined on the intended chain ## Rationale @@ -203,7 +218,7 @@ performance. Personalization strings provide domain separation between event payload hashing and Merkle internal-node hashing. Anchoring Merkle roots rather than full event records minimizes chain load while -preserving independent verifiability. The memo remains short and constant-sized +preserving independent verifiability. The shielded memo field remains short and constant-sized for the root-commitment case even as the underlying event history grows. ## Privacy Considerations @@ -226,7 +241,7 @@ underlying application database. Security depends on: - correct Merkle insertion ordering - correct association between proof bundles and the anchored root that covers them -- correct wallet-side retrieval of the mined memo-bearing transaction +- correct wallet-side retrieval of the mined shielded-memo-bearing transaction This ZIP does not address: @@ -252,7 +267,7 @@ distinct human-readable protocol marker. Reference implementations are available at: - [Frontier-Compute/zap1](https://github.com/Frontier-Compute/zap1), which implements the deployed `ZAP1` attestation protocol, Merkle tree maintenance, proof bundle generation, and root anchoring flow. -- [Frontier-Compute/zap1-verify](https://github.com/Frontier-Compute/zap1-verify), which provides a standalone Rust and WASM verifier for ZAP1 leaf hashes and Merkle proofs. +- [Frontier-Compute/zap1-verify](https://github.com/Frontier-Compute/zap1-verify) [^zap1-verify], which provides a standalone Rust and WASM verifier for ZAP1 leaf hashes and Merkle proofs. In the deployed `zap1` implementation: @@ -269,20 +284,17 @@ A companion test vector package SHOULD provide: - the expected `leaf_hash` - the hash personalization strings used -The deployed `ZAP1` implementation publishes those vectors separately as: +The deployed `ZAP1` implementation [^zap1] publishes those vectors separately as: - [Frontier-Compute/zap1/TEST_VECTORS.md](https://github.com/Frontier-Compute/zap1/blob/main/TEST_VECTORS.md) -- [TEST_VECTORS.md](./TEST_VECTORS.md) - -## Acknowledgements - -This draft draws on the deployed `ZAP1` protocol (formerly `NSM1`) and the Zcash -shielded memo and Orchard tooling ecosystem. +- [TEST_VECTORS.md](https://github.com/Frontier-Compute/zap1/blob/main/TEST_VECTORS.md) ## References -[^zip-guide]: [ZIP guide](https://zips.z.cash/zip-guide). +[^BCP14]: [Information on BCP 14 -- "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words"](https://www.rfc-editor.org/info/bcp14) + +[^zip-0302]: [ZIP 302: Standardized Memo Field Format](https://zips.z.cash/zip-0302) -[^zap1]: [Frontier-Compute/zap1](https://github.com/Frontier-Compute/zap1). +[^zap1]: [Frontier-Compute/zap1: ZAP1 attestation protocol reference implementation](https://github.com/Frontier-Compute/zap1) -[^zap1-verify]: [Frontier-Compute/zap1-verify](https://github.com/Frontier-Compute/zap1-verify). +[^zap1-verify]: [Frontier-Compute/zap1-verify: standalone Rust and WASM verifier for ZAP1 proofs](https://github.com/Frontier-Compute/zap1-verify) From 33bccfdf8470b72e3463946b84d3d617a30eb018 Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Wed, 8 Apr 2026 09:55:52 -0700 Subject: [PATCH 09/10] fix typos: remove doubled shielded, stray prefix --- zips/draft-frontiercompute-zap1.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zips/draft-frontiercompute-zap1.md b/zips/draft-frontiercompute-zap1.md index 49fd738af..84c636cb6 100644 --- a/zips/draft-frontiercompute-zap1.md +++ b/zips/draft-frontiercompute-zap1.md @@ -77,7 +77,7 @@ An implementation of this ZIP: ### Binary Payload Layout -Before shielded shielded memo encoding (or ZIP 302 part encoding), the binary attestation payload is: +Before shielded memo encoding (or ZIP 302 part encoding), the binary attestation payload is: ```text byte 0 : version = 0x01 @@ -128,7 +128,7 @@ types in production. The staking and governance event types are reserved and MUST NOT be assumed stable until separately activated. ### Hash Construction -nField sizes for hash inputs: +Field sizes for hash inputs: - `wallet_hash`: 32 bytes (application-derived identifier) - `serial_number`: 32 bytes From 0537ce5606e1e1700b1278285cdceef8ffbd8397 Mon Sep 17 00:00:00 2001 From: Zk-nd3r Date: Sat, 23 May 2026 19:48:57 +0700 Subject: [PATCH 10/10] docs: clarify ZAP1 protocol rationale --- zips/draft-frontiercompute-zap1.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/zips/draft-frontiercompute-zap1.md b/zips/draft-frontiercompute-zap1.md index 84c636cb6..938c552ab 100644 --- a/zips/draft-frontiercompute-zap1.md +++ b/zips/draft-frontiercompute-zap1.md @@ -46,6 +46,23 @@ Zcash shielded memos can carry structured application commitments, but the ecosystem lacks a convention for typed lifecycle events that can be independently recomputed by external verifiers. +Exposing Zcash state and actions to agents is straightforward. A REST or +GraphQL endpoint can be wrapped as an MCP server in a small amount of code, and +wallet-layer MCP implementations can expose balances, signing workflows, sync +state, and transaction construction. These surfaces share one property: the +consumer must trust the server response. If the backend is wrong, compromised, +or unavailable later, the agent has no independent receipt it can hand to a +third party for verification. + +ZAP1 closes that gap. It exposes no balances and moves no value. It produces a +receipt: a typed event committed to a BLAKE2b Merkle tree, with the root +anchored in Zcash memo data, verifiable from the public schema, proof material, +and chain anchor without trusting the issuer's server. + +The distinction is categorical. Tool servers answer "what does this backend say +right now?" ZAP1 answers "what happened, provable later to another verifier?" +The protocol exists for the proof artifact, not for tool exposure. + Applications that track ownership, deployment, billing, transfer, and exit events need: