> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xpectrum.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Provenance

> Commit-first reveal, verifiable from public data

Xpectrum's trust model is verifiable. A collection's provenance hash is committed on-chain, by the creator's own wallet, before mint opens. Anyone can later re-derive that hash from public data and check it. Neither the platform nor the creator can alter a frozen collection without leaving permanent, machine-checkable evidence.

This is what lets an Xpectrum collection do a delayed reveal without asking buyers to trust anyone.

## Why commit-first

A fair NFT drop has two opposing requirements: buyers must not be able to read which token IDs are rare during the mint (or they snipe them), but they must be able to confirm afterward that the rarity was not rearranged once the rare IDs were known.

Commit-first resolves both:

<Steps>
  <Step title="Commit">
    Before mint opens, the creator computes the provenance hash locally and writes it on-chain with `set_provenance_hash(hash)`. This is a one-way write. From this point the token-to-trait assignment is locked.
  </Step>

  <Step title="Mint">
    The rarity-revealing per-token metadata stays held back during the mint. Buyers cannot read which IDs are rare.
  </Step>

  <Step title="Reveal">
    The creator publishes the byte-exact metadata the hash was computed from. The collection flips to revealed.
  </Step>

  <Step title="Verify (anyone, forever)">
    Recompute the hash from the now-public metadata and compare it to `get_provenance_hash()`. A match proves the assignment is the one committed before mint.
  </Step>
</Steps>

## The hash

The provenance hash is a 64-character lowercase hex string, stored on the collection contract:

```
set_provenance_hash(hash: string)   // one-way, owner only
get_provenance_hash(): string       // read by anyone; "" until set
```

It is constructed by concatenating the SHA-256 of each input, in a fixed canonical order, then hashing the result:

```
input = sha256(0.json) || ... || sha256((N-1).json)
        || sha256(collection.json)
        || sha256(trait layers, sorted by (trait_slug, value_slug))
        || sha256(referenced token images, ascending token id, deduped)
        || sha256(referenced animation assets, ascending token id, deduped)
hash  = sha256(input)
```

Key rules that make it verifiable:

* **N is `max_supply`, not `total_minted`.** Every token JSON must exist before the hash can be set, so a collection cannot be frozen with metadata missing.
* Hashes are over the **exact stored bytes**. No re-serialization, no field stripping.
* `ipfs://` media is not byte-hashed (the CID inside the token JSON is already a content hash). `https://` media cannot appear in a frozen collection at all.
* Avatar and banner are deliberately excluded; they are cosmetic and may be refreshed without breaking provenance.

The full canonical algorithm is part of the [Metadata Standard](/standards/metadata).

## Verification flow

An indexer or any third party verifies a collection like this:

1. Read `get_provenance_hash()`. An empty string means not yet committed (no badge).
2. If a `collection.contract_address` is recorded, confirm it equals the deploying contract. A mismatch rejects the collection.
3. Recompute the hash from the public metadata per the canonical construction.
4. Match **and** `mutability == "frozen_by_provenance"` shows **Provenance Verified**.
5. A mismatch shows a **Provenance Mismatch** warning.

Because step 3 runs entirely on public data, you do not have to trust Xpectrum to trust the result. The [xpress](/developers/xpress) CLI implements exactly this check (`xpress verify <collection_address>`).

<Note>
  Provenance covers source bytes. Composed pixel output is not hashed, because compositor implementations can differ; verifying a composed render's pixels requires a stable compositor spec, which is a future extension.
</Note>
