POLARIS
A working reference implementation of an issuer-unlinkable, duress-aware
identity-token system, signed with ML-DSA-65 under an audited algorithm-migration path.
Reference implementation · notional data only
Fixus inter mutabilia · fixed amid the mutable
46 schema tables · 134 routes ·
338 machine-checked invariants ·
ML-DSA-65 signing default ·
X25519MLKEM768 TLS edge ·
Plonky2 ZK + second witness
What Polaris is
An authority issues a credential signed with ML-DSA-65; a holder presents it; anyone
checks it two ways. Authenticity is offline: a standalone verifier checks the
signature against published keys, with no database and no network. Authorization
is answered online by a relying-party API, or offline by a short-lived signed status assertion.
The cryptographic claim is algorithm agility under an audited migration path,
not settled security against a quantum adversary.
The backbone is a schema whose constraints are the security boundary: the
guarantees live in the database, not in application code. A rule enforced by a trigger, a
CHECK constraint or a unique index binds every client and survives every restore from backup.
Around the credential: a protocol of signed statements (registry, trust list,
exchange receipts, timestamps, document signing, login tokens, wallet presentations), each
verified offline by the same verifier and both SDKs, frozen at version 1 and re-verified on
every push.
The problem it models: Americans carry six to eight credentials that do not talk
to each other. Polaris consolidates them into one token per person, verified through
context-scoped events (banking, voting and healthcare are different events with different
disclosure rules). The default disclosure level is zero-knowledge, so the typical verification
stores no token identifier at all, and the zero-knowledge verification graph cannot be
reconstructed even by someone holding the whole database (SELECTIVE and FULL events do carry a
token id).
The ten guarantees
Above all ten sits the vocation: no person can be compelled to renounce,
transfer, or surrender their identity against their will. Each guarantee is enforced
in the database, where no client can bypass it, and machine-checked on every change.
C1Append-only history. Triggers reject any UPDATE or DELETE on the audit tables. What happened, stays.
C2Zero-knowledge means zero. A CHECK constraint refuses to store a token id on a zero-knowledge verification.
C3One active token per person. A partial unique index makes a second ACTIVE row impossible, under any concurrency.
C4Atomic lockout counting. Failed logins increment in a single statement; there is no check-then-act race.
C5No inline scripts. Content-Security-Policy is script-src 'self', verified per route.
C6Server-side disclosure. A client cannot upgrade what a verification reveals; redaction is tested at every read path.
C7No hardcoded crypto. Algorithms are rows in a registry; rotation is an INSERT, not a redeploy.
C8Bounded aggregates. Every map and API result set carries a hard cap; payload scales with the viewport, not the ledger.
C9Real concurrency tests. Race-prone paths are tested with real threads against a live database, not mocks.
C10Identity is not money. The schema carries no monetary claim; the boundary is structural, not policy.
The hard parts
Consolidating six credentials into one token is the easy half.
The interesting half is what happens when an adversary shows up.
Six answered by construction, at the database layer, not in policy.
Cryptographic compulsion
"Sign this or I break your fingers." The holder cannot refuse without injury.
A second secret produces a verification that looks identical and silently records a DuressEvent. By design the coercer sees success; the indistinguishability is a tested property of the modeled flow, not an audited side-channel guarantee.
Catastrophic loss
Token lost, holder unidentified, nothing to prove who they are.
A two-phase ceremony gated by independent out-of-band channels, a cooldown, and an admin-only decision. Compromising one channel is not enough.
Quantum migration
Today's signing algorithms break overnight when a quantum computer arrives.
Tokens carry classical AND post-quantum signatures simultaneously during cutover, with a hard database rule that exactly one is active. The default is already post-quantum.
Issuer concentration
One agency issues tokens that masquerade as any other agency's.
Explicit-only federation; no transitive trust. Every cross-agency verification gates on an active trust attestation row.
Auditability without privacy loss
"Prove this token was in the ledger" without revealing which one.
A Plonky2 proof over a Merkle commitment answers membership and nothing else. The verification graph cannot be reconstructed from zero-knowledge events.
Issuer overreach
An agency revokes tokens at industrial scale, outside policy.
A per-agency revocation-rate ceiling enforced by trigger, sanctioned by a policy row, audited under an advisory lock.
Verified, not asserted
Every number and every link on this page is checked before it is
published: the counts are recomputed from the repository, the links and images are
resolved against the tree, and either one failing stops the deployment. The two test
counts are measured per release on the reference machine. CI does not just run tests;
it exercises the artifacts.
1245product tests, live DB
126crypto-witness tests
338invariant checks
23CI jobs
5services booted in CI
test counts measured at v1.0.0-rc.62; the rest recomputed on every push
- The production-profile stack boots in CI. Five services behind a self-built TLS edge come up end to end on every push, and health is asserted through the edge. Building that job surfaced four prod-down bugs the day it landed.
- Backups restore, provably. An encrypted backup and restore round-trip runs in CI with a fail-closed negative check, and the HA profile's automated failover is drilled on every push.
- The post-quantum handshake is proven, not claimed. CI negotiates X25519MLKEM768 against a real certificate on every push, and signs with real ML-DSA-65 inside the production image.
- CVEs gate the build. Both the dependency surface and all five self-built container images are scanned on every push; a fixable CRITICAL fails CI.
- Every check can prove it works. Each of the 338 invariant checks is paired with a detection test showing it fails on a broken fixture. A check that cannot detect its own violation is treated as broken.
What happened when somebody else's software tried it
Everything above is this project checking itself. These are the only
results that are not. A constraint lattice and a verifier that an unmodified wallet
already spoke to is the whole of what is demonstrated here; the scale the architecture
is designed for is a design target, not a deployment.
A wallet nobody here wrote
On 15 September 2026 an unmodified walt.id Wallet API v2 presented an SD-JWT VC over
OpenID4VP 1.0 and polaris-oid4vp accepted it. It first refused Polaris,
correctly: a certificate defect that every internal check had passed over.
OpenID Certified verifier

OpenID Certified™ by Egor Khaklin to the OpenID4VP 1.0 + HAIP 1.0
Verifier profile: polaris-oid4vp 1.0.0rc7, 24 September 2026
(listing).
A self-certification the Foundation reviewed: not an endorsement, not an audit, and not
a certification of the rest of Polaris.
Installable without cloning anything
Release candidates on PyPI and npm:
pip install --pre polaris-verify,
pip install --pre polaris-oid4vp,
pip install --pre polaris-sdk-python,
npm install polaris-sdk-ts@next. Each was verified by installing from the
live registry into a clean environment.
Still missing
No independent security review by anyone who did not build this. No non-author
operator has run it. No pilot, no real users, no real identity data. Distribution
is not validation, and a green test suite is not proof of correctness.
Real cryptography
Which algorithm signed a token is data, not code: a foreign key into a
first-class registry, so adding or retiring one is a row, not a redeploy. The shipped
signer implements ML-DSA-65.
ML-DSA-65 signing
NIST FIPS 204 lattice signatures, Level 3, on every new token. Both shipped production paths sign with real liboqs bytes, cross-checked by a second implementation. A development run without that flag records a deterministic SHA3-256 placeholder under a label that says so, so a development signature can never pass for a real one.
SLH-DSA registered
FIPS 205 hash-based signatures rest on different assumptions than lattices, so both parameter sets are rows in the algorithm registry and a rotation is a row update. No SLH-DSA signer is wired yet; that gap is on the ledger in PQC-POSTURE.md.
Plonky2 ZK-SNARK
FRI-based, transparent setup. Proves epoch membership without revealing which token. The epoch root is recomputed bit-for-bit by an independent Python witness.
Post-quantum TLS edge
The public edge negotiates X25519MLKEM768 hybrid key exchange; CI proves the handshake on every push. What stays classical is mapped honestly in PQC-POSTURE.md.
WebAuthn MFA
Admin accounts enroll a FIDO2 credential against a per-account deadline; once enrolled, or once the deadline passes, a password alone cannot reach the admin role. The relying party offers ML-DSA-65 first.
What this is not
Not production-ready for real identity data. Every engineering
gap the readiness ledger enumerated is closed and pinned by a check. What remains
cannot be built here: nine decisions that belong to the deploying organization,
two engineering limits carried openly, and the deployment-scale work the roadmap
tracks phase by phase.
The nine decisions, each one a named accountable choice rather than a
missing feature:
- Legal basis, data-protection impact assessment, regulator approval
- Signing-key custody and the rotation authority
- The PostgreSQL high-availability topology and promotion policy
- Encryption at rest on the host volume, and its key custodian
- The offsite backup target, its retention and its schedule
- The alerting backend and the named on-call rotation
- The right-to-erasure policy against an append-only audit
- The retention schedule per class and jurisdiction, and the counsel who says it satisfies the statute
- An independent penetration test and threat-model sign-off
The bound on every claim on this page is the ledger itself:
PRODUCTION-READINESS.md.
This is a reference implementation on notional data; it holds no real identity record.
Run it
Evaluate it locally (macOS, Docker Desktop)
git clone https://github.com/EgorKhaklin/polaris-id.git polaris
cd polaris
./Polaris.command
The launcher pulls PostgreSQL, builds the image, loads the schema,
runs the SQL self-tests and opens the console on notional data with development
credentials.
Single-host compose profile (any Docker host)
./scripts/polaris-generate-secrets.sh
export POLARIS_DOMAIN=polaris.example.com
./scripts/polaris-deploy.sh prod
curl -fsS https://$POLARIS_DOMAIN/api/health
Five services behind a self-built TLS edge that provisions its own
certificate. One host, so the database has no standby: that is one of the nine
decisions above.
Linux server under systemd
sudo POLARIS_DOMAIN=polaris.example.com deploy/linux/install.sh
The same stack as a system service on Debian, Ubuntu or an
RHEL-family host, installed by one script and exercised on Debian and Rocky in CI.
Hardening is a separate, documented step:
LINUX-SERVER.md then
HARDENING.md.
Kubernetes reference profile
helm install polaris deploy/helm/polaris --namespace polaris
The same topology with enforced network policies and the restricted
pod security standard, booted on kind in CI. It runs a single PostgreSQL replica;
high-availability automation is roadmap work, not a shipped feature.
KUBERNETES.md.
Evaluate it
The documents an assessor reads first, in the order they usually matter.