LRFS signing scheme
This chapter specifies how LRFS payloads are signed so downstream consumers can verify integrity and detect tampering. Per-layer signing is mandatory for conformance level L3; file-level checksum is mandatory for L2 and above.
1. Per-layer signing: HMAC-SHA256
HMAC-SHA256 provides symmetric-key signing for private corpora where all parties share a pre-shared key. The signature is computed as follows:
-
For each layer
llmind:<layer>, canonicalize the layer's RDF triples per the payload-format chapter (§4). -
Compute
HMAC-SHA256(key, canonical_bytes)wherecanonical_bytesis the N-Quads canonical form as UTF-8 bytes. - Encode the resulting 32-byte MAC as base64 (RFC 4648, no padding).
-
Store the base64 MAC as the value of
llmind:<layer>_signature. -
Store an opaque key identifier as
llmind:<layer>_signature_key. This identifier is NOT the key itself; it is metadata that helps the verifier locate the correct key. Example:"prod-key-2026-q2"or a UUID.
Key management is out of scope for the LRFS specification. Implementers document their own key distribution and rotation policies. Keys MUST never be stored in the LRFS payload itself.
2. Per-layer signing: ed25519
ed25519 provides asymmetric signing for public verification. Any party with the signer's public key can verify the signature without possessing the private key. The process:
-
For each layer
llmind:<layer>, canonicalize the layer's RDF triples per the payload-format chapter (§4). - Sign the canonical bytes with the ed25519 private key to produce a 64-byte signature.
- Encode the signature as base64 (RFC 4648, no padding).
-
Store the base64 signature as
llmind:<layer>_signature. -
Store the public-key reference as
llmind:<layer>_signature_key. The reference MUST be a dereferenceable URL, such as an HTTPS endpoint serving the public key in PEM format or a.well-knownpath.
Implementers MAY fetch and cache public keys. The specification RECOMMENDS fetching over HTTPS and validating the TLS certificate chain. Implementers SHOULD set a reasonable TTL (e.g., 1 hour) on cached keys and allow manual key rotation via configuration.
The ed25519 private key MUST NOT leave the signing environment. Keys stored in HSMs, KMS systems, or secure enclaves are acceptable.
3. File-level checksum
In addition to per-layer signing, the writer computes a file-level SHA-256 checksum covering the file's content independent of metadata. This allows verifiers to detect modifications to the file body even if the XMP packet is rewritten or updated.
The algorithm:
- Extract all bytes from the original file EXCEPT the XMP packet itself.
- Compute the SHA-256 digest of these bytes.
- Encode the digest as hexadecimal (lowercase, 64 ASCII characters).
-
Store the hex digest as the value of
llmind:file_checksuminside the XMP packet.
Implementation note: The exact byte-range exclusion depends on the host file format. For JPEG, exclude the APP1 segment. For PNG, exclude the iTXt chunk. For PDF, exclude the Metadata stream. Format-specific rules are defined in the format appendices (v1.1 will detail these; v1.0 assumes implementers reference the XMP specification and format-specific guidelines).
4. Verification algorithm
Pseudo-code for verifying an LRFS payload:
function verifyLRFS(file, hmacKey, ed25519PublicKeyUrl):
# Extract XMP packet from file
xmpPacket = extractXMP(file)
parseRDF(xmpPacket) # Load all llmind:* properties
# Per-layer verification
for layer in ["description", "entities", "structure", ...]:
if llmind:<layer> not in RDF:
continue # Layer not present, skip
# Canonicalize the layer's triples
canonicalBytes = canonicalize(getRDFTriplesFor(layer))
# Get the stored signature and key
signature = llmind:<layer>_signature
keyRef = llmind:<layer>_signature_key
# Verify HMAC or ed25519
if isHMAC(signature):
expected = base64Encode(HMAC_SHA256(hmacKey, canonicalBytes))
if signature != expected:
FAIL("HMAC signature mismatch for layer " + layer)
elif isEd25519(signature):
pubKey = fetchPublicKey(keyRef) # Dereference the URL
if not ed25519Verify(pubKey, canonicalBytes, base64Decode(signature)):
FAIL("ed25519 signature invalid for layer " + layer)
# File-level checksum
bodyBytes = extractFileBodyExcludingXMP(file)
expectedChecksum = SHA256_hex(bodyBytes)
if llmind:file_checksum != expectedChecksum:
FAIL("File checksum mismatch — body modified")
PASS("All signatures and checksums valid") 5. Key rotation and revocation
The current LRFS v1.0 specification does not define a revocation protocol. An ed25519 public key is either trusted or not; there is no list of revoked keys.
Implementers using ed25519 SHOULD publish a key-rotation policy alongside their
public keys. For example, a key published at
https://example.com/.well-known/llmind-keys can include rotation
schedules and guidance. Any future revocation protocol will be specified in LRFS
v2.0 (which will use a new namespace URI and backward-compatibility-breaking
changes).
6. Security considerations
HMAC keys: Shared keys MUST be distributed out-of-band via secure channels (e.g., manual distribution, KMS, or secure provisioning systems). Keys MUST NOT be embedded in code, configuration files, or version control systems.
ed25519 private keys: Private keys MUST NOT leave the signing environment. Use hardware security modules (HSMs), key management services (KMS), or secure enclaves.
Tamper detection: An attacker with write access to a file's body bytes but not the signing key cannot forge a valid signature. The signed layers protect against silent modification. However, an attacker WITH access to the signing key or the shared HMAC key can modify both content and signatures.
Signature verification must fail closed: Any verification error (missing signature, invalid format, algorithm mismatch, signature mismatch, checksum mismatch) MUST cause the operation to reject the payload. Implementations MUST NOT silently ignore verification errors or fall back to unsigned data.
7. Related chapters
- Payload format — Canonicalization algorithm (§4)
- Conformance — L3 conformance requires full signing support
- File enrichment glossary — definitions of terms used throughout the specification