# AllKard File Format Specification
```
Identifier: allkard/1.0
Media type: application/vnd.allkard+zip
Extension: .kard
JSON Schema: https://allkard.com/schema/v1.json
This document: https://allkard.com/docs/spec-allkard-1.0.md
```
## Abstract
This document defines the on-disk layout of an AllKard archive, the contents of `kard.json`, the manifest and signature binding, witness key discovery, and the recommended verification procedure. A conforming archive is a ZIP file containing JSON metadata, optional binary assets, a SHA-256 manifest, and a detached Ed25519 signature.
## 1. Conventions
The key words MUST, MUST NOT, SHOULD, SHOULD NOT, MAY, and OPTIONAL in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119).
The JSON Schema at `https://allkard.com/schema/v1.json` is normative for the structure of `kard.json`. Where this document and the schema disagree on archive handling, canonicalization, or signing, this document takes precedence for those topics.
Implementations MUST NOT hardcode a witness hostname. Witness metadata MUST be read from each `kard.json` instance.
## 2. Archive
### 2.1 Members
A conforming archive MUST contain:
| Member | Required |
|--------|----------|
| `kard.json` | yes |
| `manifest.json` | yes |
| `signature` | yes |
| `assets/*` | as referenced by `kard.json` |
No other member names are permitted except optional ZIP directory markers (e.g. `assets/`) that verifiers MUST ignore.
### 2.2 Path syntax
Member names:
- MUST NOT start with `/` or `./`
- MUST NOT contain `\`, U+0000, empty path segments, `.`, or `..`
- MUST NOT exceed 240 octets in length
- MUST be either `kard.json`, `manifest.json`, `signature`, or match `^assets/[a-zA-Z0-9_./-]+$`
Asset paths listed in `kard.json` MUST satisfy the same `assets/` rules. Dot-segment rejection is required even when a pattern match would succeed.
### 2.3 Decompression limits
A verifier SHOULD enforce the following limits (reference implementation values):
| Limit | Value |
|-------|-------|
| Total uncompressed payload | 64 MiB |
| Single member | 24 MiB |
| Member count (including ignored directories) | 80 |
Exceeding a limit MUST cause verification to fail.
## 3. Document `kard.json`
### 3.1 Format field
`format` MUST be the string `allkard/1.0`.
### 3.2 Serialization
The stored file MUST be UTF-8. It MUST NOT begin with a BOM. The file bytes MUST equal the canonical JSON encoding of the parsed value (Section 6).
### 3.3 Class `memory`
When `class` is `memory`:
- `custody.transferable` MUST be `false`
- `custody.transfer_epoch` MUST be `0`
- `back.provenance_chain` MUST NOT be present
### 3.4 Class `provenance`
When `class` is `provenance`:
- `custody.transferable` MUST be `true`
- `back.provenance_chain` MUST be present and non-empty
- `custody.transfer_epoch` MUST equal the `epoch` of the last element of `provenance_chain`
- `custody.holder` MUST equal the `holder` of that last element
### 3.5 Chapters
`back.chapters[].sequence` MUST be contiguous starting at `1`. `id` values MUST be unique within the document.
### 3.6 Provenance chain
For `back.provenance_chain`, each element’s `epoch` MUST equal its zero-based array index. `acquired_at` MUST NOT decrease when read in array order.
### 3.7 Witness block
- `witness.authority` MUST be an `https` origin with empty path, query, userinfo, and fragment. Hierarchical hostnames (for example regional franchise witnesses) are permitted when they remain valid HTTPS origins sharing a single keys document at `/.well-known/witness-keys.json`.
- `witness.keys_discovery` MUST be `https`, share the origin of `witness.authority`, and have pathname `/.well-known/witness-keys.json`.
- `witness.signed_at` SHOULD be greater than or equal to `issued_at`.
### 3.8 Asset references
Each path in `front.hero_asset`, `front.logo_asset`, and any `back.chapters[].asset` MUST name a member present in the archive and listed in `manifest.json`. Packagers SHOULD NOT include assets that are not referenced.
## 4. Document `manifest.json`
The document MUST be a JSON object mapping member paths to lowercase hexadecimal SHA-256 digests of the raw member bytes. Keys MUST include at least `kard.json` and every `assets/*` member.
The on-disk bytes MUST be canonical JSON (Section 6). Key order in the serialization MUST be lexicographically sorted.
The signature (Section 5) is computed over the UTF-8 encoding of those bytes, not over a reformatted representation.
## 5. File `signature`
The file MUST contain one base64url-encoded Ed25519 signature and no other characters (no PEM, no JSON, no whitespace).
The signed message is the UTF-8 encoding of the canonical `manifest.json` octets.
`witness.key_id` in `kard.json` MUST identify the public key used for verification.
## 6. Canonical JSON
Canonical JSON is used for `kard.json`, `manifest.json`, and signing input.
Rules:
1. Object keys are serialized in lexicographic order.
2. No insignificant whitespace.
3. Strings use JSON escaping; U+0000–U+001F use `\uXXXX` unless named escapes apply.
4. Numbers MUST be safe integers or are not permitted in archive-bound values.
5. Object members with `undefined` values MUST NOT appear in output.
This definition is a restricted profile aligned with [RFC 8785](https://www.rfc-editor.org/rfc/rfc8785) for the value types allowed in AllKard.
## 7. Witness key document
Published at the URL named by `witness.keys_discovery`.
Object shape:
```
{
"authority": string, // MUST equal witness.authority
"keys": [ // 1–32 entries
{
"key_id": string,
"algorithm": "Ed25519",
"public_key": string, // base64url, 32 octets decoded
"status": "active" | "retired" | "revoked"
}
]
}
```
Verifiers MUST reject `revoked` keys. Verifiers MAY accept `retired` keys for older archives.
Fetch MUST use HTTPS. Credentials embedded in URLs MUST NOT be used. Automatic redirect following is NOT RECOMMENDED.
## 8. Verification procedure
Recommended order:
1. Extract members per Section 2.
2. Parse `kard.json`; check canonical form and schema.
3. Apply Section 3 semantic rules.
4. Parse `manifest.json`; check canonical form.
5. Hash members; compare to manifest.
6. Obtain Ed25519 public key for `witness.key_id`.
7. Verify signature over manifest bytes.
8. OPTIONAL: query `custody.status_endpoint` (Section 9).
Cryptographic success SHOULD be reported only if steps 2–7 pass. Step 8 does not change digest or signature results.
## 9. Optional custody endpoint
If `custody.status_endpoint` is set and the implementation performs an online check:
- Request HTTPS; parse JSON body.
- Body MUST include integer `current_epoch` ≥ 0.
- If `current_epoch` equals `custody.transfer_epoch`, an optional `holder` field SHOULD match `custody.holder` when present.
- If `current_epoch` is greater than `custody.transfer_epoch`, the file MAY be labeled a historical transfer at a later epoch.
- Network failure MUST NOT downgrade offline hash or signature results.
## 10. Media type
Files SHOULD be labeled `application/vnd.allkard+zip`. Registration with IANA is outside the scope of this revision.
## 11. Security considerations
- The signature binds `manifest.json` only. All manifest-listed bytes MUST be hashed.
- Malformed ZIP metadata and path traversal must be rejected (Section 2).
- A valid signature indicates that the witness signed the manifest at issuance time; it does not prove current ownership without Section 9 when applicable.
- Compromise of a witness private key affects all archives signed under that key id.
Vulnerability reports: see `SECURITY.md` in the reference repository.
## 12. Conformance
Reference vectors ship in the `conformance/` directory of the reference implementation. Independent implementations SHOULD produce equivalent pass/fail results for those vectors.
## 13. Revision history
| Revision | Changes |
|----------|---------|
| allkard/1.0 | Initial publication (this document) |
## 14. Normative references
- JSON Schema Draft 2020-12
- RFC 2119 (Key words for use in RFCs)
- RFC 8032 (Edwards-Curve Digital Signature Algorithm, EdDSA)
- RFC 8785 (JSON Canonicalization Scheme)
## 15. Informative references
- Reference implementation: `verifyKard`, `packKard` (`@allkard/core`)
- Optional verify parameter `trustedAuthorities` (reference SDK only): when provided, verification fails unless `witness.authority` matches a listed HTTPS origin or a wildcard host suffix such as `*.witness.example`. Omitting the parameter preserves neutral key discovery via `witness.keys_discovery`.