Standard Trait Definition for Commitment-Based Private Metadata (Encrypted NFTs)
By Xenitron, Bogachev
- Idea
- Draft
- Accepted
- CAB vote
- Recommended
- Activation
- Ratified
Abstract
This SIP proposes a minimal, composable trait interface for “Encrypted NFTs” (eNFTs): NFTs that commit on-chain to a private off-chain payload (“private metadata”) while keeping the payload itself off-chain. The standard defines:
- A public commitment interface,
- An optional owner-gated envelope descriptor for wallet user experience.
- Indexer-friendly event conventions.
This enables interoperable private-metadata NFT patterns across contracts, wallets, marketplaces, and indexers without requiring consensus changes.
Introduction
“Encrypted metadata / private metadata” NFTs on Stacks are currently implemented as project-specific patterns. This fragmentation makes it difficult for wallets, marketplaces, and indexers to support such NFTs uniformly.
This SIP standardizes a minimal interface for commitment-based private metadata on SIP-009 NFTs:
- A public commitment (hash) to the payload (or ciphertext), enabling anyone to verify integrity after reveal.
- An optional owner-gated envelope descriptor to guide wallet user experience (e.g., show “Reveal” only to the owner).
- A recommended event format so indexers can detect updates efficiently.
Relationship to SIP-009
This trait is designed to be implemented alongside SIP-009-compliant NFT contracts, not as a replacement. An eNFT contract implements SIP-009 for ownership and transfer, and additionally implements this trait to expose commitment-based private metadata.
Specification
1. Terminology
- Payload: The private off-chain data (JSON, image, encrypted blob, etc.).
- Ciphertext: An encrypted payload (still considered “payload bytes” for commitment purposes).
- Commitment: A hash over the payload bytes (often ciphertext bytes) recorded on-chain.
- Envelope: A small off-chain descriptor used for UX/access (e.g., retrieval URI, encrypted key blob, signed URL descriptor).
- Reveal: Off-chain delivery of payload/envelope to the user; the client verifies integrity by comparing hash(payload_bytes) to the on-chain commitment.
- Algo ID: An integer identifier that indicates how the commitment hash is computed.
- Version: A monotonically increasing version number for commitment/envelope encoding.
- Token-id: The SIP-009 NFT token identifier (
uint). Each token-id uniquely identifies a single NFT within a contract.
2. Commitment Semantics
Implementations must expose a commitment for a given token-id.
- The commitment must be computed exactly according to the declared algorithm id.
- The commitment must be stable: the same payload bytes must produce the same commitment.
- This SIP does not mandate a single algorithm, but recommends:
algo = u0=> SHA-256 over raw payload bytes
Algorithm Registry (Informative)
| Algo ID | Algorithm | Notes |
|---|---|---|
| u0 | SHA-256 | Recommended default |
| u1-u99 | Reserved | For future standardization |
| u100+ | Application-defined | Projects may define custom algorithms |
Wallet implementation guidance: Wallets and indexers are not required to support all algorithm ids. A conforming wallet may support only u0 (SHA-256) and display a warning or informational notice for tokens using unrecognized algorithms. The registry enables organic ecosystem convergence without requiring a new SIP for each algorithm.
Notes
- If the payload is JSON, implementers should treat the committed object as raw bytes of a canonical encoding chosen by the application (this SIP does not standardize canonicalization). Consumers must verify against the exact bytes they receive on reveal.
3. Trait Interface (Clarity)
To make “optional” functionality actually optional in Clarity, this SIP defines two traits:
- A required commitment trait (baseline interoperability).
- An optional owner-envelope trait (wallet UX extension).
Contracts may implement the baseline trait alone, or both traits.
3.1 Required Trait: Commitment
(define-trait enft-commitment-trait
(
;; Public: returns the commitment to the private payload (often ciphertext bytes)
(get-private-commitment (uint)
(response
(tuple
(commitment (buff 32)) ;; hash of payload bytes
(algo uint) ;; algorithm id (e.g., u0 = sha256)
(mime (optional (string-ascii 64))) ;; e.g. "application/json", "image/png"
(size (optional uint)) ;; payload size in bytes (optional)
(commitment-version uint) ;; commitment scheme version
)
uint
)
)
)
)
3.2 Optional Trait: Owner-Gated Envelope (Wallet UX Extension)
(define-trait enft-owner-envelope-trait
(
;; user experience oriented: returns an owner-gated envelope descriptor.
;; Implementations SHOULD check ownership for consistent wallet UX.
(get-owner-envelope (uint)
(response
(tuple
(envelope-uri (string-ascii 256)) ;; retrieval location (NOT a secrecy guarantee)
(envelope-hash (buff 32)) ;; integrity check for envelope blob/response
(algo uint) ;; algorithm id for envelope-hash
(envelope-version uint) ;; envelope scheme version
)
uint
)
)
)
)
Normative guidance
- Contracts that claim eNFT support must implement
enft-commitment-trait. - Contracts may implement
enft-owner-envelope-traitto provide a standardized “Reveal” UX path. - Wallets/indexers should treat the presence of
enft-owner-envelope-traitas an optional capability.
3.3 Error Codes (Recommended)
Implementations may choose their own error codes. This SIP recommends:
err u404=> token-id not found / no commitment seterr u401=> not authorized forget-owner-envelope(only relevant ifenft-owner-envelope-traitis implemented)
4. Events (Indexer Conventions)
When a private-metadata commitment is set or updated, contracts should emit a print event with a predictable structure:
(print {
notification: "enft-update",
token-id: token-id,
commitment: commitment,
algo: algo,
commitment-version: commitment-version
})
If an envelope descriptor is set/updated, contracts may emit:
(print {
notification: "enft-envelope-update",
token-id: token-id,
envelope-hash: envelope-hash,
algo: algo,
envelope-version: envelope-version
})
Notes
- Events are intended for indexers/wallets discovery and user interface updates.
envelope-uriis intentionally excluded from the event for safety; wallets should fetch it via the read-only function if needed.- Indexers should treat these events as hints and verify by reading the latest on-chain state as required.
Backwards Compatibility
This SIP introduces no breaking changes. It is additive and does not modify existing SIP-009 NFT contracts. Projects can implement these traits alongside existing token URI / metadata patterns. Wallets and indexers can support eNFTs incrementally.
Security Considerations
Read-only visibility and “owner gating”
get-owner-envelope ownership checks are primarily for wallet UX consistency, not cryptographic secrecy. Read-only calls can be simulated by any party running a node; therefore, confidentiality must not rely solely on on-chain gating.
If the envelope or payload must remain private, it should be protected off-chain via:
- encryption (e.g., encrypt payload/key per owner), and/or
- access control (signed challenges, bearer tokens, short-TTL URLs).
Integrity and server non-equivocation
Assuming collision-resistant hash functions, the on-chain commitment ensures the server cannot swap the underlying private payload after minting without being detected. Clients must verify hash(payload_bytes) == commitment after reveal.
Phishing / malicious URIs
Wallets should treat envelope URIs as untrusted input and apply standard URL safety practices (origin warnings, link previews sandboxing, and user confirmation flows where appropriate).
MIME type validation
The mime field is informational and does not instruct clients to execute content. Clients should validate MIME types before processing payloads and should reject executable types (e.g., application/x-executable, application/x-msdownload) by default. This follows standard content-security practices.
Reference Implementation (Informative)
A reference contract can implement:
- a mapping
token-id -> commitment tuple - optionally a mapping
token-id -> envelope tuple - setters restricted to contract-defined roles (e.g., token owner or authorized operator)
printevents as specified above
Related Work (Informative)
Commitments and commit–reveal schemes are widely used across blockchains to prevent equivocation. Some NFT ecosystems support “encrypted metadata” patterns, but these are often application-specific and lack a shared interface for wallets/indexers.
To the best of our knowledge, Stacks lacks a minimal, interoperable trait and event convention for commitment-anchored private metadata on SIP-009 NFTs; this SIP defines such a standard in a composable, non-consensus, and implementation-agnostic manner.
Activation
No consensus changes are required. This SIP is considered Active when all of the following conditions are met before Bitcoin block height (H₀ + 12,960), where H₀ is the Bitcoin block height at the time this SIP is merged, and 12,960 blocks represents approximately 3 months:
-
A reference trait contract implementing this specification is deployed on Stacks mainnet.
-
At least one production NFT contract on mainnet implements the trait(s) exactly as specified in this SIP.
-
At least one ecosystem integration — indexer, wallet, or marketplace — demonstrates consumption of the interface, proving interoperability independent of the authors.
A trait that follows this specification will be made available on mainnet upon status update to activation-in-progress, and its deployed address will be recorded here.
Until activation, the SIP remains Draft, and implementers may ship experimental contracts under the proposed interface.
References
[1] SIP-009
SIP-038: Standard Trait Definition for Commitment-Based Private Metadata (Encrypted NFTs)
Preamble
SIP Number: 038
Title: Standard Trait Definition for Commitment-Based Private Metadata (Encrypted NFTs)
Authors: Xenitron nortinex@gmail.com, Bogachev ogres2009anton@gmail.com
Status: Draft
Consideration: Technical
Type: Standard
Created: 2026-01-10
License: CC0-1.0
Sign-off:
Layer: Trait
Discussions-To: https://forum.stacks.org/t/encrypted-nfts-on-stacks-a-standard-trait-for-commitment-based-private-layers-enft/18560
Copyright
This SIP is made available under the terms of the CC0-1.0 license. This SIP’s copyright is waived to the extent possible under law.
Introduction
“Encrypted metadata / private metadata” NFTs on Stacks are currently implemented as project-specific patterns. This fragmentation makes it difficult for wallets, marketplaces, and indexers to support such NFTs uniformly.
This SIP standardizes a minimal interface for commitment-based private metadata on SIP-009 NFTs:
- A public commitment (hash) to the payload (or ciphertext), enabling anyone to verify integrity after reveal.
- An optional owner-gated envelope descriptor to guide wallet user experience (e.g., show “Reveal” only to the owner).
- A recommended event format so indexers can detect updates efficiently.
Relationship to SIP-009
This trait is designed to be implemented alongside SIP-009-compliant NFT contracts, not as a replacement. An eNFT contract implements SIP-009 for ownership and transfer, and additionally implements this trait to expose commitment-based private metadata.
Goals
- Define a reusable trait for commitment-based private metadata for eNFTs.
- Make private-layer patterns discoverable and composable for wallets/indexers.
- Keep the standard minimal, additive, and backward-compatible.
Non-Goals
- Full on-chain confidentiality (not achievable in a public read-only model).
- Mandating a specific storage network, encryption scheme, or reveal flow.
- Defining a full game/puzzle “answer verification” protocol (out of scope).
Note on encryption flexibility: This SIP intentionally does not mandate a specific encryption scheme. Wallets and indexers interact only with the commitment layer — they verify hash(payload) == on-chain commitment and never perform decryption. Decryption occurs off-chain between the application and the asset owner, outside the trait scope. Different projects require different threat models (server-assisted reveal vs. client-side decryption with embedded key blob vs. proxy re-encryption). To prevent fragmentation, implementers using any non-default algorithm id (other than u0) must publish a stable, publicly available algorithm specification. Wallets may support only u0 (SHA-256) and treat unknown algorithm ids as unsupported for verification while still supporting discovery.
Relationship to SIP-009
This trait is designed to be implemented alongside SIP-009-compliant NFT contracts, not as a replacement. An eNFT contract implements SIP-009 for ownership and transfer, and additionally implements this trait to expose commitment-based private metadata.
Goals
- Define a reusable trait for commitment-based private metadata for eNFTs.
- Make private-layer patterns discoverable and composable for wallets/indexers.
- Keep the standard minimal, additive, and backward-compatible.
Non-Goals
- Full on-chain confidentiality (not achievable in a public read-only model).
- Mandating a specific storage network, encryption scheme, or reveal flow.
- Defining a full game/puzzle “answer verification” protocol (out of scope).
Note on encryption flexibility: This SIP intentionally does not mandate a specific encryption scheme. Wallets and indexers interact only with the commitment layer — they verify hash(payload) == on-chain commitment and never perform decryption. Decryption occurs off-chain between the application and the asset owner, outside the trait scope. Different projects require different threat models (server-assisted reveal vs. client-side decryption with embedded key blob vs. proxy re-encryption). To prevent fragmentation, implementers using any non-default algorithm id (other than u0) must publish a stable, publicly available algorithm specification. Wallets may support only u0 (SHA-256) and treat unknown algorithm ids as unsupported for verification while still supporting discovery.
zadao.ai