Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,326 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PARAMANT — Post-Quantum Encrypted File Relay

Version License Security Audit Relays Jurisdiction Docker

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.


Quick start

# 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 | bash

Or 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)


Powered by paramant-core

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, @noble reference).

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.


What's new in 3.0.0

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/core Rust 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 /setup replaces hand-run admin scripts — admin token, TOTP and first key from the browser (ADR R005).
  • Visual admin config + in-browser CLI. /admin/settings edits relay config without touching .env; /admin/cli is 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/capabilities advertises a compact core mode (2 algorithms) by default; extended sets are opt-in via CRYPTO_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=1 lets a single relay serve its own UI for plug-and-play self-hosting (ADR R011).

Architecture Decision Records (this repo)

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).


What is included

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.


How it works

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 - Post-quantum document signing

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.

The .psign proof

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.

Zero-knowledge scope

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.

/v1 developer API

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.psign

Webhooks: 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).


Use cases

Healthcare — DICOM / HL7 FHIR (NEN 7510)

# 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


Legal & Notary — eIDAS compatible

# 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

Legal compliance


Industrial IoT — IEC 62443

# 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

IEC 62443 compliance


Finance — NIS2 / DORA

# 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"

HR — GDPR-compliant payslip distribution

# Bulk payslip delivery — no email, no storage, no GDPR risk
paramant-payslip \
  --bulk employees.csv --dir ./payslips/april/

Software supply chain — EU CRA 2027

# 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/api

Sector relays

Five 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.


Self-hosting

Linux VPS (Ubuntu 22.04+ / Debian 12+)

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 -d

This 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/

Raspberry Pi (arm64)

curl -fsSL https://paramant.app/install-pi.sh | bash
# Detects Pi model, installs Docker, disables swap, prints relay URL

Automated full setup (domain + TLS + sectors)

curl -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).

Bootable OS (no Docker needed)

Flash paramantOS to USB — relay starts on boot.


API

Send a file

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}

Receive a file (burn-on-read)

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 response

Health check (public)

curl https://health.paramant.app/health
# {"ok":true,"version":"3.0.0","sector":"health","edition":"licensed"}

CT log (public)

# 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


CLI tools

All 44 paramant-* tools are included in paramantOS and installable via .deb:

curl -fsSL https://paramant.app/install-client.sh | bash

Setup & diagnostics

paramant-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

Sector tools (use-case specific)

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

Key management

paramant-keys              # list all API keys
paramant-key-add           # add new API key
paramant-key-revoke        # revoke an API key

CT log verification

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 & network

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

Data management

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

Python SDK

pip install paramant-sdk
from 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)

Security

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.


Certificate Transparency log

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/

Compliance

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.


Pricing

Tiers, limits, and current prices are maintained on the website:

https://paramant.app/pricing

API key signup: https://paramant.app/signup


Docs

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

About

Post-quantum encrypted file relay. ML-KEM-768. Burn-on-read. EU/DE. NIS2/NEN7510/IEC62443 ready.

Topics

Resources

Contributing

Security policy

Stars

26 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages