Skip to main content

Official SDK for the Grundnorm grounded source-of-law truth layer — resolve a legal norm by open identifier (ELI/ECLI) + date and verify its cryptographic seal locally.

Project description

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_found instead 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", "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-3 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 demo record signed by one party is ok: True. Read quorum and attestation before treating a record as authoritative.

What verify() re-derives (no trust required)

  1. Hash: sha256(canonicalize(norm["canonical"]["content"])) equals norm["seal"]["contentHash"], where canonicalize = JSON with keys sorted recursively (UTF-16 order), no whitespace, UTF-8.
  2. View integrity: the English atoms/purpose are exactly what the sealed canonical.content projects to (view_consistent); canonical.content is the source of truth.
  3. Signatures: each seal.signatures[].signatureHex is a valid Ed25519 signature by that signer's publicKeyHex over the UTF-8 bytes of the seal.contentHash hex string.
  4. 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 fails ok. 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). Not proof of institutional independence.
  • attestation — honest flags the SDK cannot prove: custody ("unverified" for the demo — one party regardless of pinning), independence (as asserted in the record), ledger ("unanchored" for demo/local seals), key_provenance ("pinned_oob" when a signer's key matches the SDK's out-of-band snapshot, else "in_band_response"), classification ("rule_reexecuted", "not_present", or "rule_unsupported" when the witness declares a rule version this SDK does not implement).
  • Key pinning (key_provenance, per-signature pinned) is tamper-evidence of a snapshot, not proof of institutional independence: a single-party demo key is pinned yet custody stays "unverified". It is not a key-transparency log.

Errors

  • Nothing sealed for (id, date) → returns NotFound (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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grundnorm-0.3.0.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grundnorm-0.3.0-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file grundnorm-0.3.0.tar.gz.

File metadata

  • Download URL: grundnorm-0.3.0.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for grundnorm-0.3.0.tar.gz
Algorithm Hash digest
SHA256 0399d02330b07b705e66e461b0f66dff62d4ab5b1ab0a013de321f02ece42aa9
MD5 515858ce0d2d9c972cf4c3f5f3bf49cf
BLAKE2b-256 c16103d9db29954fb667768d789af8fbd33e4df4b11b92d871383f0a0d8e70dd

See more details on using hashes here.

File details

Details for the file grundnorm-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: grundnorm-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 10.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for grundnorm-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0668fc4493a798e6a367769ce7f47c932b86c6440a79f756c82ff7aad107899a
MD5 b9f23db138da02df812066c2ba6a2b75
BLAKE2b-256 f6ae5bc7a581457011f7d51630f43e2cbb025c3c6f69b5dc03a525fac20bfd58

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page