Post-quantum encrypted file relay. Burn-on-read. EU jurisdiction. Self-hostable in 2 minutes.
Data is encrypted client-side with ML-KEM-768 + AES-256-GCM, relayed through RAM only, and destroyed after one download. Nothing is ever written to disk. Every transfer is recorded in a public Merkle tree — proving delivery without storing content.
# 1. Clone
git clone https://github.com/Apolloccrypt/paramant-relay && cd paramant-relay
# 2. Configure
cp .env.example .env
echo "ADMIN_TOKEN=$(openssl rand -hex 32)" >> .env
# 3. Launch (6 containers: 5 sector relays + admin panel)
docker compose up -d
# 4. Verify
curl http://localhost:3001/health
# {"ok":true,"version":"3.0.0","sector":"health","edition":"licensed"}Or on a Raspberry Pi / fresh VPS:
curl -fsSL https://paramant.app/install-pi.sh | bashOr via the browser — no install: Try ParaShare → (no account, no key needed)
Create a free account → (TOTP, no password)
Get a free API key → (email delivery, 30-second form)
As of the M5b release, PARAMANT's crypto layer is migrating from pure JavaScript
(@noble/post-quantum) to a Rust core via the
@paramant/core NAPI binding.
In production as of 3.0.0: ML-KEM-768 keygen (M5b) and server-side ML-DSA-65
signing — the relay identity, delivery receipts and signed tree heads now run on
@paramant/core. Later releases migrate the remaining call sites (AEAD on the
hot path, hybrid KEM). The wire format and client behavior are unchanged at each
step -- this is an internal implementation swap.
Why a separate repo:
- Audit clarity: crypto reviewers work on paramant-core's small Rust codebase without the HTTP, admin, and billing layers.
- Cross-language reuse: the same Rust crypto serves this relay (Node.js via NAPI), the SDKs, and native apps.
- Compliance: 325 KAT vectors, 21 ADRs, byte-equivalence proven across three
implementations (oqs server-side, RustCrypto browser-side,
@noblereference).
Browser-side crypto (parashare, ontvang) lives vendored in
crypto-wasm/ (RustCrypto, compiled to wasm32). It is validated
against paramant-core via the cross-impl-validator crate there (ADR-0020,
ADR-0021). See
paramant-core/docs/ARCHITECTURE.md
for the full cross-repo overview.
3.0.0 keeps the wire format, API surface and crypto guarantees of 2.5.x — every 2.5.x client stays compatible — and concentrates on the operator and self-host experience. Status: M5b is live (crypto split), with the M11 onboarding and admin features landing in the 3.0.0 release.
- paramant-core crypto split (M5b). Server-side ML-DSA-65 signing now runs on
the standalone
@paramant/coreRust library via its NAPI binding; client-side ML-KEM-768 still runs in the browser/SDK. The relay never holds a key. - First-run setup wizard. A web wizard at
/setupreplaces hand-run admin scripts — admin token, TOTP and first key from the browser (ADR R005). - Visual admin config + in-browser CLI.
/admin/settingsedits relay config without touching.env;/admin/cliis a web terminal for debugging without SSH. - Document workspace. The user dashboard starts signing and delivery flows, lists account-owned envelopes and exposes lifecycle actions on desktop and mobile.
- Crypto-mode negotiation.
/v2/capabilitiesadvertises a compactcoremode (2 algorithms) by default; extended sets are opt-in viaCRYPTO_MODE(ADR R006). - Add-on architecture (spec). Container-isolated integrations that work on ciphertext and metadata only (ADR R007, draft).
- Static front-end serving. Opt-in
SERVE_FRONTEND=1lets a single relay serve its own UI for plug-and-play self-hosting (ADR R011).
| ADR | Topic | Status |
|---|---|---|
| R005 | Plug-and-play onboarding (/setup wizard) |
Draft |
| R006 | Crypto-mode opt-in (core default / extended) |
Accepted |
| R007 | Add-on architecture (manifest, lifecycle, security) | Draft |
| R011 | Static front-end serving (SERVE_FRONTEND) |
Accepted |
Full set: docs/adrs/ (R001–R011).
| Feature | Status |
|---|---|
| Post-quantum file relay (ML-KEM-768 + AES-256-GCM) | Live — all 5 sector relays |
| Anonymous drop (no account, 12-word mnemonic) | Live — paramant.app/drop |
| User accounts with TOTP (no password required) | Live — paramant.app/signup |
| Admin dashboard (Overview, Users, Audit, Billing, Relay) | Live — /admin/ |
| Resend TOTP setup link | Live — admin panel |
| ParaSign developer settings and API keys | Live at paramant.app/developer |
| Billing | Operator-managed. Hosted paramant.app uses Mollie; bundled admin tool has Stripe device-sync hooks |
| Chromium browser extension | Source in repo — server-side encryption path during client-side PQ migration (architecture §08) |
| Outlook Add-in | Source in repo — server-side encryption path during client-side PQ migration (architecture §08) |
Zero-knowledge scope: the relay-cannot-read guarantee applies to transfers from the official SDKs (paramant-sdk for Python and JavaScript), the WebApp tools (ParaShare), and the anonymous /send flow. The Chromium and Outlook extensions currently take a server-side encryption path while their client-side hybrid crypto is being finished — until that lands, treat extension uploads as relay-side, not zero-knowledge.
Sender Ghost Pipe Relay Receiver
------ ---------------- --------
file.pdf RAM only — no disk writes file.pdf
│ burn-on-read ▲
▼ 5 MB fixed padding │
encrypt(ML-KEM-768) ───► hash → Merkle CT log ────► decrypt(ML-KEM-768)
X-Api-Key header blob destroyed on read X-Api-Key header
What the relay never sees: plaintext, encryption keys, filenames, or recipient identity.
What it does see: fixed-size (5 MB) ciphertext blobs, blob hashes, API key identifiers.
Every transfer is hashed into a SHA3-256 Merkle tree. The relay signs each tree head with ML-DSA-65 and publishes it publicly — anyone can verify that a specific blob was delivered, and that the log has not been tampered with, without reading its contents.
ParaSign is the second product on the PARAMANT relay: post-quantum document signing, alongside the encrypted file transfer described above. Same relay, same notary invariant, a different job. Instead of moving a file and burning it, ParaSign proves who signed what, and when, with a signature that survives the arrival of quantum computers.
For PDF files, the browser can place the visible seal on one page, repeat it on every page, or append a separate signature sheet. The sheet includes the visible signer seal, source filename, source page count, signing time and SHA3-256 source hash. Later co-signers remain part of the cryptographic .psign envelope and are not retroactively painted into the PDF.
- Post-quantum signatures. Every signature is ML-DSA-65 (NIST FIPS 204). No RSA and no ECDSA on the signing path.
- Envelopes. A signing request is an envelope: one document, one or more signers, an optional signing order, and a TTL.
- Multi-signer. Route a single document to several signers; the envelope completes only when every party has signed.
- Hosted signing ceremony. Each signer gets a hosted browser page and signs there. The signing key is generated and used client-side, so a private key never reaches the relay.
Signature level: ParaSign produces advanced electronic signatures (AES) as understood under eIDAS. It is explicitly NOT an eIDAS-qualified signature (QES). There is no qualified trust service provider and no qualified certificate on this path, and ParaSign makes no qualified-signature claim.
When an envelope completes, ParaSign issues a .psign receipt: a compact, canonical-JSON proof that is self-contained and verifiable offline. It binds together:
| Field | What it proves |
|---|---|
| Signer public key | who signed |
| Timestamp | when they signed |
| ML-DSA-65 signature per party | that this signer, and only this signer, signed this document |
| Document hash (SHA3-256) | which document, without ever revealing its contents |
| Relay notary countersignature | that the relay witnessed the ceremony and logged it |
A .psign is independently verifiable with no call back to the relay: re-check each ML-DSA-65 signature against the signer public key, verify the notary countersignature against the relay public key, and confirm the envelope's inclusion in the public CT log (the same SHA3-256 Merkle tree that backs file transfers). You verify the math, not the operator.
The signed-in document workspace reads account-scoped envelope metadata. An owner
can cancel an open request and download the .psign proof for a completed request.
Cancellation removes the encrypted document capsule immediately. The workspace
does not claim to recover plaintext. Users keep the signed document and proof
together and can verify them later in Paramant.
The relay is a notary, not a reader. What it retains for an envelope is the SHA3-256 document hash, never the document content, and it never holds a signing private key. In the hosted /v1 ceremony the relay does hold the raw document blob, but only for the lifetime of that ceremony, and it is dropped on TTL expiry. Nothing but the hash persists.
A thin, public /v1 layer lets any application create envelopes and collect signatures without a browser session, using an API key. It wraps the internal envelope machinery.
Authentication is a Bearer token: an API key with the psk_ prefix (psk_live_ for production, psk_test_ for the sandbox) that carries the parasign scope. A key without that scope is rejected.
| Method and path | Purpose |
|---|---|
| POST /v1/envelopes | Create an envelope from a PDF plus a signer list; returns the envelope id and one hosted sign_url per signer. |
| GET /v1/envelopes/:id | Read envelope status and per-signer progress. |
| GET /v1/envelopes/:id/receipt | Download the full .psign proof once the envelope is complete. |
| GET /v1/envelopes/:id/document | Download the signed PDF once the envelope is complete. |
| POST /v1/envelopes/:id/void | Void an open envelope (owner only). |
# 1. Create an envelope. The document is sent as base64; signers are routed to
# hosted signing pages.
curl -X POST https://paramant.app/v1/envelopes \
-H "Authorization: Bearer psk_live_..." \
-H "Content-Type: application/json" \
-d '{
"document": { "content_base64": "JVBERi0xLjc..." },
"original_filename": "quote-8842.pdf",
"signers": [
{ "name": "Signer One", "email": "signer@example.com", "order": 1 }
],
"webhook_url": "https://app.example.com/hooks/parasign"
}'
# 201 -> { "id": "env_...", "status": "sent",
# "signers": [ { "sign_url": "https://paramant.app/..." } ],
# "webhook_secret": "..." } # returned once, for HMAC verification
# 2. The signer opens sign_url and signs ML-DSA-65 client-side (hosted ceremony).
# 3. On completion, pull the full .psign proof.
curl https://paramant.app/v1/envelopes/env_.../receipt \
-H "Authorization: Bearer psk_live_..." \
--output quote-8842.psignWebhooks: point webhook_url at your endpoint and the relay posts envelope lifecycle events (for example envelope.sent and envelope.voided), each signed with HMAC-SHA256 in the X-Paramant-Sig header, so you do not have to poll. The webhook secret is returned once, in the create response.
Pricing for signing volume lives with everything else at https://paramant.app/pricing.
Licensing: ParaSign runs on the same source-available relay (BUSL-1.1). The client SDKs are open source (Apache-2.0).
# Send MRI scan to specialist — burned after one download
python3 paramant-sender.py \
--key pgp_xxx --device mri-001 --sector health scan.dcm
# Receive and forward to PACS system
python3 paramant-receiver.py \
--key pgp_xxx --stream --forward https://pacs.hospital.nl/api
# Structured referral (HL7 FHIR R4)
paramant-referral referral.json --type fhir --from gp-001 --to cardiology-umcg→ NEN 7510 compliance · DICOM setup guide
# Send signed deed — cryptographically gone after receipt, CT log proof preserved
paramant-notary deed.pdf --sign --receipt
# Court documents with case reference
paramant-legal summons.pdf --case ROT-2026-1234 --proof# PLC telemetry — no VPN, no direct OT exposure to internet
python3 paramant-sender.py \
--heartbeat 15 --device plc-factory-01 --sector iot data.bin
# Firmware update to body cams / IoT device fleet
paramant-firmware update-v2.1.bin \
--sign --device-group bodycams.txt --version 2.1# ISO 20022 payment file relay with Merkle audit trail
python3 paramant-sender.py \
--watch /export/iso20022/ --device bank-nl-01 --sector finance
# Every transfer produces a CT log entry for DORA audit
curl https://finance.paramant.app/v2/ct -H "X-Api-Key: pgp_xxx"# Bulk payslip delivery — no email, no storage, no GDPR risk
paramant-payslip \
--bulk employees.csv --dir ./payslips/april/# CI/CD: sign + relay build artifacts with SBOM
paramant-cra dist/app-v1.2.tar.gz \
--sbom sbom.json --sign --registry https://registry.company.nl/apiFive live relays — each tuned for its compliance domain:
| Subdomain | Sector | Port | Compliance |
|---|---|---|---|
| relay.paramant.app | General | 3000 | — |
| health.paramant.app | Healthcare | 3001 | NEN 7510, DICOM, HL7 FHIR |
| legal.paramant.app | Legal/Notary | 3003 | eIDAS, KNB |
| finance.paramant.app | Finance | 3002 | NIS2, DORA, ISO 20022 |
| iot.paramant.app | Industrial IoT | 3004 | IEC 62443, EU CRA |
All five run the same codebase — the SECTOR env var determines which compliance mode activates.
git clone https://github.com/Apolloccrypt/paramant-relay
cd paramant-relay
cp .env.example .env
echo "ADMIN_TOKEN=$(openssl rand -hex 32)" >> .env
docker compose up -dThis starts 6 containers: 5 sector relays + admin panel. System nginx handles TLS.
| Container | Host port | Public URL |
|---|---|---|
| relay-main | 127.0.0.1:3000 | relay.your-domain |
| relay-health | 127.0.0.1:3001 | health.your-domain |
| relay-finance | 127.0.0.1:3002 | finance.your-domain |
| relay-legal | 127.0.0.1:3003 | legal.your-domain |
| relay-iot | 127.0.0.1:3004 | iot.your-domain |
| admin | 127.0.0.1:4200 | your-domain/admin/ |
curl -fsSL https://paramant.app/install-pi.sh | bash
# Detects Pi model, installs Docker, disables swap, prints relay URLcurl -fsSL https://paramant.app/install.sh | bash
# Brings the relay up and opens the first-run /setup wizard in the browser
# (admin token, TOTP, first key — falls back to a localhost URL on headless hosts).
# Set SERVE_FRONTEND=1 to serve the UI from the relay itself; CRYPTO_MODE selects
# the algorithm set advertised on /v2/capabilities (ADR R005, R006, R011).Flash paramantOS to USB — relay starts on boot.
curl -X POST https://health.paramant.app/v2/inbound \
-H "X-Api-Key: pgp_your_key" \
-H "Content-Type: application/json" \
-d '{"hash":"sha256_of_payload","payload":"base64_5mb_blob","ttl_ms":3600000}'
# Returns: {"blob_hash":"sha256...","ttl":3600}curl https://health.paramant.app/v2/outbound/abc123... \
-H "X-Api-Key: pgp_your_key" --output received-file.bin
# Blob is destroyed immediately after this responsecurl https://health.paramant.app/health
# {"ok":true,"version":"3.0.0","sector":"health","edition":"licensed"}# Latest Signed Tree Head — ML-DSA-65 signed, public
curl https://relay.paramant.app/v2/sth
# {"ok":true,"sth":{"relay_id":"relay.paramant.app","sha3_root":"c7a9…","tree_size":43,"timestamp":1744123456789,"signature":"…"}}
# Verify the signature
paramant-verify-sth --relay https://relay.paramant.app
# Relay identity public key (for independent signature verification)
curl https://relay.paramant.app/v2/pubkey
# {"ok":true,"alg":"ML-DSA-65","public_key":"base64…","pk_hash":"sha3-256…"}
# Verify a delivery receipt
curl -X POST https://relay.paramant.app/v2/verify-receipt \
-d '{"receipt":"<base64url from X-Paramant-Receipt header>"}'
# {"valid":true,"blob_hash":"a3f2…","burn_confirmed":true}Full API reference: docs/api.md
All 44 paramant-* tools are included in paramantOS and installable via .deb:
curl -fsSL https://paramant.app/install-client.sh | bashparamant-help # full command reference
paramant-setup # first-time wizard (key + relay URL)
paramant-status # relay health across all sectors
paramant-doctor # automated health check
paramant-relay-setup # clone + configure + start relay
paramant-referral # healthcare referral (NEN 7510, HL7 FHIR, DICOM)
paramant-notary # legal document transport (eIDAS, KNB)
paramant-legal # court document relay (replaces Zivver)
paramant-payslip # HR payslip distribution (GDPR)
paramant-firmware # IoT/body cam firmware updates (IEC 62443)
paramant-cra # software supply chain relay (EU CRA 2027)
paramant-ticket # one-time transit ticket issuer/verifier
paramant-keys # list all API keys
paramant-key-add # add new API key
paramant-key-revoke # revoke an API key
paramant-verify-sth # fetch /v2/sth + /v2/pubkey, verify ML-DSA-65 signature
paramant-receipt # view, save, or verify a delivery receipt
paramant-verify-peers # cross-check STH consistency across all peer relays
security-status # all security layers at a glance
paramant-ports # firewall rules + listening ports
paramant-scan # LAN relay discovery + registry
paramant-verify # TOFU fingerprint verification
paramant-crypto-audit # scan for quantum-vulnerable algorithms
paramant-hybrid-check # verify PQC hybrid mode is active
paramant-backup # backup keys + CT log
paramant-restore # restore from backup
paramant-export # export audit log to USB
paramant-logs # live log stream
paramant-update # check for updates
paramant-migrate # migrate relay data between versions
paramant-roadmap # PQC migration roadmap generator
paramant-supply-chain # software supply chain audit
pip install paramant-sdkfrom paramant import GhostPipe
gp = GhostPipe(api_key="pgp_xxx", device="device-001", sector="health")
# Send — returns (hash, inclusion_proof)
hash_, proof = gp.send(open("scan.dcm", "rb").read(), ttl=3600)
# proof contains leaf_hash, leaf_index, tree_size, audit_path, root, sth
# Receive — returns (data, receipt)
data, receipt = gp.receive(hash_)
# receipt contains blob_hash, burn_confirmed, tree_size_at_retrieval, ML-DSA-65 signature
# Verify receipt (calls POST /v2/verify-receipt)
result = gp.verify_receipt(receipt)
assert result["valid"]
# Anonymous drop with 12-word mnemonic
mnemonic = gp.drop(b"sensitive data", ttl=3600)
data, _ = gp.receive(mnemonic)The relay is untrusted by design — it never holds a decryption key.
| What a compromised relay can do | What it cannot do |
|---|---|
| Deny service | Read file contents |
| Learn transfer timing | Decrypt any stored ciphertext |
| See blob sizes (fixed 5 MB) | Substitute a registered public key once a fingerprint has been verified out-of-band (TOFU on first contact — verify the recipient's fingerprint via a separate channel before sending) |
Crypto stack:
| Layer | Standard |
|---|---|
| Key encapsulation | ML-KEM-768 · NIST FIPS 203 |
| Hybrid KEM (browser path) | ML-KEM-768 + ECDH P-256, combined via HKDF-SHA256 |
| Symmetric | AES-256-GCM · NIST SP 800-38D |
| Signatures (relay STH / receipts) | ML-DSA-65 · NIST FIPS 204 |
| Signatures (client, SDK only) | ML-DSA-65 over ctKem ‖ senderPub ‖ nonce ‖ ct ‖ aad (Node/Python SDK; browser ParaShare path does not yet sign client-side) |
| Key derivation | HKDF-SHA256 · RFC 5869 |
| Password blobs | Argon2id · RFC 9106 |
| Crypto runtime | Rust/WASM — browser-side encryption runs in native code |
| Storage | RAM only — never written to disk |
| Padding | 5 MB fixed — all transfers look identical (DPI masking) |
| Audit log | SHA3-256 Merkle tree — tamper-evident, public |
| Infrastructure | Hetzner Frankfurt DE — EU jurisdiction only, no US CLOUD Act |
| Docker | cap_drop ALL, no-new-privileges, read-only rootfs |
Security audits (April 2026):
- 2026-04-19 — internal automated audit (6-layer + load test): 0 critical · 0 high · 2 medium (fixed) · 1 low (fixed) · 11 passing checks. Load tested to 500 req/s, p95 latency 135 ms, zero errors. Full report
- 2026-04-15 — R. Zwarts RAPTOR review: 10 findings (3 high · 3 medium · 4 low), all resolved. Commit 769f163
- 2026-04-13 — R. Zwarts dependency review: 0 npm vulnerabilities. Node 20 EOL → node:22-alpine. express 4.x → 5.x. Commit e6f216d
- 2026-04-11 — R. Zwarts verification review: 14 findings (1 high · 8 medium · 5 low), all resolved. Commit e6f216d
- 2026-04-10 — R. Zwarts independent audit: 6 findings (3 high · 3 medium), all resolved. Commit 0db3ef0
- 2026-04-08 — Ryan Williams, Smart Cyber Solutions (AU): 4 critical · 5 high · 6 medium · 5 low. Full report
All findings publicly documented in SECURITY.md.
Every transfer is appended to a public SHA3-256 Merkle tree. The trust model mirrors RFC 6962: you don't trust the relay operator, you verify the math.
| What you can prove | How |
|---|---|
| A specific blob was uploaded | merkle_proof in POST /v2/inbound response |
| A specific blob was delivered and burned | X-Paramant-Receipt header on GET /v2/outbound |
| Receipt is genuine and unmodified | POST /v2/verify-receipt |
| Log has not been forked | GET /v2/sth/consistency?from=N&to=M |
| Peer relays agree on the tree | GET /v2/sth/peers |
# Independent verification — no trust required
curl https://relay.paramant.app/v2/sth # latest tree root
curl https://relay.paramant.app/v2/pubkey # relay signing key
paramant-verify-sth --relay https://relay.paramant.app
paramant-verify-peers
# RSS archiving (subscribe to independently retain signed tree heads)
curl https://relay.paramant.app/ct/feed.xml
# Public web UI
open https://relay.paramant.app/ct/| Regulation | Status | Details |
|---|---|---|
| NIS2 (EU 2022/2555) | Self-assessed | Compliance page |
| NEN 7510 (Healthcare NL) | Self-assessed* | Compliance page |
| IEC 62443 (Industrial IoT) | Self-assessed | Compliance page |
| DORA (Finance EU) | Partial | Transit encryption supports DORA Art. 6 (ICT risk management); broader DORA scope not covered |
| EU CRA 2027 | Designed for | paramant-cra tool + CT log |
| GDPR Art. 28 | Available | DPA |
"Self-assessed" means Paramant's own architectural mapping to the framework, not a certification or audit by an accredited third party.
*NEN 7510: finding #4 (filename in transit RAM) patched in v2.4.5 — filename encrypted in relay RAM and never written to disk.
Tiers, limits, and current prices are maintained on the website:
API key signup: https://paramant.app/signup
| docs/api.md | Full API reference — all endpoints, request/response formats |
| docs/self-hosting.md | Docker deploy, nginx, TLS, env vars, upgrade |
| docs/dicom-guide.md | Healthcare sector — DICOM gateway, HL7 FHIR, NEN 7510 |
| docs/licensing.md | Key types, edition limits, Ed25519 enforcement |
| docs/security.md | Threat model, crypto stack, audit reports |
| Apolloccrypt/ParamantOS | Bootable NixOS ISO — plug in, boot, relay is live |
| CHANGELOG.md | Version history |
| SECURITY.md | Vulnerability reporting |
Requirements: 1 GB RAM · Ubuntu 22.04+ / Debian 12+ · Docker 24+ · swap disabled
License: BUSL-1.1 — source available, free for ≤ 5 active API keys per relay.
Licensor: PARAMANT | Jurisdiction: EU/DE | Contact: privacy@paramant.app