-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
The PyPI distribution is openvc-core (bare openvc collides with
opencv under PyPI's typosquatting guard); the import package stays openvc:
pip install openvc-coreThe core depends only on cryptography and pyjwt. Heavier machinery lives
behind extras:
| Extra | Adds | Pulls in |
|---|---|---|
openvc-core[data-integrity] |
the RDF-canonicalized Data Integrity suites (eddsa-rdfc-2022, ecdsa-rdfc-2019, ecdsa-sd-2023) |
pyld |
openvc-core[ebsi] |
the EBSI registry client | httpx |
openvc-core[schema] |
credentialSchema (W3C VC JSON Schema) validation |
jsonschema |
openvc-core[trustlist] |
XAdES signature verification for EU Trusted Lists | signxml |
openvc-core[all] |
everything above + the dev tools |
The JCS Data Integrity suites (eddsa-jcs-2022 / ecdsa-jcs-2019), VC-JWT,
SD-JWT VC, DIDs, and status lists all work with the bare core.
verify_credential is the one-call pipeline: it detects the format (VC-JWT /
SD-JWT VC / Data Integrity / enveloped), resolves the issuer key, verifies the
proof, and applies policy. Here the issuer is addressed by did:key, so
everything runs offline:
from cryptography.hazmat.primitives.asymmetric import ed25519
from openvc import VerificationPolicy, verify_credential
from openvc.keys import Ed25519SigningKey
from openvc.multibase import encode_multibase
from openvc.proof.vc_jwt import VcJwtProofSuite
# 1. An issuer key, addressed by did:key (multicodec ed25519-pub -> base58btc).
private_key = ed25519.Ed25519PrivateKey.generate()
public_raw = Ed25519SigningKey(private_key, kid="_").public_key_raw()
mb = encode_multibase(bytes([0xED, 0x01]) + public_raw)
issuer = Ed25519SigningKey(private_key, kid=f"did:key:{mb}#{mb}")
# 2. Sign a credential as a VC-JWT.
token = VcJwtProofSuite().sign({
"@context": ["https://www.w3.org/ns/credentials/v2"],
"id": "urn:uuid:2f3a-example",
"type": ["VerifiableCredential", "ExampleCredential"],
"issuer": f"did:key:{mb}",
"credentialSubject": {"id": "did:example:alice", "name": "Ada Lovelace"},
}, signing_key=issuer)
# 3. Verify: format detection, key resolution, signature, policy — one call.
result = verify_credential(
token, policy=VerificationPolicy(expected_types=["ExampleCredential"]))
print(result.format, result.issuer, result.subject)In production the issuer key usually lives in an HSM/KMS and is addressed by
did:web — see Keys & HSM backends and
Resolving issuer keys.
- A credential that declares a
credentialStatusis rejected unless you supply a status resolver (or opt out explicitly). See Status lists. - An unresolvable issuer key, an unparseable timestamp, or an
algorithm outside the
{ES256, ES384, EdDSA, Ed25519}allow-list all reject — ambiguity never resolves to "accept". The reasoning is laid out in the Security model. - Every failure raises a subclass of a single root, so
except OpenvcErrorcatches any openvc rejection.
- One credential format per guide: VC-JWT, SD-JWT VC, Data Integrity.
- Verifying what a wallet sends you: Presentations & OpenID4VP.
- Batch and async verification: Async verification.
- The full API, module by module: the API reference.
📖 Published automatically from the wiki/ directory of the main repository — edits made directly on the wiki are overwritten by the next sync. To change a page, open a PR against wiki/. Every python block on these pages is executed by CI. · API reference · LGPL-3.0-or-later
Start
Proof formats
Verifying in practice
- Presentations & OpenID4VP
- Resolving issuer keys
- Relying-party certificates
- Credential schemas
- Status lists
- Trust anchors: EU TL & EBSI
- Async verification
Walkthroughs
Operating
Reference