Skip to main content

Thin Python binding to Google's Longfellow zero-knowledge mdoc library

Project description

pylongfellow

CI Docs PyPI Python License: Apache 2.0

Overview

A thin Python binding to google/longfellow-zk, the zero-knowledge library that ISO 18013-5 / EUDI mdoc wallets use to prove attributes of a credential without revealing the credential. The underlying scheme is described in Anonymous credentials from ECDSA.

pylongfellow is a cffi wrapper over the library's extern "C" mdoc ABI (lib/circuits/mdoc/mdoc_zk.h). It binds the prove and verify calls and the few structs they take; it does not add a layer of its own. The binding is attribute-agnostic — it proves and verifies (namespace, id, cbor_value) statements over an mdoc and has no notion of what any attribute means. age_over_18 is just the attribute the examples and tests happen to use.

Status: pre-1.0. Upstream is explicitly experimental and its ABI and circuits can change between releases. The vendored upstream is hard-pinned (see Upstream); treat pylongfellow, like its upstream, as not production-ready.

For what each function does and the exact types, read the docstrings — they render to a docs site (mkdocstrings + MkDocs-Material).

Install

pip install pylongfellow

Wheels are published for CPython 3.11–3.14 on Linux x86_64 (manylinux and musllinux). On any other platform pip falls back to the source distribution, which builds the vendored C++ locally and needs a C++ toolchain — see Build from source.

The wheel's only runtime dependency is cffi.

What it binds

Everything is in the pylongfellow.mdoc submodule: from pylongfellow import mdoc, then call mdoc.verify(...). Each function wraps one C entry point. The wrappers marshal inputs, copy results out, and turn non-success return codes into typed exceptions.

Python C entry point Role
generate_circuit(spec) generate_circuit produce the compressed circuit a spec names
circuit_id(circuit) circuit_id recompute a circuit's canonical id (equals ZkSpec.circuit_hash)
find_zk_spec(system, circuit_hash) find_zk_spec look up a built-in ZkSpec, or None
prove(circuit, mdoc, issuer_pk, transcript, attrs, timestamp, spec) run_mdoc_prover holder side — produce a proof
verify(circuit, issuer_pk, transcript, attrs, timestamp, proof, doctype, spec) run_mdoc_verifier verifier side — raises on a bad proof, returns on success

A circuit is just bytes: get them from generate_circuit, or read a committed blob from disk. There is no load_circuitpathlib.Path(...).read_bytes() is the loader.

Two C structs are exposed as frozen dataclasses:

  • RequestedAttribute(namespace, id, cbor_value) — "attribute (namespace, id) holds this value." cbor_value is raw CBOR bytes (e.g. b"\xf5" is CBOR true); the binding does no encoding.
  • ZkSpec(system, circuit_hash, num_attributes, version, block_enc_hash, block_enc_sig) — a circuit's identity. The spec is the small descriptor prover and verifier agree on; circuit_hash (SHA-256 hex) pins which circuit it is. len(attrs) must equal num_attributes.

A non-success C return code raises mdoc.ProverError, mdoc.VerifierError, or mdoc.CircuitError. All three are subclasses of mdoc.Error, which is a subclass of LongfellowError:

LongfellowError
└── mdoc.Error
    ├── mdoc.ProverError      # .code is a mdoc.ProverErrorCode
    ├── mdoc.VerifierError    # .code is a mdoc.VerifierErrorCode
    └── mdoc.CircuitError     # .code is a mdoc.CircuitGenerationErrorCode

Catch by class; read .code for the specific failure. The classes do not collapse to one: the code enums mirror C ints and overlap, so only the exception class says which enum a code is from.

Usage

import json
from datetime import datetime
from pathlib import Path

from pylongfellow import mdoc

spec = mdoc.find_zk_spec("longfellow-libzk-v1", circuit_hash)
circuit = mdoc.generate_circuit(spec)          # or Path(...).read_bytes()

attrs = [mdoc.RequestedAttribute("org.iso.18013.5.1", "age_over_18", b"\xf5")]  # CBOR true

proof = mdoc.prove(circuit, credential, issuer_pk, transcript, attrs, now, spec)
mdoc.verify(circuit, issuer_pk, transcript, attrs, now, proof, doctype, spec)   # raises on failure

A complete, runnable version over a committed sample mdoc is in examples/prove_and_verify.pyfind_zk_specgenerate_circuitcircuit_idproveverify. It needs nothing but the package and the bundled fixture; circuit generation takes ~15s.

Logging

Upstream logs to stderr (not Python logging, and it exposes no callback to bridge). The one control is the PYLONGFELLOW_LOG_LEVEL environment variable, read once when the extension loads — there is no Python API and no runtime reconfiguration, following the TF_CPP_MIN_LOG_LEVEL / GRPC_VERBOSITY convention.

Values (case-insensitive): error, warning, info, silent. The default is warning, which hides upstream's per-call info output but keeps genuine errors and warnings.

Build from source

The vendored upstream is a standard CMake project. Prerequisites (Debian/Ubuntu):

sudo apt install -y cmake libssl-dev libzstd-dev libstdc++-13-dev libgtest-dev libbenchmark-dev
git submodule update --init --recursive

The default c++ (g++) works. Build and test with uv:

uv sync                                   # builds the extension + dev group, writes uv.lock
uv run pytest                             # fast suite
uv run pytest -m "slow or not slow" --cov # full suite incl. real circuit generation

scikit-build-core drives the vendored CMake build and packages the cffi extension. The internal upstream object libraries are built position-independent and linked into a single shared object that cffi binds.

Two gotchas worth knowing:

  • uv sync won't rebuild on a C/C++-source-only change — it keys off version and dependencies, not native source mtimes, so it silently leaves the old .so installed. Force it with uv sync --reinstall-package pylongfellow.
  • Use a current uv. A stale one can serve a Python alpha (e.g. 3.14.0a4) whose GC segfaults at finalization after circuit generation; a shutdown SIGSEGV is the symptom. Update uv and check the interpreter version first.

How wheels are built

  • Wheels: cibuildwheel builds cp311–cp314 × {manylinux, musllinux}, x86_64, with the test suite run inside each build container as the gate; auditwheel repairs them. A source distribution bundling the pinned upstream ships alongside.
  • Publish: PyPI Trusted Publishing (OIDC, no long-lived tokens), which emits PEP 740 build attestations binding each wheel to its source commit.
  • Dev: uv (envs, lock), ruff (lint + format), mypy (strict), pytest, mkdocs.

Upstream

pylongfellow vendors google/longfellow-zk (Apache-2.0) as a git submodule, hard-pinned to a specific commit (currently v0.9, fe83ec6) and built from source into each wheel. It does not float: the upstream ABI and circuits can change between releases, and the test fixtures are pinned to a particular circuit and version.

Not affiliated with Google or the European Commission — an independent binding to a public Apache-2.0 library.

License

Apache-2.0, matching upstream.

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

pylongfellow-0.2.1.tar.gz (13.6 MB view details)

Uploaded Source

Built Distributions

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

pylongfellow-0.2.1-cp314-cp314-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ x86-64

pylongfellow-0.2.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

pylongfellow-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

pylongfellow-0.2.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

pylongfellow-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

pylongfellow-0.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

pylongfellow-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

pylongfellow-0.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

File details

Details for the file pylongfellow-0.2.1.tar.gz.

File metadata

  • Download URL: pylongfellow-0.2.1.tar.gz
  • Upload date:
  • Size: 13.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pylongfellow-0.2.1.tar.gz
Algorithm Hash digest
SHA256 2472b33ca57371b2a16d12d43e99a3b1b7f294aefa8fafcee4af73da659b7ee3
MD5 d1082682bceb3743683631056c6baace
BLAKE2b-256 b3a8a09f08fca697309b0a15ae71693b92ca026afdd38620a864f97070e8255a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1.tar.gz:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylongfellow-0.2.1-cp314-cp314-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.2.1-cp314-cp314-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 6e60c8d348a3713bf220e4985063554ce377e4a471739c213a1ea5c951c39b2d
MD5 e7627641feef0015c8c6ceaf6b42ae4e
BLAKE2b-256 f00efdb9fc38df81c477d3ff525ff2e0bbf268456916bbc756a6aa7663d33934

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1-cp314-cp314-musllinux_1_2_x86_64.whl:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylongfellow-0.2.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.2.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8d2f781e01ec30cef39477f5ab68034f0fd70b3a8e9504e4e74060592c7d4141
MD5 0df32b9eb7eaad01ff4c231ec31f8dd6
BLAKE2b-256 f39e164edfc6dd47411b32484ea9b3de96aee6fcfb2b711c59f31b307d9ae97f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylongfellow-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 681537a5a4f3bf4030e96dbfe13111f71df39d1ffff0f0512c37fcfa4b067271
MD5 942ba2ca964c076b7a63504b2daad6c4
BLAKE2b-256 47aefe04de65bd09c6cb114e81cff30f918352429d53c2e53e77f0e5aeb3dd55

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylongfellow-0.2.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.2.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 aaf0900254971d0bcaa8d6acc9118dcb41e684cc2eb2a1cce37ad95d3f76b708
MD5 b74f3df16e7e206604d223fa7b9bd8f3
BLAKE2b-256 6786ba940beffbe77b21c46ef67c0b79427594374661ccfc63af101720500251

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylongfellow-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9607e3c3ea7c742c799b6bd0db2d1fdea525ccf185c3aba08fb3db4c9c8504ec
MD5 19882c46b0f68fab3d9c74ccc28829f2
BLAKE2b-256 ee9b12d36cbbe6b769adc2f94a15ca4661bcf26c3584314d12bfb247d223d562

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylongfellow-0.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 502b2175c9b41e7caf1ce136c47554a14b603d250f1d7995aa452dcf9ddb8c0f
MD5 21fdc9f28d29e9b9e93c6231aa556070
BLAKE2b-256 2d3d68d80d80597b3e3c2679d51d0f291efad533f5d34e08202b270b63f14ac2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylongfellow-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 b3974a38c1c0c7c9ffad22162f63435d907a86adf742417ff24a636c44484f74
MD5 826edb017cb72c5cd81a82086e13a922
BLAKE2b-256 bc0a412f072990cc1296591c40e12a5e4e8f806c2d049fbbb68294fcc418f6c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pylongfellow-0.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c4bd260108c5fcb938b7fdf25f75e0b599d2b12b7da6185c977c8a8c6c3c3ebb
MD5 4c78b3bcf9683a0a74416fe481aa493f
BLAKE2b-256 4a807bad9f5fd86b11f154de4dc0c48465655b4b10b399d332391d9754c91816

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on pipe23-org/pylongfellow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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