← vault manual
Embedding Specification
Core vault document — v1.0 — March 2026. Classification: pre-authentication disclosure.
§E1 Overview
This document specifies the complete process by which cryptographic private
keys are embedded into The 8 Museum photographs. It is written so that a
future accessor — possessing computational capability far beyond the era
of authorship — can reverse the process mechanically, without ambiguity,
and recover all keys from the canonical photograph set.
The process has five stages: format canonicalisation, key generation,
steganographic embedding, integrity sealing, and distribution. Each stage
is fully deterministic given the specified inputs. No stage involves
randomness that is not derived from documented seeds.
§E2 Format Canonicalisation
The source photographs are captured in HEIC (High Efficiency Image
Container, based on HEIF/HEVC), the native format of the capture device.
HEIC is a lossy-compressed format with 10-bit per channel colour depth.
It is not suitable for steganographic embedding because the compression
scheme is complex, poorly standardised across decoders, and unlikely to
remain widely implemented over the vault's timeframe.
Each source HEIC is converted to 8-bit PNG (Portable Network
Graphics) as a one-time, irreversible canonicalisation step. PNG is
losslessly compressed, universally implemented, and specified by a simple,
public standard (ISO/IEC 15948, W3C Recommendation) that can be
reimplemented from the specification alone. The 10-bit to 8-bit tonal
range reduction is an accepted and deliberate trade-off: it produces the
standard 8-bit channel values that the embedding algorithm operates on,
and that any future extractor will expect.
Source format
HEIC (HEIF/HEVC), 10-bit per channel
Canonical format
PNG, 8-bit per channel, RGB colour space
Colour space
sRGB (IEC 61966-2-1). No ICC profile embedding. No colour management transformation during conversion.
Metadata
All EXIF, XMP, and IPTC metadata is stripped during canonicalisation. The PNG contains pixel data only. Metadata is preserved separately in the vault manifest.
Conversion tool
ImageMagick convert, invoked as: convert input.heic -depth 8 -strip -colorspace sRGB PNG24:output.png
Provenance hash
The SHA-3-512 hash of the original HEIC file is recorded in the vault manifest before conversion, preserving provenance.
After canonicalisation, the HEIC originals are retained as provenance
records but are not part of the vault's key infrastructure. Only the
canonical PNGs carry embedded keys. Only the canonical PNGs are
distributed. Only the canonical PNGs are hashed in the vault manifest.
§E3 Key Generation
The vault uses 8,888 distinct SPHINCS+-256s keypairs (NIST FIPS 205,
SLH-DSA). All keypairs are derived deterministically from a single
256-bit master key (MK), ensuring that the full key set can be
regenerated from MK alone if the vault manifest is lost.
Signature scheme
SPHINCS+-256s (SLH-DSA, NIST FIPS 205)
Security level
NIST Level V (256-bit post-quantum)
Private key components
SK.seed (32 bytes) + SK.prf (32 bytes) = 64 bytes
Public key components
PK.seed (32 bytes) + PK.root (32 bytes) = 64 bytes
Master key (MK)
256-bit value generated from OS entropy. Stored in key material archive (not in vault manifest).
Per-image key derivation
seed_i = HKDF-SHA-256(MK, salt=empty, info="afterberry-sphincs-" || i) where i is the 4-byte big-endian image index (1 to 8,888). The 64-byte output is split: first 32 bytes → SK.seed, last 32 bytes → SK.prf.
Public key derivation
PK.seed and PK.root are computed from SK.seed and SK.prf per the SPHINCS+-256s key generation algorithm (FIPS 205 §7.1).
Key generation procedure
For each image index i from 1 to 8,888: (1) Derive 64 bytes of
key material from MK via HKDF-SHA-256 with info string
"afterberry-sphincs-" || i. (2) Split into SK.seed (bytes 0–31)
and SK.prf (bytes 32–63). (3) Generate the SPHINCS+-256s keypair per
FIPS 205 §7.1. (4) Store the public key (PK.seed || PK.root, 64 bytes) in
the vault manifest under index i. (5) The private key material
(SK.seed || SK.prf, 64 bytes) is the payload to be embedded in photograph
i.
§E4 Steganographic Embedding
The embedding algorithm is S-UNIWARD (Spatial UNIversal WAvelet
Relative Distortion), operating in the spatial domain on 8-bit RGB pixel
values. S-UNIWARD assigns a distortion cost to each possible modification
of each pixel channel, then embeds the payload by making the minimum-cost
set of changes. The cost function uses a directional filter bank to
identify high-texture, high-noise regions where modifications are
statistically undetectable.
Algorithm
S-UNIWARD (spatial domain)
Reference
Holub, V., Fridrich, J., Denemark, T. "Universal Distortion Function for Steganography in an Arbitrary Domain." EURASIP Journal on Information Security, 2014(1).
Wavelet basis
Daubechies-8 (db8), three directional subbands: horizontal (LH), vertical (HL), diagonal (HH)
Stabilisation constant
σ = 1 (standard S-UNIWARD stabilisation to prevent division by zero in smooth regions)
Colour channels
All three (R, G, B). Cost is computed independently per channel. The embedding path interleaves channels by ascending cost across the full image.
Modification
±1 LSB modification per selected sample. Each modification encodes one bit of payload.
Payload size
512 bits (64 bytes) per image
Typical embedding rate
~0.000014 bpp for a 12-megapixel image (4 orders of magnitude below steganalytic detection thresholds)
§E5 Embedding Path Derivation
The embedding path — the specific sequence of pixel locations and colour
channels modified during embedding — must be deterministic and reproducible
from documented parameters. It is derived as follows:
Master embedding key (MEK)
256-bit value generated from OS entropy. Independent of MK. Stored in key material archive. Published in vault manifest (required for extraction).
Per-image embedding seed
eseed_i = HKDF-SHA-256(MEK, salt=empty, info="s-uniward-seed-" || i) where i is the 4-byte big-endian image index.
Seed output
32 bytes, used to initialise a ChaCha20 CSPRNG for the embedding path selection.
Embedding procedure for image i
(1) Load the canonical PNG as a 3-dimensional array of 8-bit unsigned
integers: height × width × 3 (R, G, B).
(2) Compute the S-UNIWARD cost map. For each pixel (x, y) and each
channel c ∈ {R, G, B}, compute the distortion cost ρ(x, y, c) as the
reciprocal of the sum of absolute values of the three directional wavelet
residuals (LH, HL, HH) at that position, with stabilisation constant
σ = 1 added to the denominator:
ρ(x, y, c) = 1 / (|r_LH(x,y,c)| + |r_HL(x,y,c)| + |r_HH(x,y,c)| + σ)
(3) Enumerate all candidate positions as triples (x, y, c). Exclude any
position where the pixel value is 0 or 255 (boundary values that cannot
accommodate ±1 modification in one direction). Sort all remaining positions
by ascending cost ρ.
(4) Initialise a ChaCha20 CSPRNG with the per-image embedding seed
eseed_i as the key and a zero nonce. Use the CSPRNG to generate a
permutation of the lowest-cost 2,048 candidate positions (4× the payload
size, providing selection margin). The first 512 positions in the permuted
list are the embedding path.
(5) For each of the 512 positions in the embedding path, in order: read
the corresponding bit of the 64-byte payload (MSB first, byte 0 bit 7
through byte 63 bit 0). If the payload bit matches the current LSB of
the pixel channel value, make no change. If it does not match, modify
the pixel channel value by +1 or −1, choosing the direction that results
in lower S-UNIWARD distortion (or +1 if equal).
(6) Write the modified image as PNG, preserving all PNG encoding
parameters (compression level, filter method) from the canonicalised
input. The output PNG is the canonical embedded photograph for index
i.
The selection of 2,048 low-cost candidates (step 4) rather than
embedding directly into the 512 lowest-cost positions is deliberate.
Embedding exclusively into the absolute lowest-cost positions creates a
detectable statistical signature (the "always embed at minimum cost"
artefact). The CSPRNG-driven selection from a 4× candidate pool
introduces controlled randomness while still concentrating modifications
in high-distortion-tolerance regions.
§E6 Integrity Sealing
After all 8,888 photographs have been embedded, the full set is sealed
with integrity hashes and a signed Merkle tree.
Sealing procedure
(1) For each embedded PNG (index 1 to 8,888), compute the
SHA-3-512 hash of the complete file (including PNG headers, not
just pixel data). Record in the vault manifest as
photo_hash[i].
(2) Construct a Merkle tree over the 8,888 hashes. Use SHA-3-256 as the
internal hash function. Leaf nodes are
SHA-3-256("leaf:" || i || photo_hash[i]). Internal nodes are
SHA-3-256("node:" || left || right). Pad the tree to the next
power of 2 (16,384) with leaves hashing the empty string.
(3) Sign the Merkle root with Berry's personal Ed25519 signing key. The
signature, public key, and Merkle root are published in the vault
manifest.
(4) For each image, compute and record a Merkle proof (the sibling hashes
needed to verify that image's leaf against the root). These proofs are
included in the vault manifest, enabling per-image verification without
downloading the full set.
(5) Record the SHA-3-512 hash of the vault manifest itself as the final
integrity anchor. Publish this hash independently (in the reconstruction
guide, on the afterberry.com website, and in all documentation copies).
§E7 Distribution Protocol
Once sealed, the canonical embedded PNGs are distributed to all storage
locations documented in the
vault locations manifest. The distribution
protocol is:
Distribution rules
(1) Transfer files as raw byte streams. Use checksummed transfer protocols
(SCP, rsync with checksum verification, S3 PUT with Content-MD5).
Verify the SHA-3-512 hash of each file at the destination after
transfer.
(2) Never re-encode, resize, resample, rotate, crop,
colour-correct, strip metadata from, add metadata to, or in any other way
modify the pixel data of a canonical embedded PNG after sealing. Any
modification to pixel data, however minor, may destroy the steganographic
payload.
(3) Never serve canonical PNGs through any system that
performs automatic image processing (CDN image optimisation, thumbnail
generation from the embedded file, social media upload, cloud photo
library sync). Serve only from raw object storage or static file
hosting with no processing pipeline.
(4) Store the vault manifest alongside the photograph set at every
storage location. The manifest is required for extraction and must
travel with the photographs.
(5) Periodically (at least annually) verify the integrity of stored
photographs by spot-checking SHA-3-512 hashes against the vault manifest.
Replace any corrupted copies from a verified source.
§E8 Key Material Summary
The complete embedding process depends on exactly two secret values and
one semi-public value:
Master key (MK)
DESTROYED. 256 bits. Derived all 8,888 SPHINCS+ private keys during the key generation ceremony (see §E10). Existed only in volatile memory on an air-gapped machine for the duration of key derivation. Never written to persistent storage. Never transmitted. Overwritten and destroyed within minutes of creation. Cannot be recovered.
Master embedding key (MEK)
PUBLISHED IN VAULT MANIFEST. 256 bits. Derives per-image embedding seeds. Required for both embedding and extraction. Without MEK, the embedding path cannot be reconstructed and payloads cannot be extracted. Published because extraction requires it — and because knowing the embedding path without the photograph originals reveals nothing.
Berry's Ed25519 signing key
PUBLIC KEY PUBLISHED. Used to sign the Merkle root. The public key is in the vault manifest. The private signing key is held by Berry and used only for manifest signatures.
The security model: MK derived the private keys and is destroyed. MEK
is published. The photographs are public. The vault manifest is public.
The reconstruction guide is public. Everything is in the open — the
private keys exist only as steganographic payloads inside the photographs
themselves, and the AES-256-GCM key that protects the locations manifest
has been destroyed. The vault hides in the gap between what is published
and what is computable.
§E9 Extraction (Reverse Procedure)
For the complete extraction and reconstruction procedure, see the
Reconstruction Guide. Extraction
is the exact reverse of §E5: load the canonical PNG, compute the
S-UNIWARD cost map, sort all eligible positions by ascending cost,
take the 2,048 lowest-cost candidates, derive the per-image embedding
seed from MEK, initialise the same ChaCha20 CSPRNG with that seed,
apply the same permutation to the 2,048 candidates, and take the first
512 positions from the permuted list. These are the embedding path.
Read the LSB of each pixel channel value at these 512 positions, in
order, to recover the 64-byte payload. The payload is the SPHINCS+-256s
private key (SK.seed || SK.prf) for that image's index.
§E10 Key Lifecycle
The master key (MK) is designed to exist for the shortest possible duration.
The following lifecycle ensures that MK never persists beyond the initial
key generation session, and that individual private keys are consumed
progressively as photographs are completed.
Phase 1 — Key generation ceremony
Boot a clean, air-gapped machine from a live operating system (Tails
recommended). The machine must never have been and must never be connected
to any network. Generate MK from /dev/urandom (32 bytes).
Generate MEK from /dev/urandom (32 bytes). Derive all 8,888
SPHINCS+-256s keypairs from MK in a single session. Record all 8,888
public keys to the vault manifest. MK is then overwritten in memory and
destroyed. MK's total lifetime is measured in minutes. It is never written
to persistent storage, never transmitted, and never displayed beyond the
air-gapped session.
Phase 2 — Immediate embedding (existing photographs)
In the same session or an immediately subsequent air-gapped session, embed
private keys into all existing canonical photographs (those already taken
at the time of the ceremony). Each key is embedded per §E4–§E5, verified
by test extraction per §E9, and then deleted from the working key set.
Photograph indices are assigned chronologically: the earliest photograph
receives index 1, and so on.
Phase 3 — Escrow of remaining keys
Private keys for photographs not yet taken (indices beyond the current
collection) are encrypted with AES-256-GCM using a key derived
from a memorised passphrase via Argon2id (memory cost ≥ 1 GiB,
time cost ≥ 4 iterations, parallelism = 1). The encrypted key file is
stored on a single secure device (encrypted USB drive, air-gapped).
This is the only location where unembedded private keys exist.
Phase 4 — Progressive consumption
As each new photograph is taken and canonicalised (HEIC → PNG per §E2),
the next available private key is retrieved from the encrypted escrow file,
embedded into the photograph per §E4–§E5, verified by test extraction,
and immediately deleted from the escrow file. The escrow file shrinks by
one key with each new photograph. Indices are assigned chronologically:
the next photograph taken receives the next sequential index.
Phase 5 — Sealing
Upon completion of photograph 8,888: the last private key is embedded, the
escrow file is empty and is destroyed. No private key material exists
anywhere except within the 8,888 canonical photographs. The vault manifest
is finalised, the Merkle tree is computed and signed, and the integrity
seal is applied per §E6. The vault is sealed.
Interim risk (Phase 3–4): During the period between the
key generation ceremony and photograph 8,888, the escrow file contains
private keys for not-yet-taken photographs. These keys, if compromised,
could decrypt their corresponding shards — but individual decrypted shards
are algebraic noise due to the erasure coding (reconstruction requires
6,000 of 8,888 shards). The interim exposure is therefore limited: even
total compromise of the escrow file does not enable archive reconstruction,
provided fewer than 6,000 shards are decrypted in combination with shards
from already-embedded keys. The escrow file's size decreases daily as
keys are consumed, and the risk window closes permanently at photograph
8,888.
§E11 Historical Note — Key Storage Format
During the project's development phase (prior to the adoption of this
specification), the master key was stored using a bespoke steganographic
encoding: the key material was converted to randomised words and
interpolated into a fictitious berry pie recipe. The resulting document —
datavault_berrypie.txt — reads as an elaborate, whimsical
baking recipe and contains no recognisable cryptographic notation. This
format allowed the key to be carried, stored, and transmitted in contexts
where a cryptographic key file would attract scrutiny. The encoding
algorithm is intentionally not documented here; it was designed to be
recoverable by brute force combined with insight by a sufficiently
advanced system, but resistant to casual inspection.
The berrypie format is noted for historical completeness and as an
illustration of the project's approach to hiding critical material in
plain sight. Under this specification, MK does not survive beyond the
key generation ceremony and therefore requires no storage format.