Skip to content
LimniFS

.spec · concepts · §1

Identity & invariants.

The identity plane is load-bearing. Everything else — codec, AEAD, EC, locator — is a representation, recorded as metadata, never part of identity. Five invariants pin it.

§1.1 — The identity rule

DropId = BLAKE3(plaintext), the 256-bit hash of a drop’s plaintext bytes — after full decoding through every representation transform (codec inverse, AEAD open, EC reconstruct). The plaintext argument MUST be the bytes the user would read from the corresponding slice range if the image were mounted read-only.

DropId       = BLAKE3(plaintext)                      // 256-bit output
DropId.text  = "b3:" || base32_no_pad(DropId)        // multihash display

The display form is the multihash text string b3:<base32-lower-no-pad> — RFC 4648 base32 lowercase, no padding. The b3: prefix is the multihash code for BLAKE3-256. This makes LimniFS drop names directly pinnable as IPFS CIDs without an adapter layer.

Identity is representation-independent

The same plaintext sealed with XChaCha20-Poly1305 then zstd-compressed, and the same plaintext stored uncompressed under no AEAD, share the same DropId. Codec/AEAD/EC/locator are recorded in Representation metadata; they never affect the name.

REPRESENTATION AXChaCha20-Poly1305zstd level 19→ stored bytesct: 0x4a72…decodePLAINTEXTthe bytesBLAKE3DropIdb3:abc23…256 bits

The plaintext hashed = the name. Representation never matters.

Two representations of the same drop decode to the same plaintext and therefore share the same DropId.

Readers MUST verify BLAKE3(decoded_plaintext) == DropId after all representation inversions. This hash check is the canonical test of identity; AEAD tags and EC shard hashes are fast-fail optimizations that fire before the BLAKE3 check.

§1.2 — Image identity

ManifestRoot is the identity of an entire .lim image. It is the Merkle root over the layer-2 metadata blob and the manifest’s own sections, defined in §5.10. Two images with the same ManifestRoot are byte-for-byte equivalent under this spec: same metadata, same slabs, same drops with the same representations.

§1.3 — Representation plane separation

Codec, AEAD, erasure coding, and locator placement are collectively the representation plane. They never appear in the identity plane. Concrete consequences:

  • A drop MAY have multiple Representation rows in the slab index, each at a different (slab_id, offset, len) with a different (codec, aead, ec) triple. All decode to the same plaintext and share DropId.
  • A reader’s DropSource takes a DropId and a Representation as input. The reader selects one (locator racing), decodes, and verifies.
  • Deepening (epilimnion → hypolimnion) APPENDS a new Representation row; never mutates existing ones; never changes any DropId.
  • Locator mirroring is likewise representation-plane: one slab may have multiple locator entries pointing at the same stored bytes.

§1.4 — Determinism

Every byte of a .lim image MUST be a deterministic function of the input tree and the manifest’s recorded parameters, with two exceptions: the image creation timestamp and the image key. Five concrete rules:

  • Chunking: same input + same FastCDC parameters ⇒ same drops. No random padding.
  • Classification: same drop head bytes + same classifier registry ⇒ same class.
  • Codec encode: same input + same codec id + same level ⇒ same output bytes.
  • Slab packing: same drop sequence + same packing parameters ⇒ same slabs in the same order.
  • Manifest assembly: same inputs ⇒ same sections, same section hashes, same ManifestRoot.

A nondeterministic byte found in CI (same input, two runs, different ManifestRoot) is a bug class tracked under §19 conformance. The conformance harness runs the build pipeline twice and asserts byte equality of the resulting manifests.