Verification
These functions check evidence you have been given, rather than producing any. They are the Python counterpart of the checks the Integrity explorer runs in the browser, and they answer two separate questions:
- Is this statement still what it says it is? Every lineage statement is identified by a hash of
its own canonicalized content, so recomputing that hash and comparing it with the statement's
@iddetects any modification after the fact. - Is this credential's signature good, and is it about the statement I think it is? A valid signature over some other subject proves nothing about the statement in hand, so the two checks belong together.
Both run fully offline. JSON-LD contexts resolve against documents compiled into the package or
supplied by you via contexts=, and credentials are restricted to DID methods that can be resolved
from the identifier itself, so verification never reaches the network. This is what makes them usable
in an air-gapped or reproducible pipeline.
There is no manifest-level entry point. Verifying a whole manifest means looping these two functions
over its statements, which is what the explorer does:
import json
from eqty_sdk import verify_statement, verify_vc
manifest = json.loads(open("manifest.json").read())
contexts = manifest.get("contexts")
for statement in manifest["statements"].values():
if not verify_statement(json.dumps(statement), contexts):
print("modified since it was created:", statement["@id"])
verify_statement
Pass the manifest's contexts map whenever you have one. Statements reference their context by CID
("@context": "urn:cid:..."), and while the common contexts ship inside the package, a statement
written against a custom context cannot be canonicalized without it.
A True result means every field the statement's @context defines is unmodified. It does not mean
the bytes are unmodified: the identifier commits to the statement's canonicalized RDF, and JSON-LD
expansion drops keys the context does not define.
verify_statement
builtin
verify_statement(
statement_json: str,
contexts: Optional[Dict[str, Any]] = None,
) -> bool
Verifies that a lineage statement's content still hashes to its @id.
Canonicalizes the statement as JSON-LD, recomputes its BLAKE3 RDFC CID and
compares it with the @id the statement carries. Returns False when they
differ, meaning the statement was modified after it was created.
contexts maps a JSON-LD context URI to its context document, for contexts
this build does not embed. Values may be dicts or JSON strings, so a
manifest's contexts field can be passed straight through. Note that a
supplied context takes precedence over an embedded one of the same URI.
Runs fully offline. A context that is neither embedded nor supplied raises rather than being fetched.
A True result means every field the statement's @context defines is
unmodified. It does not mean the bytes are unmodified: the identifier
commits to the statement's canonicalized RDF, and JSON-LD expansion drops
keys the context does not define.
Raises ValueError if the statement is not a JSON object or has no string
@id, and RuntimeError if a context cannot be resolved.
verify_vc
Supply statement_id whenever you know which statement the credential is supposed to attest. Without
it, only the signature is checked.
Supply contexts whenever the credential's @context references a document this build does not
embed. Verification re-expands the credential, so an unresolvable context means the proof cannot be
checked at all — and because nothing is fetched, that surfaces as False rather than an error,
indistinguishable from a bad signature. If a credential you expect to be valid returns False, an
unsupplied context is the first thing to check.
This verifies the cryptographic proof alone. Whether a credential has since been revoked or suspended lives in its status list, which has to be fetched over the network and is deliberately not consulted here.
verify_vc
builtin
verify_vc(
vc_json: str,
statement_id: Optional[str] = None,
contexts: Optional[Dict[str, Any]] = None,
) -> bool
Verifies a W3C Verifiable Credential's proof offline.
When statement_id is given, also checks that the credential's
credentialSubject.id is that statement. A valid signature over some other
subject says nothing about the statement in hand.
Returns False when the credential does not verify or is bound to a
different subject. Raises ValueError when the input is not a credential,
meaning it is not JSON, has no credentialSubject, or has more than one
subject. Raises RuntimeError when the credential's DID method would need
network access: only did:key, did:jwk and did:pkh resolve offline.
Checks the cryptographic proof only. Revocation and suspension live in the credential's status list, which is fetched over the network and is not consulted here.
contexts maps a JSON-LD context URI to its context document, for contexts
this build does not embed. Values may be dicts or JSON strings, so a
manifest's contexts field can be passed straight through. Note that a
supplied context takes precedence over an embedded one of the same URI.
Runs fully offline. Verifying a credential re-expands it, so a context that
is neither embedded nor supplied is never fetched — it reports False,
alongside the other reasons a proof may not check out.