Skip to content
dssutgPublic

About

Asset-package compiler that reads MJSON source maps and emits encrypted, integrity-checked .pak files for games.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

mpack

An asset-package compiler implemented in Odin, per SPEC.md. It reads an asset source map (MJSON) and produces a single encrypted, integrity-checked, platform-independent .pak file that games load directly.

mpack [options] <source_map>

Building

Requires Odin. Only the console + core: libraries are used (no third-party code).

make            # or: odin build .
make vet        # odin vet .
make test       # builds, then runs test/run_tests.sh (all green)
make clean

Usage

mpack --root project --out build/assets --signing-key <hex64> assets/packages/units.mjson
mpack --gen-key ~/keys/pak           # writes ~/keys/pak (private) and ~/keys/pak.pub
mpack --inspect build/assets/x.pak --public-key $(cat ~/keys/pak.pub)
Flag Meaning
--root <dir> Project root. Map paths and entry patterns are project-root-relative. Defaults to the current directory.
--out <dir> Directory for <FNV32a(map path)>.pak. Created if needed.
--signing-key <hex64> Ed25519 private seed signing the ToC.
--gen-key <path> Generate a fresh Ed25519 keypair: seed at <path>, public key at <path>.pub.
--inspect <file.pak> Verify a package instead of packing.
--public-key <hex64> Enable the --inspect Ed25519 signature check.
--no-overwrite Refuse to replace an existing <hash>.pak.
--verbose Report per-package details on stderr.

Exit codes: 0 success, 1 packaging/verification/I-O failure, 2 bad CLI arguments.

Source maps

A source map is MJSON (Bitsquid SJSON) at a project-root-relative path such as assets/packages/units.mjson:

{
    assets = [
        {
            pattern = "data/units/unit1.bin",
            alias   = "data/units/unit1.alias.bin",
        },
        { pattern = "data/units/*.atlas",   no_compress = true, no_encrypt = true },
        { pattern = "data/ui/main.raw",     no_encrypt = true },
    ],
}
  • pattern (required) - a project-root-relative file path. If it contains glob metacharacters (*, ?, [) it is expanded (ascending) into one entry per match; a glob that matches nothing is an error.
  • alias (optional) - an extra logical key that resolves to the same payload bytes and inherits the entry's no_compress/no_encrypt flags. Not allowed on glob patterns (there is no single payload to share).
  • no_compress - store the payload raw; otherwise zlib (level 9), kept only when strictly smaller.
  • no_encrypt - store the payload in the plaintext tail (its 16-byte MAC tag is zeroed; the runtime detects plaintext slots by the all-zero tag).

Every entry's key (pattern, expanded match, or alias) is hashed with FNV32a and must be unique within the map; any collision is reported. Across maps, <root>/.mpack-registry records every hash -> map path pair. A map whose hash is already claimed by a different path aborts before any .pak is written.

The .pak format (summary)

Mirrors SPEC.md; the authoritative layout is the spec.

  • Header (56 bytes) - "MPAK", version (1), 16-byte ToC key seed, 12-byte ToC nonce, 16-byte ToC Poly1305 tag, u32 LE ToC size.
  • ToC (encrypted) - plaintext: u32 LE entry count, u32 hashes in ascending order (for runtime binary search), 72-byte descriptors (offset, uncompressed, compressed u32 LE, seed, nonce, sha256), a 64-byte Ed25519 signature over everything that precedes it, then zero padding so header + toc_size ≡ 0 (mod 64). The ToC is sealed with ChaCha20-Poly1305, authenticating the header (with its tag field zeroed) as AAD.
  • Payloads - one slot per entry: data-bytes (compressed or raw) + 16-byte MAC tag, padded to a 64-byte boundary. Encrypted entries come first (in declaration order), then the plaintext tail (declaration order). Descriptor sizes describe only the data. All integers are little-endian.

--inspect re-derives each per-entry key from its own seed, decrypts, decompresses, and checks each SHA-256, then checks the ToC tag (and optionally the Ed25519 signature).

Crypto interpretation notes

SPEC.md leaves these decisions open; the game runtime must match.

  1. Key derivation. The spec's derived key material is 16 bytes, but ChaCha20-Poly1305 (RFC 8439) requires a 256-bit key. derive_key produces the specified 16 bytes and expands them to 32 with SHA-256(derived). Rotating every key in a project means changing KDF_TABLE_SEED (crypto.odin) in both this tool and the runtime.
  2. Cascading tables. The 16 x 256 substitution tables are generated deterministically from KDF_TABLE_SEED (splitmix64 + Fisher-Yates) at first use. Odd seed bytes are nibble-swapped then two's-complement negated; even bytes pass through all sixteen tables.
  3. Per-slot tag. Each slot stores a 16-byte Poly1305 tag. Plaintext (no_encrypt) slots carry an all-zero tag, which is how the runtime distinguishes a plaintext slot from an encrypted one. Encrypted-slot data is authenticated with empty AAD.
  4. ToC AAD. The 56-byte header with the tag field zeroed is the ToC AEAD AAD; the computed tag is then written into the header.
  5. Dev signing key. Without --signing-key, packages are signed with the public dev seed 0001...1f. Such packages must not ship; pack unconditionally prints a warning.

Layout

config.odin    constants, Asset, Options
util.odin      FNV32a hashing, hex, u32 LE access, errorf
crypto.odin    key derivation, tables, AEAD + Ed25519 wrappers, entropy
map_pack.odin  MJSON parsing, glob/alias expansion, collision checks
pack.odin      layout, ToC build/sign/encrypt, slot writing, output
registry.odin  <root>/.mpack-registry load/check/commit
inspect.odin   verifier
main.odin      CLI, gen-key, exit codes, pack arena
test/          fixture project + end-to-end suite (run_tests.sh)

All allocations in a pack cycle come from a single virtual arena threaded as allocator; arena memory is never freed individually.

About

Asset-package compiler that reads MJSON source maps and emits encrypted, integrity-checked .pak files for games.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages