{"id":50486820,"url":"https://github.com/systemslibrarian/postquantum.fileformat","last_synced_at":"2026-06-01T23:02:33.373Z","repository":{"id":353011176,"uuid":"1217496336","full_name":"systemslibrarian/PostQuantum.FileFormat","owner":"systemslibrarian","description":"Draft specification for a hybrid post-quantum file encryption format. X25519+ML-KEM-1024 + Ed25519+ML-DSA-87. EXPERIMENTAL — seeking review.","archived":false,"fork":false,"pushed_at":"2026-05-30T00:24:27.000Z","size":1329,"stargazers_count":1,"open_issues_count":15,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-30T01:14:18.546Z","etag":null,"topics":["cryptography","dotnet","draft-spec","file-format","hybrid-encryption","post-quantum","specification"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/systemslibrarian.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":"MAINTAINERS.md","copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["systemslibrarian"]}},"created_at":"2026-04-22T00:17:18.000Z","updated_at":"2026-05-30T00:24:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/systemslibrarian/PostQuantum.FileFormat","commit_stats":null,"previous_names":["systemslibrarian/postquantum.fileformat"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/systemslibrarian/PostQuantum.FileFormat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2FPostQuantum.FileFormat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2FPostQuantum.FileFormat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2FPostQuantum.FileFormat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2FPostQuantum.FileFormat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/systemslibrarian","download_url":"https://codeload.github.com/systemslibrarian/PostQuantum.FileFormat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2FPostQuantum.FileFormat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33797128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-01T02:00:06.963Z","response_time":115,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cryptography","dotnet","draft-spec","file-format","hybrid-encryption","post-quantum","specification"],"created_at":"2026-06-01T23:02:32.601Z","updated_at":"2026-06-01T23:02:33.363Z","avatar_url":"https://github.com/systemslibrarian.png","language":"C#","funding_links":["https://github.com/sponsors/systemslibrarian"],"categories":[],"sub_categories":[],"readme":"# PQF — Post-Quantum File Format\n\nPQF is a specification and reference implementation for hybrid post-quantum encrypted files at rest.\n\n[![CI](https://github.com/systemslibrarian/PostQuantum.FileFormat/actions/workflows/ci.yml/badge.svg)](https://github.com/systemslibrarian/PostQuantum.FileFormat/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/systemslibrarian/PostQuantum.FileFormat/actions/workflows/codeql.yml/badge.svg)](https://github.com/systemslibrarian/PostQuantum.FileFormat/actions/workflows/codeql.yml)\n[![Differential](https://github.com/systemslibrarian/PostQuantum.FileFormat/actions/workflows/differential.yml/badge.svg)](https://github.com/systemslibrarian/PostQuantum.FileFormat/actions/workflows/differential.yml)\n[![Reproducible pack](https://github.com/systemslibrarian/PostQuantum.FileFormat/actions/workflows/reproducible-pack.yml/badge.svg)](https://github.com/systemslibrarian/PostQuantum.FileFormat/actions/workflows/reproducible-pack.yml)\n[![NuGet](https://img.shields.io/nuget/vpre/PostQuantum.FileFormat.Cli.svg?label=nuget%20%28pqf%29)](https://www.nuget.org/packages/PostQuantum.FileFormat.Cli/)\n[![Downloads](https://img.shields.io/nuget/dt/PostQuantum.FileFormat.Cli.svg)](https://www.nuget.org/packages/PostQuantum.FileFormat.Cli/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Spec: draft v0.6.0](https://img.shields.io/badge/spec-draft%20v0.6.0-orange.svg)](spec/PQF-SPEC-v1.md)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/systemslibrarian/PostQuantum.FileFormat/badge)](https://securityscorecards.dev/viewer/?uri=github.com/systemslibrarian/PostQuantum.FileFormat)\n[![codecov](https://codecov.io/gh/systemslibrarian/PostQuantum.FileFormat/branch/main/graph/badge.svg)](https://codecov.io/gh/systemslibrarian/PostQuantum.FileFormat)\n[![REUSE compliant](https://img.shields.io/badge/REUSE-compliant-success.svg)](LICENSE)\n\n## Quick start\n\nInstall the preview CLI as a [.NET global tool](https://learn.microsoft.com/dotnet/core/tools/global-tools) (requires the **.NET 10+ runtime** — the BCL native ML-KEM and ML-DSA APIs are mandatory):\n\n```bash\ndotnet tool install --global PostQuantum.FileFormat.Cli --prerelease\n```\n\nThen encrypt and decrypt a file end-to-end:\n\n```bash\npqf keygen   --type encrypt --public-out alice.pub.pem --private-out alice.key.json\npqf encrypt  --in secret.pdf --out secret.pqf --recipient alice.pub.pem\npqf inspect  --in secret.pqf\npqf decrypt  --in secret.pqf --out secret.dec.pdf --identity alice.key.json --mode authenticated\n```\n\n\u003e **Preview:** `pqf` is published as `0.6.0-preview.*`. The wire format is draft v0.6.0 (X-Wing + ML-KEM-768) and is **wire-incompatible** with v0.5.x and v0.3.x previews. Files produced by previews are not guaranteed to be readable by `v1.0.0`.\n\n## How to try it\n\nA self-contained roundtrip you can paste into a fresh shell. It creates a throwaway working directory, generates a sample plaintext, encrypts and signs it, inspects the container, decrypts in Authenticated Mode, and confirms the output matches the input byte-for-byte.\n\n```bash\n# 1. Install the CLI (skip if already installed)\ndotnet tool install --global PostQuantum.FileFormat.Cli --prerelease\n\n# 2. Set up a scratch directory\nmkdir -p /tmp/pqf-demo \u0026\u0026 cd /tmp/pqf-demo\n\n# 3. Generate a recipient encryption keypair and a signing keypair\npqf keygen --type encrypt --public-out alice.pub.pem  --private-out alice.key.json\npqf keygen --type sign    --public-out signer.pub.pem --private-out signer.key.json\n\n# 4. Create a sample plaintext\necho \"hello post-quantum world\" \u003e sample.txt\n\n# 5. Encrypt and sign\npqf encrypt --in sample.txt --out sample.pqf \\\n  --recipient alice.pub.pem \\\n  --signing-key signer.key.json\n\n# 6. Inspect the container without decrypting\npqf inspect --in sample.pqf\n\n# 7. Decrypt in Authenticated Mode (verify before releasing plaintext)\npqf decrypt --in sample.pqf --out sample.out.txt \\\n  --identity alice.key.json \\\n  --mode authenticated\n\n# 8. Confirm roundtrip\ndiff sample.txt sample.out.txt \u0026\u0026 echo \"OK: roundtrip verified\"\n```\n\nTo clean up: `cd ~ \u0026\u0026 rm -rf /tmp/pqf-demo`.\n\n## What this project is\n\n- A **file format specification** ([spec/PQF-SPEC-v1.md](spec/PQF-SPEC-v1.md), draft v0.6.0).\n- A **reference implementation** in .NET 10 ([src/PostQuantum.FileFormat](src/PostQuantum.FileFormat)).\n- A **command-line tool**, `pqf` ([cli/PostQuantum.FileFormat.Cli](cli/PostQuantum.FileFormat.Cli)).\n- A **deterministic-encoding, fail-closed parser** with no recovery paths.\n- A **test-vector and conformance model** ([tests/PostQuantum.FileFormat.TestVectors](tests/PostQuantum.FileFormat.TestVectors)) used to gate the implementation against the spec.\n\n## What this project is NOT\n\n- Not TLS or any transport-security protocol.\n- Not a messaging protocol.\n- Not a disk- or volume-encryption scheme.\n- Not an anonymity or metadata-privacy system.\n- Not production-certified cryptography. The format and code have not undergone external cryptographic review.\n\n## Core properties\n\n- **Fail-closed by design:** any malformed structure, unknown field, reserved bit, length mismatch, or integrity failure results in immediate refusal with a typed error. There are no best-effort or permissive parsing paths.\n- **Hybrid post-quantum encryption:** **X-Wing** (X25519 + ML-KEM-768) per draft-connolly-cfrg-xwing-kem, with external IND-CCA proofs in ROM/QROM (Barbosa et al., 2024). No bespoke combiner.\n- **Hybrid signatures (optional):** Ed25519 + ML-DSA-87, fixed 4691-byte concatenated layout. If signed, both halves must verify.\n- **Deterministic CBOR header** per RFC 8949 §4.2.2. Non-deterministic encodings are refused.\n- **Chunked AES-256-GCM payload** with per-chunk HKDF-derived keys, fixed zero nonce, and AAD binding `file_id || chunk_index || is_final`.\n- **Multi-recipient** in a single container, no payload duplication.\n- **Two decryption modes:**\n  - *Authenticated Mode* (default): verifies the file signature (when present) and footer before releasing any plaintext to the caller.\n  - *Streaming Mode*: releases verified chunks as they are read, with explicit, non-silent post-hoc signaling if the footer or file signature fails to verify. Streaming failures cannot be silently ignored by the caller.\n- **Fail-closed validation:** unknown fields, length mismatches, reserved bits, truncation, trailing bytes, and any algorithm deviation are refused. There are no permissive paths.\n\n## 60-second example\n\n```bash\n# Generate a recipient encryption keypair\npqf keygen --type encrypt \\\n  --public-out alice.pub.pem \\\n  --private-out alice.key.json\n\n# Generate a signing keypair\npqf keygen --type sign \\\n  --public-out signer.pub.pem \\\n  --private-out signer.key.json\n\n# Encrypt and sign a file\npqf encrypt \\\n  --in secret.pdf \\\n  --out secret.pqf \\\n  --recipient alice.pub.pem \\\n  --signing-key signer.key.json\n\n# Inspect header and footer metadata without decrypting\npqf inspect --in secret.pqf\n\n# Decrypt in Authenticated Mode (verify before releasing plaintext)\npqf decrypt \\\n  --in secret.pqf \\\n  --out secret.dec.pdf \\\n  --identity alice.key.json \\\n  --mode authenticated\n```\n\n- `.pqf` is the encrypted container: `PQF1` magic, deterministic CBOR header, optional 4691-byte header signature, AES-256-GCM chunks, 20-byte footer, and an optional 4691-byte file signature.\n- `pqf inspect` parses and prints the header and footer without touching plaintext.\n- `--mode authenticated` buffers verification before any plaintext is released. `--mode streaming` releases verified chunks as they are read and surfaces post-hoc verification failures explicitly.\n\nThe resulting `.pqf` file is a self-contained encrypted container: it bundles recipient-wrapped keys, chunked ciphertext, integrity metadata, and optional hybrid signatures in a single byte stream.\n\n## Repository structure\n\n```\nspec/                            Format definition and design rationale\n  PQF-SPEC-v1.md                 Normative specification (v0.6.0 draft)\n  PQF-DESIGN-RATIONALE-v1.md     Why the spec is what it is\n  ietf/                          Internet-Draft skeleton (work in progress)\nsrc/PostQuantum.FileFormat/      Reference .NET implementation\ncli/PostQuantum.FileFormat.Cli/  `pqf` command-line tool\nimpl/rust/pqf-reader/            Second-source Rust reader + cross-impl gate\ntests/PostQuantum.FileFormat.TestVectors/\n                                 Deterministic interoperability vectors\ntests/PostQuantum.FileFormat.Tests/\n                                 Validation, refusal, and roundtrip tests\ntests/PostQuantum.FileFormat.Cli.Tests/\n                                 CLI integration tests\ntests/PostQuantum.FileFormat.Fuzz/\n                                 Lightweight parser fuzz harness\ntests/PostQuantum.FileFormat.Kat/\n                                 NIST KAT (FIPS 203 / FIPS 204) cross-check harness\nexamples/                        Short integration scripts (e.g. tar | pqf encrypt)\nscripts/smoke.sh                 End-to-end roundtrip + refusal-path script (run by CI)\ndocs/                            Threat model, compatibility policy, side-channel posture\nSPEC-CHECKLIST.md                Per-section conformance checklist\nCONTRIBUTING.md                  How to file spec reviews, bugs, and PRs\nSECURITY.md                      Security-reporting policy and supported versions\nCODE_OF_CONDUCT.md               Contributor Covenant 2.1\n```\n\n## Security model\n\n- **Confidentiality:** holds if *either* the classical (X25519) or post-quantum (ML-KEM-768) primitive remains unbroken. A break of one half does not compromise the other.\n- **Authenticity:** present only when the file is signed. When signed, both Ed25519 and ML-DSA-87 must verify; either failure refuses the file.\n- **No anonymity guarantees.** PQF protects file contents at rest; it does not hide that a `.pqf` file exists, who the recipients are, or transport-layer metadata.\n- **Metadata is visible.** The header is unencrypted and includes algorithm IDs, recipient public-key material, signer public keys (when signed), `chunk_size`, and `created` timestamp. Treat it as visible.\n- **Side-channel posture is inherited from the underlying primitives.** The reference implementation is wired to verify before release and to run the recipient trial in constant time over recipient blocks. ML-KEM-768 and ML-DSA-87 are supplied by the native BCL types ([`System.Security.Cryptography.MLKem`](https://learn.microsoft.com/dotnet/api/system.security.cryptography.mlkem) and [`MLDsa`](https://learn.microsoft.com/dotnet/api/system.security.cryptography.mldsa)) on .NET 10, which are platform-backed (Linux OpenSSL 3.5+ via libcrypto; Windows CNG on 11 / Server 2025) and the strongest practical side-channel posture available today. BouncyCastle stays as a dependency only for X25519, Ed25519, and the FIPS 204 *deterministic* ML-DSA signing path used in byte-deterministic test-vector regeneration — none of which the BCL exposes natively yet. The full per-operation matrix — what the wrapper controls and what it inherits — is documented in [docs/SIDE-CHANNEL-POSTURE.md](./docs/SIDE-CHANNEL-POSTURE.md).\n- **Implementation correctness matters.** The format is fail-closed by design, but security still depends on a correct implementation of the spec, the underlying KEM/AEAD/signature primitives, and the host OS's randomness source.\n\n## Conformance philosophy\n\n- **Strict parsing.** Unknown fields at any header level are refused. Permissive CBOR parsing is non-conforming.\n- **Deterministic encoding required.** Headers must be re-encodable byte-for-byte; non-deterministic input is refused.\n- **MUST-level enforcement.** Every `MUST` in the spec corresponds to a refusal path in the reader, exercised by negative test vectors and refusal-test suites.\n- **No silent recovery.** There are no \"best effort\" paths. Any deviation from the spec terminates processing with an explicit, typed error.\n- **Conformance is testable.** [SPEC-CHECKLIST.md](SPEC-CHECKLIST.md) enumerates the normative items. The implementation is gated against committed test vectors under [tests/PostQuantum.FileFormat.TestVectors](tests/PostQuantum.FileFormat.TestVectors).\n\n## Performance\n\nIndicative numbers from a single-machine `BenchmarkDotNet` run on\n.NET 8.0.27 / Windows 11. **Not a substitute for measuring on your\nown hardware** — crypto throughput is dominated by primitive\nimplementations whose constant factors vary by CPU. The benchmark\nproject is `tests/PostQuantum.FileFormat.Bench`; the README in there\nexplains how to reproduce.\n\n| Operation | 64 KiB | 1 MiB | 16 MiB |\n|---|---:|---:|---:|\n| `Encrypt_unsigned` (single recipient) | ~1.1 ms | ~2.2 ms | ~18 ms |\n| `Decrypt_authenticated` (single recipient) | ~0.93 ms | ~2.3 ms | ~29 ms |\n| `Parse_header_only` | ~9 µs (independent of plaintext size) | — | — |\n\nAt 16 MiB plaintext this is roughly **0.9 GiB/s encrypt and\n0.6 GiB/s decrypt** on a single core, which is fast enough for\nfile-at-rest use cases and not fast enough for line-rate disk\nstreaming. The asymmetry — decrypt slower than encrypt — comes from\nAuthenticated Mode's verify-before-release contract: above its\nthreshold the reader stages plaintext to a 0600 tempfile so the file\nsignature can be verified before any byte is released.\n\nMulti-recipient cost (64 KiB plaintext, same machine):\n\n| Recipients | Encrypt | Decrypt as first | Decrypt as last |\n|---:|---:|---:|---:|\n| 1 | ~1.1 ms | ~0.98 ms | ~1.04 ms |\n| 4 | ~2.8 ms | ~3.2 ms | ~3.2 ms |\n| 16 | ~12.0 ms | ~10.4 ms | ~11.3 ms |\n| 64 | ~41.3 ms | ~39.3 ms | ~39.9 ms |\n\nEncrypt scales ~linearly in N as expected — one X25519/ML-KEM pair\nper recipient. **Decrypt is also ~linear in N**, which is the\nrecipient-trial loop running over every block to keep the timing\nindependent of *which* recipient holds the DEK. The\n\"decrypt-as-first\" vs \"decrypt-as-last\" gap is in the noise floor at\nevery N — that's the design working.\n\n## Current implementation limits\n\n- The legacy `PqfFileReader.OpenForValidation` helper still operates on a fully materialized byte buffer (preserved for tests and for callers who already have the file in memory). Production decryption now goes through `PqfStreamingPipeline`, which reads from a `Stream` directly: only the header (≤ 1 MiB per spec) and one in-flight chunk (≤ 16 MiB + AEAD tag) are buffered. Authenticated mode still stages plaintext to a 0600-mode `DeleteOnClose` tempfile above 100 MiB so the file signature can be verified before any byte is released to the destination — that staging is required by the security model, not by the parser.\n\n## Status\n\n- **Status:** Experimental. Specification is at draft v0.6.0.\n- **Not externally audited.** No independent cryptographic review has been performed.\n- **Not recommended for irreplaceable data.** The byte format is frozen only at v1.0.0; drafts may produce files that are not readable by the final release.\n- **Latest preview:** [`v0.4.0-preview.2`](https://github.com/systemslibrarian/PostQuantum.FileFormat/releases/tag/v0.4.0-preview.2) on `main`, published to NuGet as [`PostQuantum.FileFormat.Cli`](https://www.nuget.org/packages/PostQuantum.FileFormat.Cli).\n\n| Component | State |\n|---|---|\n| Specification | Draft v0.6.0 |\n| Reference implementation (.NET) | Phases 1–5 complete on `main`, CI green |\n| Test vectors | v1 set (positive + negative) committed; reproducibility gated on the unsigned subset |\n| CLI (`pqf`) | `keygen`, `encrypt`, `decrypt`, `inspect`, `fingerprint`; published as `0.4.0-preview.2` on NuGet.org |\n| Second-language implementation | Rust reader in `impl/rust/pqf-reader` + cross-impl conformance gate in CI |\n| Parser fuzz harness | `tests/PostQuantum.FileFormat.Fuzz` (CBOR / header / streaming targets); 60-second CI smoke pass |\n| NIST KAT cross-check | `tests/PostQuantum.FileFormat.Kat` scaffolded (verifies Decapsulate + Verify against FIPS 203/204 vectors when fetched) |\n| Constant-time evidence | dudect-style measurement scaffold under `tests/PostQuantum.FileFormat.Tests/Crypto`; skipped by default until baseline noise is characterized |\n| Supply-chain posture | OpenSSF Scorecard + CodeQL weekly; SLSA-L3 provenance + CycloneDX SBOM on release |\n| Threat model | Published — see [`docs/THREAT-MODEL.md`](./docs/THREAT-MODEL.md) |\n| Compatibility / freeze policy | Published — see [`docs/COMPATIBILITY.md`](./docs/COMPATIBILITY.md) |\n| External cryptographic review | Not started |\n\n## How PQF compares\n\nThis is a deliberately narrow comparison along the dimensions PQF cares\nabout. None of the rows are intended as criticism of the listed projects —\nthey have different goals, threat models, and audiences. PQF's distinguishing\nchoice is that *hybrid post-quantum confidentiality is the default*, not an\noptional extension, and the parser is fail-closed by construction.\n\n| Property | PQF (this project) | age | GPG (OpenPGP) | Tink | libsodium / NaCl box |\n|---|---|---|---|---|---|\n| Confidentiality primitives | X25519 **+ ML-KEM-768** via X-Wing (hybrid) | X25519 | RSA / ECDH (classical) | AEAD-only by default | X25519 |\n| PQ posture | Hybrid PQ by default | None (classical) | None (classical) | None | None |\n| Signatures | Optional hybrid: Ed25519 **+ ML-DSA-87** | None (encryption-only) | RSA / EdDSA (classical) | Signature primitives, classical | Ed25519 |\n| Wire format | Deterministic CBOR (RFC 8949 §4.2.2) | Custom textual + binary | OpenPGP packet format (RFC 9580) | Protobuf (keyset), per-primitive ciphertext | Raw concatenation |\n| Parser stance | Fail-closed, no recovery paths | Strict | Historically permissive | Strict | N/A (library, not a container) |\n| Multi-recipient in one file | Yes | Yes | Yes | No (per-key API) | No |\n| Streaming vs authenticated mode contract | Both, explicit non-silent failure signaling | Streaming | Streaming | API-level | API-level |\n| Spec frozen? | Draft v0.6.0 (v1.0.0 target) | Stable | Stable (RFC) | Stable (Google) | Stable |\n| External cryptographic audit | Not yet (review wanted) | Multiple reviews | Decades of scrutiny | Google + audits | Multiple reviews |\n\nIf you want a stable, audited classical format today, **age** is the right\nchoice for most file-at-rest cases. PQF is for callers who explicitly need\n\"this file should remain confidential against a quantum-capable adversary\ndecades from now, and I don't want a flag to forget.\"\n\n## Why not just use age, S/MIME, or OpenSSL CMS?\n\nThe honest answer per alternative — what each one gives you, what it\ndoesn't, and the specific reason PQF exists alongside them.\n\n### age (`age-encryption.org`)\n\n**Use age** if your threat model is anything other than HNDL with\nquantum capability. age is mature, audited multiple times, has a\ncleanly specified format, and is the right answer for the\noverwhelming majority of file-at-rest cases in 2026. Its X25519\nconfidentiality is excellent against today's adversaries.\n\n**PQF differs in one specific way:** age is purely classical. A 2026\nciphertext encrypted with age becomes recoverable to whoever owns a\ncryptographically-relevant quantum computer in 2035+. age has discussed\nPQ extensions (e.g. `age-plugin-xwing` exists) but the format\nitself is X25519-only by spec. PQF starts from \"hybrid PQ is the\ndefault, not a plugin\" and pays for that with a bigger wire format,\nyounger primitives, and a smaller audited history.\n\n### S/MIME (RFC 8551)\n\n**Use S/MIME** if you are operating inside an established X.509 PKI\n(corporate CA, certificate authorities, S/MIME-capable mail clients),\nand your audience has S/MIME-capable readers.\n\n**PQF differs in three significant ways:**\n\n1. S/MIME is CMS-based, which is a TLV format with a long history of\n   parser ambiguity and downgrade bugs (the format predates the\n   modern fail-closed design discipline). PQF uses deterministic CBOR\n   with a closed schema and refuses on any unknown field.\n2. S/MIME has no standardized hybrid PQ profile. There are CMS\n   extensions (`draft-ietf-lamps-cms-kemri`, `draft-ietf-lamps-pq-composite-kem`)\n   that aim to fix this, but they are drafts; PQF is also a draft, but\n   it picked a single standardized combiner (X-Wing) rather than\n   creating its own.\n3. S/MIME is bound to the X.509 ecosystem (issuer chains, CRLs / OCSP,\n   subject DNs). PQF is keypair-only by design — no CA, no revocation\n   semantics, no DN. That's a feature for some workflows and a missing\n   feature for others.\n\n### OpenSSL CMS (`openssl cms`)\n\n**Use `openssl cms`** if you need a battle-tested CLI that produces\nRFC 5652 CMS containers (the format S/MIME wraps) and you're willing\nto manage the X.509 plumbing yourself.\n\n**PQF differs in the same three ways as S/MIME**, plus a\nparser-stance difference: OpenSSL's CMS parser has historically been\npermissive (it has shipped fixes for malformed-input handling bugs as\nrecently as 2024). PQF's parser is fail-closed by design and rejects\nany structural variation, including non-deterministic CBOR encoding\nthat would still round-trip to the same logical structure.\n\n### PGP / GnuPG / OpenPGP (RFC 9580)\n\n**Use OpenPGP** if your audience has GPG-shaped tooling\n(Linux distros, Debian package signing, established PGP webs of\ntrust) and your threat model accepts classical-only confidentiality.\n\n**PQF differs significantly:**\n\n1. PGP is a packet format with decades of accumulated parser footguns;\n   the IETF is on RFC 9580 specifically because of those. PQF's\n   deterministic-CBOR-with-closed-schema is the modern version of\n   that lesson.\n2. PGP's PQ story is similar to S/MIME's: extension drafts exist\n   (X-Wing in OpenPGP is being discussed at the IETF), but the format\n   itself is classical. PQF picked the standardized X-Wing combiner\n   and made hybrid PQ the default.\n3. PGP's signature semantics carry web-of-trust baggage that PQF does\n   not. PQF signatures only attest \"this hybrid private keypair\n   produced these signature bytes over this exact header / file.\" Any\n   identity binding is the caller's responsibility.\n\n### Why use PQF at all, then?\n\nThe narrow case where PQF is the right tool: **you want a file format\nwhere (a) hybrid post-quantum confidentiality is the default not an\nextension, (b) the parser refuses every form of malformed input by\nconstruction not by convention, and (c) the implementation is small\nenough to read end-to-end in an afternoon.** Outside that case, the\nmature alternatives are better.\n\n## Why this exists\n\nExisting file-encryption formats either predate the post-quantum transition or treat post-quantum primitives as an optional extension. PQF starts from the assumption that confidential files written today may need to remain confidential against quantum-capable adversaries decades from now (\"harvest now, decrypt later\"), and that this should be the default rather than a bolt-on.\n\nPQF is **spec-first, not implementation-first.** The specification is the source of truth; the .NET reference implementation exists to prove the spec is implementable and to provide a conformance baseline for a future second-language implementation. Where the implementation and spec disagree, the spec wins.\n\n## Cryptographic review wanted\n\nPQF is explicitly seeking review from cryptographers and post-quantum implementers on the following normative sections of [spec/PQF-SPEC-v1.md](spec/PQF-SPEC-v1.md):\n\n- **§2.4** — Hybrid KEM combiner construction (HKDF salt/IKM layout, label binding). Note: the spec uses two distinct strings here — `pqf1-concat-extract-v1` is the algorithm-identifier value placed in the CBOR header field `alg.combiner`; `PQF1-combiner-v1` is the literal byte prefix of the HKDF salt. Both are intentional; the in-tree reference implementation lives in [`HkdfCombiner.cs`](src/PostQuantum.FileFormat/Crypto/HkdfCombiner.cs).\n- **§5.2** — Per-chunk AEAD construction and AAD binding (`file_id || chunk_index || is_final`).\n- **§6.2 step 9** — File-signature coverage composition (`file_id || sha256(chunks) || footer`).\n- **§6.3 step 7** — ML-KEM implicit-rejection timing and recipient-trial constant-time posture.\n- **§6.4** — Authenticated vs Streaming Mode failure-signaling contract.\n\nA running list of spec-level questions the author would value review on — including the open question of whether header-signature and file-signature messages should carry distinct domain-separation prefixes (§6.2), and whether the footer should be AEAD-bound on unsigned files — lives in [`spec/PQF-DESIGN-RATIONALE-v1.md` §11](./spec/PQF-DESIGN-RATIONALE-v1.md#11-open-questions-the-author-acknowledges).\n\nIf you find an issue, please open a [GitHub Issue](https://github.com/systemslibrarian/PostQuantum.FileFormat/issues) or start a thread under [Discussions](https://github.com/systemslibrarian/PostQuantum.FileFormat/discussions). Reproducible refusal cases are especially welcome and will be folded into the negative test-vector set.\n\n## Where to go next\n\n- [`spec/PQF-SPEC-v1.md`](./spec/PQF-SPEC-v1.md) — the authoritative format specification and conformance rules.\n- [`spec/PQF-DESIGN-RATIONALE-v1.md`](./spec/PQF-DESIGN-RATIONALE-v1.md) — why the spec is what it is; recommended reading before reviewing the format.\n- [`spec/ietf/draft-clark-pqf-00.md`](./spec/ietf/draft-clark-pqf-00.md) — kramdown-rfc Internet-Draft skeleton, work in progress.\n- [`docs/THREAT-MODEL.md`](./docs/THREAT-MODEL.md) — explicit threat model with a per-asset STRIDE table.\n- [`docs/COMPATIBILITY.md`](./docs/COMPATIBILITY.md) — versioning policy, v1.0.0 freeze contract, deprecation rules.\n- [`docs/DESIGN.md`](./docs/DESIGN.md) — long-form design narrative for non-cryptographers.\n- [`docs/CLAIMS-AND-EVIDENCE.md`](./docs/CLAIMS-AND-EVIDENCE.md) — every security claim PQF makes, paired with the artifact that backs it.\n- [`docs/FAQ.md`](./docs/FAQ.md) — common questions with hyperlinked answers.\n- [`docs/STREAMING.md`](./docs/STREAMING.md) — decision matrix for Streaming vs Authenticated Mode.\n- [`docs/INTEROP.md`](./docs/INTEROP.md) — living interoperability matrix.\n- [`docs/SIDE-CHANNEL-POSTURE.md`](./docs/SIDE-CHANNEL-POSTURE.md) — per-operation side-channel posture (what the wrapper controls, what it inherits, what's out of scope).\n- [`CHANGELOG.md`](./CHANGELOG.md) — Keep-a-Changelog history.\n- [`MAINTAINERS.md`](./MAINTAINERS.md) — who owns what, response-time expectations, disclosure window.\n- [`man/pqf.1`](./man/pqf.1) — manual page (`mandoc man/pqf.1`).\n- [`SPEC-CHECKLIST.md`](./SPEC-CHECKLIST.md) — per-section conformance items enumerated from the spec.\n- [`docs/internal/PHASE-NOTES.md`](./docs/internal/PHASE-NOTES.md) — implementation phase notes including any spec-ambiguity decisions made during the reference build.\n- [`CONTRIBUTING.md`](./CONTRIBUTING.md) — how to file spec reviews, bugs, and PRs; what gets accepted and what doesn't.\n- [`SECURITY.md`](./SECURITY.md) — how to report security-sensitive findings (private security advisory channel for exploitable issues).\n- [`CODE_OF_CONDUCT.md`](./CODE_OF_CONDUCT.md) — community standards.\n- [`examples/`](./examples/) — short scripts that show how PQF composes with familiar Unix pipelines (`tar | pqf encrypt`).\n- [`scripts/smoke.sh`](./scripts/smoke.sh) — end-to-end roundtrip + refusal-path script run by CI; the simplest way to validate a local build.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsystemslibrarian%2Fpostquantum.fileformat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsystemslibrarian%2Fpostquantum.fileformat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsystemslibrarian%2Fpostquantum.fileformat/lists"}