Skip to main content
Yanked

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_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", "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)

  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). 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 use authoritative_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 (True iff any valid signature matched a forgeable demo pin → not authoritative), classification ("rule_reexecuted", "not_present", or "rule_unsupported").
  • 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 (pinned_demo) yet custody stays "unverified" and authoritative_ok is False. 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.

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)

Source distribution for grundnorm 0.4.0
File Size Uploaded
grundnorm-0.4.0.tar.gz 17.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for grundnorm 0.4.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page