Skip to content
LimniFS

.spec · wire-format · §5

Manifest.

The small, signed head of a .lim image. 16-byte header, nine sections, Merkle root. The ManifestRoot it produces is the image’s identity — every URL, container ID, content hash, and IPFS CID that references the image resolves to it.

METADATA BLOBH(metadata) = b3:…MANIFEST SECTIONS§5.1Magic + format header§5.2Feature flags§5.3Metadata reference§5.4Slab index§5.5Crypto params§5.6EC paramsopt§5.7DMS policyopt§5.8Delta linkageopt§5.9HistoryHASH LISTH(metadata)H(§5.1)H(§5.2)H(§5.3)H(§5.4)H(§5.5)H(§5.6)H(§5.7)H(§5.8)H(§5.9)||“limnifs/v1” || hash list→ BLAKE3§5.10 MANIFESTROOTb3:def158…= image identity

Each section is hashed individually; the section hashes plus H(metadata) are concatenated with a domain separator and BLAKE3’d into the Merkle root.

§5.1 — Magic + format header (16 bytes)

The first 16 bytes of every .lim manifest:

offset  size  field                  meaning
0       4     magic                  'LMFS' (0x4C 0x4D 0x46 0x53)
4       2     drop_store_version     u16 LE — drop store layer version
6       2     metadata_version       u16 LE — metadata layer version
8       2     manifest_version       u16 LE — manifest layer version
10      4     reserved               MUST be zero

The three version fields are independent (per-layer versioning). A reader declaring spec vX.Y MUST accept any image whose versions are each ≤ its declared maximum for that layer.

§5.2 – §5.9 — The nine sections

Sections appear in the order they’re hashed into the Merkle root. Optional sections (EC params, DMS policy, delta linkage) may be absent; readers detect by section presence. Required sections MUST be present.

§5.10 — Merkle root construction

Flat construction (not a deep tree). Each section is verifiable individually without loading siblings — important for HTTP range streaming and partial verification.

ManifestRoot = BLAKE3(
"limnifs/v1"                // domain separator
|| H(metadata)              // layer-2 metadata blob hash
|| H(format_header)         // §5.1
|| H(feature_flags)         // §5.2
|| H(metadata_reference)    // §5.3
|| H(slab_index)            // §5.4
|| H(crypto_params)         // §5.5
|| H(ec_params)             // §5.6 (or empty hash if absent)
|| H(dms_policy)            // §5.7 (or empty hash if absent)
|| H(delta_linkage)         // §5.8 (or empty hash if absent)
|| H(history)               // §5.9
)

Why flat, not deep?

A deep Merkle tree over sections would require loading sibling hashes to verify any one section. A flat construction (hash of section hashes) lets each section be verified with just its own bytes plus the root. Trade-off: updating one section invalidates the root — but .lim images are immutable, so we don’t pay that cost.