polaris-verify
A detached verifier for Polaris credentials and signed artifacts. It decides authenticity on its own: no Polaris server, no database, no operator console, no network unless you ask it to fetch status.
Project name and import name differ, and the obvious guess lands elsewhere. This project,
polaris-verify, installs thepolaris-verifyCOMMAND and the modulepolaris_verify_cli. The modulepolaris_verifybelongs to a different project,polaris-sdk-python, which is the library. They install side by side without colliding, andpip install polaris-verifyfollowed byimport polaris_verifyis the mistake this paragraph exists to prevent. The names were fixed before either was published and are not worth changing after:conformance/SPEC.mdpublishespython -m polaris_verify.conformanceas the reference verifier command, so the module name is part of a contract.
# Not on PyPI yet. This works today, from a clean machine, and is measured:
pip install "polaris-verify[cryptography] @ git+https://github.com/EgorKhaklin/polaris-id#subdirectory=packages/polaris-verify"
polaris-verify --pqc-provider auto --pack credential.json
The #subdirectory= fragment is required and is easy to miss: this repository holds several
packages, so its root has no pyproject.toml, and pip install git+… without the fragment
fails with "does not appear to be a Python project", which reads as "this is not
installable" rather than "look one directory down".
Once it is published the command becomes pip install "polaris-verify[cryptography]". See
RELEASING.md for why nothing is published yet.
It refuses to start until you say what cryptography it is doing
There is no default and no environment variable for this choice.
--pqc-provider oqs real ML-DSA via liboqs
--pqc-provider cryptography real ML-DSA via cryptography>=48
--pqc-provider auto whichever real backend is installed
--dev-placeholder NO real cryptography; development only
Run it with none of them and it exits 4 without reading your files. Name a backend that is not usable on the machine and it exits 4 rather than starting and reporting a verification failure for every credential, which reads as the credentials being bad instead of the verifier being unable.
Under --dev-placeholder every verdict carries "crypto": "DEV-PLACEHOLDER" and a banner
goes to stderr. Development crypto is never mistaken for production crypto.
Offline means it cannot reach a network
Not "does not today". The verifier contains no networking code at all: zero references to
urllib, http.client, socket or requests, and check_detached_verifier fails the build
if one appears. An air-gapped relying party is running the same code path as a connected one.
The online status path is a different thing and lives elsewhere, in the SDK and the relying
party, both of which are allowed urllib on purpose.
What it verifies
Authenticity packs, presentations and QR frames, status assertions (offline, with a
freshness window), ID tokens, epoch checkpoints and leaves, revocation feeds, federation
manifests and status bundles, trust lists and attestations, registries, timestamps and
their transparency anchors, signed documents, exchange requests, receipts and mints, holder
bindings and proofs, agent grants with their revocations and proofs, and cross-authority
decisions. --verify-dir re-verifies a directory of published vectors; --selftest checks
the verifier against material it generates.
Trust
--issuer-anchor takes a JSON file of the issuer's published verification keys, and
--trusted-anchor takes one key hex. Without either, the verifier reports whether a
signature is genuine but leaves issuer_trusted unanswered, which is the honest verdict:
a genuine signature by a key you do not trust is authentic and worthless.
Configuring a trust root
The anchor file is a JSON list of hex keys, or an object carrying one under
public_keys_hex, anchors, public_key_hex or keys. All four are accepted:
["90bece7e1902ccce...the issuer's ML-DSA public key, in hex..."]
polaris-verify --pqc-provider auto --issuer-anchor anchors.json --pack credential.json
Where the key comes from is your decision, and it is the decision that matters. The
issuer publishes its keys in a signed registry (GET /api/v1/registry/<agency_id>, verified
with verify_registry) and in a signed federation manifest; both are themselves signed, so
each moves the question one step rather than answering it. Somewhere a key is pinned out of
band, by you. This tool does not pretend otherwise and will not fetch one for you.
What it does guarantee, and what you can script on:
signature_valid |
issuer_trusted |
exit | |
|---|---|---|---|
| correct anchor | true |
true |
0 |
| a different, well-formed key | true |
false |
2 |
| empty anchor list | true |
false |
2 |
| no anchor given | true |
null |
0 |
A genuine signature by a key you did not anchor is reported authentic and untrusted, and exits non-zero. The two questions stay separate because collapsing them is how a format check gets read as a trust decision.
Status
0.1.0. Unreleased on any registry as of this writing, and not yet exercised by a named
external implementation. See lab/EXTERNAL-NOUNS.md in the repository for what has and has
not happened outside the project.
Apache 2.0. Part of the Polaris reference implementation, which runs on notional data.
Metadata
Release files for polaris-verify 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| polaris_verify-0.1.0.tar.gz | 64.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| polaris_verify-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 130.1 kB
Release files / polaris_verify-0.1.0.tar.gz
| Download URL | polaris_verify-0.1.0.tar.gz |
|---|---|
| Size | 64.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8725eb6e00d102e87ded79138b38a0d884a253e0f14cdd19ad0d7f45990a6238
|
|
BLAKE2b-256 checksum How to use checksums |
f0eeba189e9e18d138154b39012e50a118dd0a18ef7239e3d329aee8f4dcb807
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logRelease files / polaris_verify-0.1.0-py3-none-any.whl
| Download URL | polaris_verify-0.1.0-py3-none-any.whl |
|---|---|
| Size | 65.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8cda2b0cfcdbefca5140b48309a014ce8187c4e26fd4d691c95f65c53c32e71b
|
|
BLAKE2b-256 checksum How to use checksums |
54e5d555a3899becc6198e5a891a87bbee3554523bfcd5c83d156231d2a7295c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency log