Encode files into resilient offline symbols. Decode them back with strong integrity checks.
Built for air-gapped transfer, noisy capture paths, and explicit recovery diagnostics.
- 🎯 What is zioncode?
- ✨ Highlights
- 🧭 When to use it
- 🏗️ Architecture
- 🚀 Quick Start
- 🧬 Codec Pipeline
- 🛡️ Layered Robustness
- 🗺️ Roadmap
- 🧪 Testing & Hardening
- 📐 Format Contract
- 🤝 Contributing
- 📜 License
zioncode is a Rust codec for moving files through hostile offline channels — think air-gapped machines, printed
paper, camera capture, or any path where the bytes leaving origin are not the bytes arriving at destination.
The v1 repository ships Subsystem A: the offline byte codec. It turns a file into one or more self-contained .zbin
symbols with compression, error-correction, interleaving, per-block and global integrity checks, and a typed reassembler
that reports which blocks are missing instead of just failing.
Optical rendering (Subsystem B) and camera decoding (Subsystem C) are intentionally separate future layers — the codec is an independently deliverable unit.
file bytes ─▶ zion-codec ─▶ .zbin symbols ─▶ [optical transport] ─▶ captured symbols ─▶ zion-codec ─▶ restored file
- 🚫
#![forbid(unsafe_code)]— pure safe Rust, clippy pedantic enabled - 🗜️ zstd per block with raw fallback when compression does not pay off
- 🛡️ Reed–Solomon profiles in GF(256) —
safe,balanced, anddensedensity modes - 🧵 Column-major interleaving — burst errors spread across codewords
- ✅ CRC32C per block + BLAKE3-256 global hash — layered integrity
- 🧩 Out-of-order symbol reassembly with typed error model (missing / duplicate / divergent)
- 🔬 Forensic mode — recover the structure even when the global hash diverges
- 🧪 Fuzz-hardened decoder (
cargo-fuzz, 30M+ execs, zero panics) - 📦 Frozen v1 wire format — spec lives next to the code
✅ Good fit
- Air-gapped transfer between networkless machines
- Transport over media that may corrupt, truncate, or duplicate bytes
- Pipelines that need to report why something could not be recovered
- Long-term archival where you want independent per-chunk integrity
❌ Not a fit
- Real-time streaming (this is a batch codec)
- Encryption at rest — integrity ≠ confidentiality; layer a cipher on top if needed
- Tiny payloads where ECC overhead dominates — you'll want a plain hash
flowchart LR
subgraph A["🧱 Subsystem A · offline codec ✅"]
direction TB
lib["zion-codec<br/><sub>library crate</sub>"]
cli["zion-cli<br/><sub>zion binary</sub>"]
cli --> lib
end
subgraph B["🖼️ Subsystem B · optical renderer 🔜"]
render["byte stream ➜ grayscale symbol"]
end
subgraph C["📷 Subsystem C · optical decoder 🔜"]
capture["image ➜ byte stream"]
end
file[("📄 file")] -->|encode| lib
lib -->|.zbin bytes| render
render -->|print / screen| world(((📡 air gap)))
world -->|camera / scan| capture
capture -->|.zbin bytes| lib
lib -->|decode| restored[("📄 restored file")]
classDef done fill:#10B981,stroke:#065F46,color:#fff
classDef todo fill:#1F2937,stroke:#4B5563,color:#9CA3AF,stroke-dasharray: 5 5
class A done
class B,C todo
| Path | Responsibility | Status |
|---|---|---|
zion-codec/ |
Core library: format, compression, ECC, encode, decode, reassembly | ✅ v1 |
zion-cli/ |
Thin zion CLI around the library |
✅ v1 |
zion-codec/tests/ |
Roundtrip + property-based invariants | ✅ v1 |
zion-codec/benches/ |
Criterion benchmarks for hot paths | ✅ v1 |
fuzz/ |
cargo-fuzz targets (nightly) |
✅ v1 |
docs/superpowers/specs/ |
Source of truth for v1 wire format | ✅ v1 |
📦 Encode a file into symbols
cargo run -p zion-cli -- encode ./input.bin --output-prefix ./out/input
# ▶ writes ./out/input_000.zbin, ./out/input_001.zbin, ...By default, the CLI chooses an automatic K that minimizes emitted bytes for the selected profile. Override with --k
when a renderer needs a fixed physical symbol size.
Profiles:
--profile safe # RS(255,223), strongest default profile
--profile balanced # RS(255,239), lower overhead, less correction
--profile dense # RS(255,247), lowest overhead, smallest correction budgetTune compression with --zstd-level (3 · 6 · 9).
🔍 Inspect a single symbol
cargo run -p zion-cli -- inspect ./out/input_000.zbinPrints the parsed header: ECC profile, file_id, symbol_index, block_start/count, global BLAKE3 hash, and block status.
🔄 Decode back into a file
cargo run -p zion-cli -- decode ./out/input_*.zbin --output ./restored.binSymbols can be passed in any order — the reassembler sorts them via symbol_index. Use --force-write-corrupt only
for forensic recovery when the global hash does not match.
🧰 Use it as a library
use zion_codec::{Decoder, Encoder, EncoderConfig};
let config = EncoderConfig::fixed_k(148)?;
let encoded = Encoder::new(config).encode(&file_bytes)?;
let restored = Decoder::default().decode_file(&encoded.symbols)?;
assert_eq!(restored, file_bytes);flowchart TD
raw([📄 raw file])
raw --> split["🪓 split · 8 KiB blocks"]
split --> zstd{{"🗜️ zstd vs raw<br/><sub>pick whichever is smaller</sub>"}}
zstd --> pack["📦 greedy packing<br/><sub>up to 4 blocks / symbol</sub>"]
pack --> hdr["🧾 header · 82 B<br/><sub>magic, version, file_id, index</sub>"]
hdr --> crc["🧮 CRC32C · per block"]
crc --> ecc["🛡️ Reed-Solomon profile<br/><sub>safe · balanced · dense</sub>"]
ecc --> inter["🧵 column-major interleave"]
inter --> sym([🔣 .zbin symbol])
sym -.capture / transport.-> sym2([🔣 received symbol])
sym2 --> dinter["↔️ deinterleave"]
dinter --> rsd["🛡️ RS decode<br/><sub>profile auto-detected</sub>"]
rsd --> verify["🧮 verify block CRCs"]
verify --> reasm["🧩 reassemble blocks<br/><sub>out-of-order · duplicates ok</sub>"]
reasm --> blake["🔐 BLAKE3-256 global check"]
blake --> out([📄 restored file])
classDef pipe fill:#0F172A,stroke:#334155,color:#E2E8F0
classDef decision fill:#4338CA,stroke:#1E1B4B,color:#fff
classDef io fill:#10B981,stroke:#065F46,color:#fff
class split,pack,hdr,crc,ecc,inter,dinter,rsd,verify,reasm,blake pipe
class zstd decision
class raw,sym,sym2,out io
| # | Layer | Scope | What it catches |
|---|---|---|---|
| 1 | zstd + raw fallback | per 8 KiB block | Incompressible data does not inflate |
| 2 | CRC32C | per block | Local payload corruption (single-block loss is recoverable) |
| 3 | Reed–Solomon profile | per codeword | safe corrects up to 16 byte errors; balanced 8; dense 4 |
| 4 | Column-major interleave | per symbol | Bursts of errors get spread across codewords |
| 5 | Header CRC32C | per symbol | Malformed metadata fails fast, not loud |
| 6 | BLAKE3-256 | whole file | End-to-end tamper detection across symbols |
| 7 | Typed reassembler | whole file | MissingBlocks, DuplicateSymbol { divergent }, InconsistentFileMetadata, GlobalHashMismatch |
| Milestone | Subsystem | State |
|---|---|---|
| M1 · v1 freeze | wire format, constants, error model | ✅ |
| M2 · codec core | encode / decode / reassemble / tests | ✅ |
| M3 · hardening | property tests, cargo-fuzz, criterion benches |
✅ |
| M4 · optical renderer | byte stream → grayscale PNG (subsystem B) | 🔜 |
| M5 · optical decoder | camera frame → byte stream (subsystem C) | 🔜 |
M6 · .zion container |
PNG + sidecar metadata, unified file extension | 🔜 |
cargo test --workspace # unit + integration + property tests
cargo clippy --all-targets --all-features # pedantic lints, -D warnings
cargo fmt --all --check # formatting gate
cargo bench -p zion-codec # criterion hot pathsFuzzing needs nightly (see CLAUDE.md):
cd fuzz
rustup run nightly cargo fuzz run decode_full -- -max_total_time=30
rustup run nightly cargo fuzz run parse_header -- -max_total_time=30
rustup run nightly cargo fuzz run parse_block -- -max_total_time=30Invariants pinned by property tests — output.len() == K * 255, byte-identical roundtrip on clean streams, bounded
corruption within ECC tolerance always recovers, duplicate symbols merge useful blocks, structural divergence is
rejected.
The v1 binary format is frozen and lives in:
docs/superpowers/specs/2026-04-23-zioncode-codec-offline-design.md
Any change to the header layout, ECC parameters, interleaving, block packing, validation invariants, error semantics or compatibility rules must update the spec first and, when breaking, bump the version byte in the header.
We follow the superpowers workflow: brainstorming → writing-plans → subagent-driven-development, one commit
per logical step with gitmoji-prefixed subjects in English.
See CONTRIBUTING.md for the full checklist (fmt, clippy, tests, fuzzing, PR template).
Security-sensitive parser or decoder changes should include malformed-input coverage and, when relevant, fuzz target
updates.
Dual-licensed under either of:
- Apache License, Version 2.0 (
LICENSE-APACHE) - MIT License (
LICENSE-MIT)
at your option. See LICENSE for the pointer file.
Built with 🦀 · Hardened with 🧪 · Signed with 🔐