# URMA V0 — normative protocol specification

Document revision: 0.8 · 2026-10-07 · SPDX-License-Identifier: CC0-1.0

## Contents

- [1. Authority and status](#1-authority-and-status)
- [2. Scope and semantic families](#2-scope-and-semantic-families)
- [3. Roles, secrets and dependencies](#3-roles-secrets-and-dependencies)
- [4. Common byte conventions](#4-common-byte-conventions)
- [5. Private canonical record](#5-private-canonical-record)
  - [5.1 Fragmentation and representational bound](#51-fragmentation-and-representational-bound)
  - [5.2 Layout](#52-layout)
  - [5.3 Cryptographic construction](#53-cryptographic-construction)
  - [5.4 Validation and reconstruction](#54-validation-and-reconstruction)
- [6. Offline private-object container and independent recovery](#6-offline-private-object-container-and-independent-recovery)
- [7. Public record layouts](#7-public-record-layouts)
  - [7.1 Atomic text, reply, identity profile and avatar](#71-atomic-text-reply-identity-profile-and-avatar)
  - [7.2 Constants, byte conventions and geometry](#72-constants-byte-conventions-and-geometry)
  - [7.3 Kind 07: public data part](#73-kind-07-public-data-part)
  - [7.4 Shared child-reference entry](#74-shared-child-reference-entry)
  - [7.5 Kind 08: public leaf manifest](#75-kind-08-public-leaf-manifest)
  - [7.6 Kind 09: public root manifest](#76-kind-09-public-root-manifest)
  - [7.7 Author proof, membership and rejection](#77-author-proof-membership-and-rejection)
  - [7.8 Completeness and independent recovery](#78-completeness-and-independent-recovery)
- [8. Canonical Taproot publication profile](#8-canonical-taproot-publication-profile)
  - [8.1 Transaction and key roles](#81-transaction-and-key-roles)
  - [8.2 Script and commitment](#82-script-and-commitment)
  - [8.3 Author proof](#83-author-proof)
  - [8.4 Networks and discovery](#84-networks-and-discovery)
- [9. Private-object invariants and implementation boundaries](#9-private-object-invariants-and-implementation-boundaries)
- [10. Security model](#10-security-model)
- [11. Versioning and licensing](#11-versioning-and-licensing)
- [12. Conformance and completion](#12-conformance-and-completion)
- [13. Primary specifications](#13-primary-specifications)
- [14. Decision traceability](#14-decision-traceability)
- [15. Document revisions](#15-document-revisions)

## 1. Authority and status

This is the single normative URMA specification. MUST, MUST NOT and REQUIRED express conformance
requirements. Application documents cannot override this document.

V0 is a new wire format. No compatibility, implicit migration, marker alias,
fallback decoder or cryptographic equivalence with previous experiments is
specified.

Application profiles, products and services are outside this protocol. Profile
interoperability is separate from URMA conformance, and the protocol never
depends on a product or profile interpreter. A separate non-normative whitepaper
presents the protocol scientifically; it adds no rules. The revision history of
this document is in §15.

## 2. Scope and semantic families

URMA defines writing, verification and recovery of:

1. Encrypted private objects containing arbitrary original bytes. Private text,
   images, documents, audio and video use the same private-object format.
   Content type is encrypted metadata.
2. Public signed text. Its author is the key authorizing the Taproot reveal;
   a detached application signature MUST NOT be added as a second author proof.
3. Generic public signed multipart objects containing arbitrary bytes. Their
   bounded root → leaves → data graph is defined in §7.2–7.8. Payload meaning
   and application profile validation remain outside the protocol.
4. Atomic public profile records carrying an eight-byte profile identifier and
   opaque bytes, defined in §7.1.2. Payload meaning and profile validation
   remain outside the protocol.

Public text kinds 02/04/05/0A/0B, avatar kind 06 and profile record kind 0C are
atomic. They use the single Taproot profile in §8, without fragmentation,
reassembly or size-based transport selection. Atomic public records are at most
32,768 bytes including headers. Multipart records 07/08/09 are at most 262,144
bytes (256 KiB) including headers. A multipart **object** has the separate bound
in §7.2. Clients MUST count bytes, not displayed characters.

The protocol accepts arbitrary public bytes and assigns them no meaning; what
an application accepts or displays is outside it. A reference to external
media preserves the reference, not the media.

Private objects may span their full representable canonical chunk count.
Resource policies may refuse work but MUST NOT redefine protocol validity.

## 3. Roles, secrets and dependencies

An archive root is exactly 32 uniformly random bytes. Every object under that
root is recoverable with that root. Compartments use independent roots. V0
defines no recipients, key wrapping, invitations, revocation or root rotation.

The public author is a BIP 340 x-only secp256k1 public key. It identifies a
pseudonymous identity in the selected chain context, not a globally registered
name. Funding, private recovery and public authorship are different roles.
The author key and the funding key MAY be the same key; separate keys are not
required. The archive root remains a separate, independently generated secret;
nothing in this section permits deriving it from, or using it as, any other key.
V0 does not purport to detect or prohibit a third party reusing underlying key
material.

A mnemonic, QR or encrypted client backup MUST recover the raw root exactly.
None is required for interoperable recovery. A wallet seed, publisher journal,
original filename, implementation database or founder service MUST NOT be a
private recovery prerequisite.

Data sources, chain consensus and retained history remain dependencies. A
central index, username registry, canonical feed or mandatory operator relay
MUST NOT be required. Replaceable indexes may supply candidates, not authority.

## 4. Common byte conventions

Offsets are zero-based. Lengths are bytes. Integers are unsigned little-endian
unless explicitly stated otherwise. Addition, multiplication, ceiling division
and offsets MUST be checked for overflow before allocation or I/O.

The four marker bytes are ASCII URMA, hex 55 52 4d 41. Version is a separate
one-byte unsigned field; V0 encodes 00. No terminator follows a marker or string.

| Offset | Length | Field |
| ---: | ---: | --- |
| 0 | 4 | URMA marker |
| 4 | 1 | Version, 00 |
| 5 | 1 | Record/container kind |
| 6 | 2 | Flags, zero unless a defined kind explicitly assigns bits |

Kind values below are hexadecimal; all V0 flags are zero.

| Kind | Encoding | Carrier |
| --- | --- | --- |
| 01 | Private canonical record | Taproot reveal or offline container |
| 02 | Public plain post | Taproot reveal |
| 03 | Private-object container | Offline only |
| 04 | Public reply | Taproot reveal |
| 05 | Public profile | Taproot reveal |
| 06 | Public avatar | Taproot reveal |
| 07 | Public multipart data part | Taproot reveal |
| 08 | Public multipart leaf manifest | Taproot reveal |
| 09 | Public multipart root manifest | Taproot reveal |
| 0A | Public structured Wire post | Taproot reveal |
| 0B | Public structured Wire reply | Taproot reveal |
| 0C | Public atomic profile record | Taproot reveal |

No other kind or flag is allocated.

Unknown versions, unallocated kinds and nonzero reserved flags MUST be rejected
as unsupported encodings; they MUST NOT be parsed under a guessed layout.
Malformed instances of an allocated encoding are invalid. Neither result is a
complete authenticated object.

## 5. Private canonical record

### 5.1 Fragmentation and representational bound

Let C = 32,768 original bytes per chunk and L be the original byte length.
Nonempty objects have N = ceil(L / C), with 1 <= N <= 2^32 - 1.
An index i satisfies 0 <= i < N. Chunk i contains
n = min(C, L - i*C) original bytes. All but the last contain C bytes.

The count and index are u32. Length is u64, additionally bounded by
N*C and the count relation. The maximum representable original length is

140,737,488,322,560 bytes = (2^32 - 1) * 32,768 = 2^47 - 32,768.

There is no smaller normative private-object policy ceiling. Empty private
objects are not encoded by this layout. A client limit, insufficient funds or
local capacity refusal MUST be reported separately from invalid object data.

Every new encryption generates an independent OS-random 32-byte object ID.
Each index is encrypted once under that ID. Resume MUST retain the original
encrypted bytes. Reencrypting, including after snapshot restoration, requires
a fresh object ID. RNG failure is outside the construction's security guarantee.

The public count is the real count. Dummy chunks, size classes, cover modes
and power-of-two object padding are absent. Only the last record's unused
plaintext capacity is randomly padded.

### 5.2 Layout

Every canonical private record is exactly 32,928 bytes.

| Offset | Length | Field |
| ---: | ---: | --- |
| 0 | 8 | Common header; kind 01, flags 0000 |
| 8 | 32 | Random object ID |
| 40 | 16 | Keyed discovery tag |
| 56 | 4 | Index i, u32 |
| 60 | 4 | Real total count N, u32 |
| 64 | 16 | Canonical AES counter IV |
| 80 | 32,816 | Ciphertext |
| 32,896 | 32 | HMAC-SHA256 tag |

The first 64 bytes are the public authenticated header. The decrypted body is:

| Body offset | Length | Field |
| ---: | ---: | --- |
| 0 | 32 | SHA-256 of the complete original bytes |
| 32 | 8 | Original length L, u64 |
| 40 | 4 | Private content-type hint, u32 |
| 44 | 4 | Reserved metadata flags, zero |
| 48 | n | Original chunk bytes |
| 48 + n | 32,768 - n | OS-random padding |

Content-type hints: 0 opaque bytes, 1 text, 2 image, 3 audio, 4 video.
They describe the original bytes; they neither transform them nor authorize
execution. Text encoding or codec inference by a client MUST NOT alter recovery.
Other hint values are unsupported in V0. All chunks of an object MUST agree
on the authenticated digest, length, count, content type and metadata flags.

Original embedded metadata remains within the original encrypted bytes.
Filename, identity, GPS and capture time are not additional public fields.
The count leaks `(N-1)*C < L <= N*C`.

### 5.3 Cryptographic construction

Use SHA-256, HMAC-SHA256, HKDF-SHA256 and AES-256 in CTR mode. The HKDF labels
below are exact ASCII bytes, without NUL or newline. Keys are raw bytes, not
passwords, hexadecimal text or mnemonic strings.

```text
PRK = HKDF-Extract-SHA256(salt = object_id, IKM = archive_root)
Kenc = HKDF-Expand-SHA256(PRK, "URMA/V0/private/content", 32)
Kmac = HKDF-Expand-SHA256(PRK, "URMA/V0/private/authentication", 32)
tag  = HKDF-Expand-SHA256(PRK, "URMA/V0/private/discovery", 16)
IV   = big_endian_u64(i) || zero[8]
ciphertext = AES-256-CTR(Kenc, IV, body)
MAC = HMAC-SHA256(Kmac, public_header || IV || ciphertext)
```

HKDF-Extract is HMAC with salt as HMAC key and the root as message.
CTR encrypts the initial 128-bit big-endian counter, XORs the resulting
keystream with the body, and increments that entire counter by one per block.
No cipher padding is used. Internal random record padding is plaintext data
covered by encryption and authentication. The 32,816-byte body consumes 2,051
AES blocks; adjacent index ranges start 2^64 blocks apart.

Every implementation uses this construction; portable recovery and negative
vectors are mandatory conformance evidence (§12).

### 5.4 Validation and reconstruction

A reader MUST:

1. Check exact record length, common header, nonzero count and index bounds.
2. Derive the object's keys and tag locally and compare the derived tag with the
   stored discovery tag. A record whose stored tag differs is unrelated to this
   root: it MUST NOT be accepted for the archive even if its MAC would verify.
   A matching tag selects a candidate and authenticates nothing by itself; the
   MAC in step 3 decides.
3. Verify the full HMAC over exactly bytes 0 through 32,895, and require the
   canonical IV, before decrypting or trusting encrypted metadata.
4. Check decrypted length bounds, N = ceil(L/C), type, reserved flags and
   consistency with the object's other authenticated records.
5. Accept identical authenticated duplicates idempotently. A different
   authenticated record for the same object/index is a conflict; arbitrary
   first-wins or last-wins resolution is forbidden.
6. Gather every distinct index, remove only padding beyond the derived n,
   concatenate original chunks by index and verify both L and SHA-256.

A truncated, malformed or authentication-failing record is invalid. A set of
valid records missing a required index is an incomplete object. Neither may
be represented as a successfully recovered canonical object. A conflict
invalidates that object's reconstruction; other objects remain independent.

Discovery skips unrelated records and SHOULD reject/count forged candidates; in
both cases it continues, and neither outcome blocks other objects. A strict
offline open (§6) rejects a supplied set that contains an unrelated or invalid
record. Zero authentic
chunks reveal no discoverable object. A wrong root and absence of matching
objects are not distinguishable from this data alone. Omission of a whole
object by a provider cannot be disproved without additional inventory.

Erasure coding is not a normative recovery step. Optional application artifacts
can supply candidate reconstructed bytes, which MUST pass ordinary validation.

## 6. Offline private-object container and independent recovery

The optional offline container contains exactly one private object:

```text
common_header(kind = 03, flags = 0)
record_count_u32
(record_length_u32 || canonical_record_bytes) repeated record_count times
```

Record count is 1 through 2^32-1, and every record length is exactly 32,928.
Total container length is 12 + record_count * 32,932. Readers MUST detect
truncation, overflow and trailing bytes. The wrapper has no separate MAC;
the records authenticate their identity, ordering, metadata and content.

Mixed objects are rejected. Identical duplicates do not satisfy missing
positions. A strict offline open rejects any invalid or unrelated supplied
record and outputs only the complete validated original. Implementations may stream
records to bounded storage rather than allocating from an untrusted count.

Independent recovery requires the raw root, canonical records or accessible
source bytes, and the source coordinates necessary to retrieve them. For a
chain scan: select the exact chain/network, a start height no later than the
first relevant reveal, and an accessible history source. No final manifest
is necessary for canonical private recovery.

A system-tool implementation must be possible from §§4–6 and the referenced
standard primitives alone; no particular tool defines correctness. Scripts MUST
authenticate before decrypting and avoid exporting partial plaintext.
Derived-key exposure in process arguments, temporary plaintext handling and
constant-time limitations must be disclosed for each actual script; they are
not protocol security guarantees.

An offline public-text export cannot discard the transaction proof and still
claim authenticated authorship; §8 applies.

## 7. Public record layouts

### 7.1 Atomic text, reply, identity profile and avatar

All public kinds use the common 8-byte prefix, flags zero, and the single
Taproot publication profile in §8. Each record occupies one separate reveal
transaction. The complete serialized record MUST be at most 32,768 bytes.
The prefix determines one fixed body layout; no JSON, CBOR, TLV, extension map,
lengthless intermediate field, separator or terminator is permitted.

| Kind | Body starting at offset 8 | Complete length |
| --- | --- | --- |
| 02 plain post | Exact UTF-8 text consuming all remaining bytes | 8–32,768 |
| 04 reply | Raw target TXID[32], then exact UTF-8 text consuming the remainder | 40–32,768 |
| 05 profile | UTF-8 pseudonym consuming all remaining bytes | 8–32,768 |
| 06 avatar | Exactly 512 raw pixel bytes | Exactly 520 |
| 0C profile record | Profile identifier[8], then opaque payload consuming all remaining bytes; §7.1.2 | 16–32,768 |

The reply target occupies offsets 8–39. Its bytes use transaction-hash wire
order, as in a serialized transaction input's previous-outpoint hash. Convert a
usual displayed TXID hex string by decoding hex and reversing the 32 bytes;
reverse again for display. It refers to the selected chain/network, which is
not duplicated in the record. Reply text starts at offset 40. There is exactly
one target and no separate quote kind.

Text and pseudonyms MUST be valid UTF-8. Their bytes, including embedded U+0000
if present, are data, never terminators. Readers MUST NOT normalize Unicode,
trim whitespace, change line endings, case-fold or reserialize before verification
or recovery. Empty UTF-8 is structurally valid; client composition/display policy
is separate. The text budget is 32,760 bytes for a plain post and 32,728 for a
reply. The avatar body is binary and MUST NOT undergo UTF-8 decoding.

A plain post contains only text after its prefix. A reply contains only its
fixed target and text. Profiles and avatars are independent author-authenticated
transactions; neither is embedded in a post or reply. Identity-state resolution,
caching and presentation are outside this protocol.
These atomic kinds do not carry multipart content; kinds 07–09 have separate
layouts and reuse the same transport.

Each public record is identified by its reveal TXID within the configured
chain/network. Identical text in different transactions creates different posts.
An unresolved target does not invalidate a reply's own bytes or author proof.

A different layout requires a newly assigned kind or protocol version. A future
kind containing multiple variable-width fields MUST use explicit lengths;
parsers MUST NOT infer boundaries from contents or append fields to a V0 kind.

#### 7.1.1 Structured wires and hashtags (kinds 0A and 0B)

Kinds 0A and 0B are structured forms of kinds 02 and 04, which remain valid. The
same 8-byte header, zero flags, one reveal, author proof and 32,768-byte
complete record cap apply.

A kind 0A body contains the following fields in order. A kind 0B body first
contains one raw 32-byte target TXID in the same wire order and selected-network
context as kind 04, followed by these same fields:

| Field | Encoding |
| --- | --- |
| Wire length | u8, 0–32 |
| Wire | Exactly wire-length ASCII bytes; zero length means no wire |
| Hashtag count | u8, 0–8 |
| Each hashtag | u8 length (1–32), followed by exactly that many ASCII bytes |
| Text length | u16 little-endian, number of UTF-8 bytes |
| Text | Exactly text-length bytes, valid UTF-8, preserved without normalization |

After text, the parser MUST be at the exact end of the record. Truncation,
trailing bytes, excess lengths/counts and complete records above the cap are
invalid. Empty text is structurally valid. Minimum complete lengths are 12
bytes for 0A and 44 for 0B. Metadata consumes part of the total byte budget;
the u16 text field does not authorize text exceeding the record cap.

Each nonempty label MUST match `[a-z0-9][a-z0-9_-]{0,31}`. Wire names are
single flat labels; there are no subchannels. `/` and `#` are display prefixes,
never encoded label bytes. Hashtags MUST be strictly ascending in ASCII byte
order, which also excludes duplicates. Decoders MUST reject noncanonical bytes,
not normalize them.

Each record has zero or one wire and independently zero to eight hashtags.
A hashtag denotes the same subject across wires within the selected network.
Wire and hashtag labels are entirely open: no registration, owner, privilege,
authorization or protocol moderation is implied. A label proves no affiliation.

A reply may target a post or reply (02, 04, 0A or 0B) on the selected network.
Its wire and hashtags are its own declared metadata, not implicitly inherited
from the target. An unresolved target does not invalidate the reply's own bytes
or proof. Existing 02/04 text containing `/labels` or `#words` remains literal
text, with no structured metadata inferred. Records without metadata may use
02/04; empty metadata in 0A/0B is also structurally valid. A reader that does
not support 0A/0B rejects them as unsupported, rather than misreading their text.

Structured fields support deterministic grouping; they do not remove the need
to discover, verify and index chain records.

#### 7.1.2 Atomic profile record (kind 0C)

Kind 0C carries an application profile's bytes in one atomic record. The same
8-byte header, zero flags, one reveal, author proof and 32,768-byte complete
record cap apply. Its body is:

| Offset | Length | Field |
| ---: | ---: | --- |
| 8 | 8 | Profile identifier |
| 16 | 0–32,752 | Payload consuming all remaining bytes |

Complete lengths are 16 through 32,768 bytes. The profile identifier is
authenticated but uninterpreted by the core; eight zero bytes mean unspecified
profile, and an unknown identifier does not make an otherwise valid record
invalid. The payload is opaque to the core: it undergoes no UTF-8 decoding, and
bytes resembling another URMA record, manifest or archive trigger no parsing.
Payload layout, meaning and validation belong to the profile's own
specification; conformance to a profile is separate from URMA conformance, and
the core never depends on a profile interpreter. A reader that does not
support kind 0C rejects it as unsupported.

### 7.2 Constants, byte conventions and geometry

All offsets below are absolute within a canonical record. The common eight-byte
URMA header is unchanged. Flags and explicitly reserved fields are zero.
Integers in these records are unsigned little-endian.
SHA-256 fields contain the 32 raw digest bytes, without display-order reversal.
TXIDs contain the existing transaction-hash wire order from §7.1;
displayed hexadecimal is converted by reversing the decoded 32-byte value.

| Symbol | Value / definition |
| --- | --- |
| `R` | 262,144 maximum bytes per complete multipart record |
| `C` | `R - 12 = 262,132` original object bytes per data part |
| `F` | 511 data references per leaf |
| `G` | 511 leaf references per root |
| `L` | Original public object payload length |
| `N` | `max(1, ceil(L / C))` data parts |
| `M` | `ceil(N / F)` leaves |

The explicit object ceiling remains **8,553,279,476 bytes**, including profile
framing. It is not enlarged by the larger record capacity. Readers MUST require
`0 <= L <= 8,553,279,476`, derive `N` and `M` as above, and require
`1 <= N <= 32,630` and `1 <= M <= 64`. Fanout remains 511; the largest
permitted object has 32,630 parts, 64 leaves and one root (32,695 records).
The final part at that ceiling has 174,448 payload bytes. The structural
511-by-511 tree capacity does not authorize larger objects.

Readers MUST NOT fall back to 32,756-byte slices or accept a root whose counts
encode that rejected geometry; there is no legacy interpretation.

For `L > 0`, part `i` has exactly `min(C, L - i*C)` payload bytes. For `L = 0`,
there is exactly part 0 with zero payload. There are no dummy parts, variable
chunk sizes, padding records or direct root-to-data shortcuts.

Leaf `j` covers indices `j*F` through `j*F + min(F, N-j*F)-1`. Every nonfinal
leaf therefore has exactly 511 entries. The root has exactly `M` entries in
increasing leaf-index order. A one-part object still uses all three levels.
Use checked arithmetic for every count, offset and multiplication before I/O
or allocation.

### 7.3 Kind 07: public data part

| Offset | Bytes | Field |
| ---: | ---: | --- |
| 0 | 8 | Common header: version `00`, kind `07`, flags zero |
| 8 | 4 | Global part index `i`, u32 |
| 12 | 0–262,132 | Exact consecutive object payload bytes |

Record length is 12 through 262,144 bytes. The zero-payload case is legal only
when the root declares the empty object above. Index and exact payload length
are validated against the root/leaf context; reject `i >= 32630` even before
that context is available. A structurally valid detached part does not by itself
establish a complete object.

The payload is opaque. Bytes resembling another URMA record, archive, executable
or manifest do not trigger parsing or recursive traversal.

### 7.4 Shared child-reference entry

An entry is exactly 64 bytes:

```text
child_reveal_txid[32] || SHA256(exact_complete_child_record)[32]
```

Hash the complete child record including its common header, not a decoded object,
application payload, script or transaction. The TXID locates the reveal; the record hash
binds expected content independently of witness-excluding TXID semantics.
No URLs, block heights, filenames, inferred ordering or index-service IDs occur
in these references.

### 7.5 Kind 08: public leaf manifest

| Offset | Bytes | Field |
| ---: | ---: | --- |
| 0 | 8 | Common header: version `00`, kind `08`, flags zero |
| 8 | 2 | Leaf index `j`, u16 |
| 10 | 2 | Data entry count `k`, u16 |
| 12 | 4 | First global part index, u32 |
| 16 | `64*k` | Ordered references to kind `07` reveals |

Readers MUST require `j < 511`, `1 <= k <= 511`, `first_index = j*511`, exact
length `16 + 64*k`, and no trailing bytes. The maximum leaf length remains
32,720 bytes; unused capacity under the 262,144-byte multipart record ceiling
MUST NOT be padded. In object context also require `j < M` and
`k = min(511, N-first_index)`. Entry `r` requires part index `first_index+r`.
Leaves cannot reference leaves or roots.

### 7.6 Kind 09: public root manifest

| Offset | Bytes | Field |
| ---: | ---: | --- |
| 0 | 8 | Common header: version `00`, kind `09`, flags zero |
| 8 | 8 | Original object length `L`, u64 |
| 16 | 32 | SHA-256 of the complete original object payload |
| 48 | 4 | Total data part count `N`, u32 |
| 52 | 2 | Total leaf count `M`, u16 |
| 54 | 2 | Reserved, zero |
| 56 | 8 | Opaque application profile identifier |
| 64 | `64*M` | Ordered references to kind `08` reveals |

Readers MUST require the geometry of §7.2 and exact length `64 + 64*M`, from 128
through 4,160 bytes under the explicit object ceiling. Unused capacity under the
262,144-byte record ceiling MUST NOT be padded. Root entry `j` requires leaf
index `j`. The profile identifier is authenticated but uninterpreted by the core.
Eight zero bytes mean unspecified
application; unknown identifiers do not make an otherwise valid URMA object
invalid. Profile-specific interpretation is outside core validity.

The root reveal TXID is the locator. A root does not contain its own TXID.
There is no content-derived substitute for this locator and no global object-ID
registry. Re-publication in another root transaction produces another locator.

### 7.7 Author proof, membership and rejection

Every root, leaf and data part uses the existing canonical Taproot commit/reveal
profile in §8. All three kinds are allowed on-chain. A commit may fund
multiple public reveals as a transport-client choice; each reveal still carries
exactly one complete record and retains the current transaction shape.

Let `A` be the root's verified BIP 340 x-only author. Readers MUST require every referenced
leaf and data reveal to verify under that same `A`. No detached signature is
added. Funding keys do not establish authorship. Signatures inside an application
payload are preserved content, not a second URMA author proof.

For each node, verify the full reveal, actual commit outpoint/amount/script,
canonical script, single-leaf commitment, control block and SIGHASH_DEFAULT
signature exactly as in §8. Parsing a key or comparing a TXID alone is
insufficient. Preserve witnesses for offline verification.

Maintain a graph-wide set initialized with the root TXID. Reject any reference
to an already referenced reveal TXID, including the root itself, repeated leaves,
repeated data within/across leaves and ancestor references. Also enforce the
kind required at each edge. Together these rules reject cycles and aliasing;
no generic recursive graph walker is needed. Identical payload bytes at two
positions are allowed, but their records have different indices and distinct
reveal TXIDs. Different roots may independently reference the same otherwise
valid records; duplicate prohibition is per root graph.

At a source boundary, a reveal with the wrong TXID, or one whose proof does not
verify, is an invalid candidate: discard it and try another source. Such a
candidate does not poison authentic data already retained. Verify the proof
before judging the record hash. Once the reveal at the requested TXID has a
fully verified proof, the record it carries is fixed by the commitment; if that
record's SHA-256 differs from the reference in the signed manifest, the object
structure is invalid, and no other source is tried for that object. A signed
manifest containing duplicate slots, wrong geometry or an impossible reference
type is likewise invalid object structure. Never resolve disagreements by
first-wins or last-wins selection.

### 7.8 Completeness and independent recovery

Recovery from a known `(chain, root_txid)` is:

1. Fetch and verify the root and its commit context; validate bounded geometry.
2. Fetch every named leaf; verify its proof and author, then check its record
   hash against the reference and its position.
3. Fetch every named part; verify its proof and author, then check its record
   hash against the reference, its index and its length.
4. Concatenate payloads by global index. Check exact `L` and root SHA-256.
5. Only then export the complete generic payload or claim full application-profile
   validation. A bounded diagnostic inspection of already authenticated segments
   MAY precede completeness, but MUST be labelled partial and MUST NOT establish
   whole-object integrity, profile acceptance or successful recovery.

The public manifest hierarchy is mandatory inventory for this family.
The existing rule that private bytes can be recovered without a final manifest
remains true for private objects; it must not be generalized to this family.
Missing a leaf or part means incomplete recovery, even if an application could
use some available bytes. Source failure is distinct from missing data. No verified
partial payload is labelled a complete snapshot.

Cryptographic validity, generic completeness, application-profile validity, chain
inclusion and confirmations are separately reported. A reorg does not corrupt
retained bytes. URMA has no all-or-nothing chain transaction spanning this graph.

Implementations MUST bound I/O, memory and storage before allocation. They MAY
refuse a valid graph exceeding declared local capacity; such a refusal is not
invalidity. Reconstruction MUST use bounded staging and MUST NOT expose a partial
payload as a completed object. Partial diagnostic inspection is not a complete
payload handoff. Source adapters must bound raw responses and
retries before decoding. No profile parser is a prerequisite to generic recovery.

## 8. Canonical Taproot publication profile

### 8.1 Transaction and key roles

For public records, A is the stable x-only public author key.
For a private record, A is a transport signing key: it authorizes the
transaction and is not private-content authorship. It MUST NOT be derived from
the archive root. It MAY be reused across private records and MAY be the
writer's author or funding key; V0 requires no per-record separation.

One reveal carries exactly one complete record of kind 01, 02, 04, 05, 06, 07,
08, 09, 0A, 0B or 0C.
The offline container kind 03 MUST NOT be accepted as an on-chain record. A commit creates
the native P2TR output that this reveal spends. A commit may fund several
private or public reveals; it does not make their object complete until all
required canonical records are recoverable.

The reveal has transaction version 2, exactly one input spending its commit
outpoint, an empty scriptSig, and one native SegWit return output (P2WPKH or
P2TR). Output value, fee, nLockTime and nSequence are chosen before signing
and must satisfy the selected chain's rules; they are not content metadata.
The commit's other funding/change details are transport-client concerns.
A funding signature alone never establishes public author identity.

### 8.2 Script and commitment

There is one tapscript leaf, leaf version c0, and no additional Merkle path.
The internal key is A. The leaf is precisely:

```text
PUSH32(A) OP_CHECKSIG
OP_0 OP_IF
  PUSH4("URMA")
  PUSH(record segment 0) ... PUSH(record segment k)
OP_ENDIF
```

Split the canonical record into consecutive 520-byte segments plus one final
nonempty segment if needed. No empty trailing segment is added. Use minimal
push encodings: a one-byte segment 01..10 uses OP_1..OP_16 and byte 81 uses
OP_1NEGATE; all other segments of length 1–75 use direct length (including
a one-byte 00 segment, encoded as 01 00). Lengths 76–255 use PUSHDATA1;
256–520 use PUSHDATA2 with a little-endian length. The parser reconstructs
number-opcode segments as their one-byte values, requires canonical segmentation
and rejects extra opcodes/data. The separate OP_0 before OP_IF is structural
and contributes no record bytes.

The native commit output is OP_1 PUSH32(Q.x), where the Taproot output key Q
is the BIP 341 tweak of internal key A with this exact single-leaf script.
The control block is 33 bytes: c0 OR Q parity, followed by A.
Reject a different internal key, leaf version, path length or output commitment.

### 8.3 Author proof

The reveal witness is exactly:

```text
[64-byte Schnorr signature, exact tapscript, 33-byte control block]
```

There is no annex, detached application signature or extra witness item.
Only SIGHASH_DEFAULT is accepted: a 64-byte BIP 340 signature with no appended
sighash byte. The signature message is the BIP 341 transaction message with
the BIP 342 script-path extension: ext_flag=1, key_version=0, this tapleaf hash,
and codesep_pos=0xffffffff because the script has no code separator.

A verifier needs the full reveal, the exact commit prevout amount/script,
the tapscript and control block. It MUST validate the commitment and Schnorr
signature against A and the actual transaction/prevout context. Merely parsing
a public key from a script, validating a commit funding signature or looking
up a TXID is insufficient.

This binds the public record through its script-path commitment and author
authorization. The TXID identifies the post, but does not itself commit to witness
bytes. An offline public proof therefore retains both transactions/witness and
the required prevout context; chain inclusion evidence is a separate claim.

### 8.4 Networks and discovery

Bitcoin and Litecoin use distinct chain contexts; network identity MUST be
checked before fetching or submitting. Mainnet support cannot be inferred
from test-network software. Feed identities, TXID references and observations
are scoped to the configured chain/network. Cross-chain replies and a merged
canonical feed are absent.

A scanner searches input witnesses for the exact envelope and validates the
record and its proof. It MUST NOT treat an arbitrary occurrence of the marker
as a valid record. Chain sources must preserve inclusion-evidence semantics.

Full consensus/chain selection may be supplied by a validating node.
Bitcoin raw-block verification includes the witness commitment, not only
the transaction Merkle root. A reader that takes Litecoin's scrypt proof of
work, MWEB or inclusion validation from a validating node has delegated them;
that delegation is not independent consensus validation by a URMA parser.

Record structural/cryptographic validity, chain inclusion, confirmation count,
provider provenance and client lifecycle remain distinct. The canonical record
does not contain a broad publication-state machine.

## 9. Private-object invariants and implementation boundaries

Each object is an independent reconstruction boundary. V0 defines no atomic
archive/scan/account transaction. Implementations may export complete authentic
objects while reporting other incomplete objects separately.

Source failures and reorg observations are not cryptographic record failures.
An implementation MUST NOT claim a scan completed or a historical placement
remains confirmed when its source/evidence does not establish that claim.
Retained authentic private bytes do not become corrupt merely because their
observed placement was orphaned.

Resource caps MUST be declared as local implementation capacity. Parsers must
bound their work and storage without trusting unauthenticated lengths.
Normative integer bounds, exact byte layouts and application capacity
refusals must not be conflated.

Publication persistence, scheduling, quotes, fee budgets, retry/timeout
handling, partial-success exit status, parity artifacts, UI labels and caches
are outside this protocol.

## 10. Security model

Encryption does not hide marker use, chunk grouping/count, publication timing
or funding relationships. Root compromise exposes that compartment's objects.
An authorized holder can retain or redistribute recovered bytes.

Public author proof establishes authorization by a pseudonymous key, not the
person's civil identity, uniqueness of display name, truth of a statement or
capture time. Private MAC authentication likewise does not prove a photographed
scene was genuine.

Recovery requires bytes that left the lost device, retained accessible copies
and surviving secrets for private objects. Chain publication supplies no
unconditional eternity, connectivity or censorship-resistance guarantee.
External media linked by public text is mutable and not canonically recovered.

The originating application and operating system can see the original
plaintext; nothing in the protocol protects plaintext held on that device.

## 11. Versioning and licensing

A change to accepted bytes, key derivation domains, mandatory validation or
meaning requires an explicit versioned specification update and new vectors.
Unknown versions are never guessed. Compatibility follows the serialized
marker, version and kind bytes; a project name confers none.

The specification, scientific whitepaper, public vectors and protocol data
are CC0-1.0. Project-authored source and reference applications are 0BSD.
Dependencies retain their own licenses.

## 12. Conformance and completion

URMA V0 conformance requires a public deterministic corpus derived from this
specification, with exact input/output bytes and expected outcomes.
Self round-trips alone are insufficient.

The corpus must cover private key derivation, encryption/MAC, padding and count,
all integer and size boundaries, invalid records versus incomplete objects,
unrelated records including a differing discovery tag with a valid MAC,
duplicates/conflicts, unknown versions/flags/kinds, public UTF-8 preservation,
atomic caps, author proof, script/commitment/sighash rejection, and every other
normative rejection. Include every public kind from §7, exact reply TXID byte order, truncated
targets, profile/UTF-8 handling, avatar lengths and forbidden appended fields.

For 07–09, the corpus MUST additionally cover empty objects, every record/count
boundary, 511-entry leaves, multiple leaves, exact two-level geometry, order,
duplicates/cycles/wrong edge kinds, missing nodes, candidate TXID and proof
failures versus invalid signed structure, including a fully verified child whose
record hash differs from its signed reference, author mismatch, unknown opaque
profiles, reserved/trailing bytes, checked overflow and bounded exact recovery.
For 0C, the corpus MUST cover the minimum and maximum complete lengths, an empty
payload, zero and unknown profile identifiers, truncation below 16 bytes and the
absence of any inferred payload structure.

An independent reader MUST verify public graph proofs and reconstruct payloads
without the URMA binary or SDK. Existing 01–06 results remain regression gates.
Maximum-count arithmetic vectors MUST be labelled sparse; claiming the full
8,553,279,476-byte capacity requires an actual streamed maximum reconstruction
with measured memory, disk and time. Public-chain acceptance requires separate
evidence.

At least one independent implementation must recover private original bytes
and reject invalid authentication without an URMA binary, SDK, service or
implementation database. Each supported chain transport needs published
evidence under its declared validation model. Scripts, code and vectors
must agree before the format revision is complete.

Conformance, stability and external audit are separate claims; an audit claim
requires an attributable report. A public corpus and readers are published in
the project repository (https://github.com/urma-protocol/urma); implementation
status and evidence are recorded outside this document.

## 13. Primary specifications

- [AES, FIPS 197](https://csrc.nist.gov/pubs/fips/197/final)
- [CTR, NIST SP 800-38A](https://csrc.nist.gov/pubs/sp/800/38/a/final)
- [SHA-256, FIPS 180-4](https://csrc.nist.gov/pubs/fips/180-4/upd1/final)
- [HMAC, RFC 2104](https://www.rfc-editor.org/rfc/rfc2104)
- [HKDF, RFC 5869](https://www.rfc-editor.org/rfc/rfc5869)
- [Schnorr, BIP 340](https://bips.dev/340/)
- [Taproot, BIP 341](https://bips.dev/341/)
- [Tapscript, BIP 342](https://bips.dev/342/)
- [Witness commitments, BIP 141](https://bips.dev/141/)

## 14. Decision traceability

The following internal decision identifiers record provenance. The requirements
are fully stated in the sections cited; no internal document is needed to implement them.

| Owner decisions | Location |
| --- | --- |
| D-001–D-003 | §§1, 4, 11 |
| D-004–D-005 | §§2–3; Capture, Archive and Wire application contracts |
| D-006–D-007 | §§5–6, 12 |
| D-008–D-010 | §§3, 7–8; Wire profile rules |
| D-011–D-012 | §§5.4, 9; shared export services and Archive Redundancy Profile |
| D-013–D-014 | §7; Wire reply/profile/avatar application rules |
| D-015 | §§2, 5, 7 |
| D-016–D-018 | Wire rollback/visibility and shared publication persistence |
| D-019 | §§3, 6 |
| D-020–D-021 | Wire external-image behavior |
| D-022–D-023 | §§5.1, 9, 12 |
| D-024–D-025 | §§2, 8, 11–12 |
| D-026 | §§4, 7; Wire separate profile/avatar transactions and cache |
| D-027–D-029 | §§1–3, 9; architecture, profiles, applications and funding documents |
| D-030 | §§2, 4, 7.2–7.8, 8, 12; generic public multipart allocation |
| D-031–D-032 | Git profile/application and shared-services contracts; no Git semantics in core |
| D-033 | §3; one public identity may both sign author proofs and fund transactions |
| D-036 | §§2, 4, 7.1.2, 8.1, 12; atomic profile record kind 0C; registry profiles outside the core |

D-035 governs the multipart record capacity and the separately retained object
ceiling in §7.2. D-036 governs kind 0C; the names registry profile that uses it
is a separate interoperable specification, not a core rule. The owner decisions
of 2026-10-07 govern key roles (§3, §8.1), discovery-tag acceptance (§5.4, §6)
and the classification of a record-hash mismatch after a verified proof (§7.7,
§7.8).

## 15. Document revisions

This list is history, not a rule; every rule is stated in the sections cited.

- 0.4: public multipart kinds 07–09 under wire version 00; kinds 01–06, their
  byte layouts, private cryptographic domains and Taproot validation unchanged.
- 0.5: the multipart geometry of §7.2 retained.
- 0.6: atomic profile record kind 0C (§7.1.2); kinds 01–0B unchanged.
- 0.7: no byte layout, key derivation or kind changed; discovery-tag acceptance
  (§5.4, §6), record-hash mismatch after a fully verified proof (§7.7, §7.8),
  shared author and funding key (§3), reusable private transport key (§8.1).
- 0.8: no rule changed; implementation state, historical evidence and
  dependencies on auxiliary documents removed, so that this document stands
  alone.
