This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 0.7.2 instead.
Reason given by maintainers: el de npm: verify() devolvía verificado sobre contenido fabricado
grundnorm (Python SDK)
Resolve a legal norm by its open identifier (ELI/ECLI) and a date, and get back its canonical, sealed meaning as an independently verifiable signed object. The SDK recomputes the content hash and verifies every Ed25519 signature locally — you never have to trust the server.
- Deterministic, zero-LLM read path. Honest
not_foundinstead of a guess. - Point-in-time:
[validFrom, validUntil). - Python 3.9+. One dependency:
cryptography.
Install
pip install grundnorm
Use
from grundnorm import GrundnormClient
# Defaults to the public GDPR demonstrator. For a pilot:
# GrundnormClient(endpoint="https://.../api/grundnorm/resolve", api_key="nlk_...")
client = GrundnormClient()
r = client.resolve(
id="http://data.europa.eu/eli/reg/2016/679/art_5",
jurisdiction="EU",
at="2026-07-07", # omit for "today"
)
if r.status == "found":
print(r.norm["atoms"]) # subject / modality / action / condition / exception / scope + evidence
print(r.verification["ok"]) # True only if hash recomputes AND all signatures verify
resolve() verifies the seal by default. Skip with verify=False, or verify a stored envelope later:
from grundnorm import verify
v = verify(norm) # {"ok", "cryptographically_ok", "authoritative_ok", "hash_ok", "view_consistent", "status_re_derivable", "signatures", "quorum", "attestation"}
v["ok"] proves cryptographic soundness, not trustworthiness. True iff the bytes, the view and
every signature check out (1-4 below) — exactly what a third party re-derives from the response alone.
It does not establish that the signers are independent institutions, that the record is externally
anchored, or that its meaning is jurist-correct. A record signed by the public demo keys (forgeable —
see below) is ok: True.
To gate real trust, use v["authoritative_ok"], not v["ok"]. It is True only when the record is
cryptographically sound AND its keys match the out-of-band snapshot as known non-demo institutions
(key_provenance == "pinned_oob", demo_keys == False) AND a pin-anchored quorum is met (>=2 pinned valid
signatures incl. >=1 pinned sovereign). Every current demo record is ok: True but authoritative_ok: False.
What verify() re-derives (no trust required)
- Hash:
sha256(canonicalize(norm["canonical"]["content"]))equalsnorm["seal"]["contentHash"], wherecanonicalize= JSON with keys sorted recursively (UTF-16 order), no whitespace, UTF-8. - View integrity: the English
atoms/purposeare exactly what the sealedcanonical.contentprojects to (view_consistent);canonical.contentis the source of truth. - Signatures: each
seal.signatures[].signatureHexis a valid Ed25519 signature by that signer'spublicKeyHexover the UTF-8 bytes of theseal.contentHashhex string. - Status (when a classification witness is present): each atom's status
(
fixed/needs_review/for_the_court) re-executes from the deterministic rule applied to the sealed per-atom signals (status_re_derivable). A mismatch failsok.None= no witness (older seals) → not re-derivable, no penalty. Bounded: proves the rule was applied to sealed inputs; it does not prove the deontic decomposition is faithful to the article (that is the jurist gate).
What it REPORTS but does not prove
quorum— a signature count (valid_signatures,has_sovereign,meets= >=2 incl. one sovereign). The sovereign role is pin-anchored where a pin exists, but an unpinned signer's claimed role is taken on trust. For a spoof-proof gate useauthoritative_ok.attestation— honest flags the SDK cannot prove:custody("unverified"for the demo),independence(as asserted),ledger("unanchored", or"claimed_unverified:<backend>"for a record claiming an anchor the SDK cannot verify — it never says"anchored:"),key_provenance("pinned_oob"= known non-demo pin;"pinned_demo"= only forgeable demo pins;"in_band_response"= no pin / substitution),demo_keys(Trueiff any valid signature matched a forgeable demo pin → not authoritative),classification("rule_reexecuted","not_present", or"rule_unsupported").- Key pinning (
key_provenance, per-signaturepinned) is tamper-evidence of a snapshot, not proof of institutional independence: a single-party demo key is pinned (pinned_demo) yetcustodystays"unverified"andauthoritative_okisFalse. It is not a key-transparency log.
Errors
- Nothing sealed for
(id, date)→ returnsNotFound(a normal outcome). - Bad key, bad input, or server error → raises
GrundnormError(.status,.code).
Demonstrator note: the demo corpus (GDPR sample) is signed by demo keys, not institutions, and its accuracy is not yet jurist-graded. See the project's
DEMO-TRUTHFULNESS.md.
Metadata
Release files for grundnorm 0.4.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 | |
|---|---|---|---|
| grundnorm-0.4.0.tar.gz | 17.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| grundnorm-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.4 kB
Release files / grundnorm-0.4.0.tar.gz
| Download URL | grundnorm-0.4.0.tar.gz |
|---|---|
| Size | 17.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b6c52018841d100f07f63cb79ec42361a124c886920455bd9e82657f545ed13b
|
|
BLAKE2b-256 checksum How to use checksums |
e40240bad85dae06b471ef81143fd7214fe80c1eb32dad6e2266a0b933205a12
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Release files / grundnorm-0.4.0-py3-none-any.whl
| Download URL | grundnorm-0.4.0-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4fbc16cfb8baecb73a79b2ac9c1875d47f59b6ebe0e8083ed6a11b8f17e5b0f8
|
|
BLAKE2b-256 checksum How to use checksums |
77df5a6e3d89841479b9501d3c80c0dabc8f3351a3b7f157c282f8a78f00e39d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|