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

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 surface 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.

Non-success C return codes raise under a single base:

LongfellowError
├── ProverError      # .code is an MdocProverErrorCode
├── VerifierError    # .code is an MdocVerifierErrorCode
└── CircuitError     # .code is a 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

import pylongfellow as lf

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

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

proof = lf.prove(circuit, mdoc, issuer_pk, transcript, attrs, now, spec)
lf.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.1.0.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.1.0-cp314-cp314-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ x86-64

pylongfellow-0.1.0-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.1.0-cp313-cp313-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

pylongfellow-0.1.0-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.1.0-cp312-cp312-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

pylongfellow-0.1.0-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.1.0-cp311-cp311-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

pylongfellow-0.1.0-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.1.0.tar.gz.

File metadata

  • Download URL: pylongfellow-0.1.0.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.1.0.tar.gz
Algorithm Hash digest
SHA256 5024cb68835a91c541d7285c480cf0efbada04a602eb92c626924efefe754edc
MD5 a0ebd7bb31bf5fe34fa6d30d86e024ec
BLAKE2b-256 5651c2e0ba6548a92b7ab774d926b971b0ad6186852fc38a7f039f68b6dff237

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0.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.1.0-cp314-cp314-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.1.0-cp314-cp314-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 e854a4a67120be0f64b988226ed48b3bb07baeb41d7a0fcb295437eab5d3d338
MD5 32ce478bb7d75202dacc7a4abae48e8b
BLAKE2b-256 93051b875d49239c20167fd0943a85ffcb885d41dd4a041db5bc9abf31ade007

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0-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.1.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.1.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 54e3461c5b7789b981e4fcbb6e955e817950b6ab86f4c244cb6b962afd0d999a
MD5 d51e8e239c5e75d77843967ac078fba6
BLAKE2b-256 9a5d34d570a26791c77ffc7d56af0efe91e3a9e6afc7b335e1ed766f9f944929

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0-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.1.0-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.1.0-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 8f4b4a8dddec7bc791876164596b315052a95bd5e88e9c9fae3fa8710c1051d8
MD5 f1794038e2cc14357a502a3dd4ff794b
BLAKE2b-256 cc91172990cb4db07a302e2ccd638a976dc40d96fe3b35b616cf38670755d8e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0-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.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 629025b8cbc74de82a2c7f344303585266563ec843c5285f0b4344f84eca5757
MD5 590be502963d363f0b35ccc75b8f585e
BLAKE2b-256 189dfd5a026534d9769a81494eb50ab6dd02172c03bfed54e6d1ee2462311b96

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0-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.1.0-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.1.0-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3576d5786505b7655ad0ad5c4937c4b5ccaeb8a1ad96e4473d12d9b98fa32f9c
MD5 40858e982898b6660980fe7f14e7e0cb
BLAKE2b-256 fc85eb00cf01b8bb842023d2d86fc3da0b88f7a777febfcb1d8cee20b3752fc1

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0-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.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b3126a32e7f4ee0bfc272ae75427766f08011156c40d03e432c24aa261b48bcb
MD5 2bf9605eb66998600771642ce5c27f3c
BLAKE2b-256 9500b6beeca23669beef15b4fd0d027ceb85c04bcf7a4465496d0654ed9bb9ec

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0-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.1.0-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.1.0-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 47d505c3113e8ba5c1bd42a6afaf470efa0d97465ce63778d3b9c9198faf4af4
MD5 ab5143b98a6ec75e33776525c50be623
BLAKE2b-256 b03f68f8e1d3360f2e8682a09d7e780acc4b7fb89a876c6abe3c747e489c61e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0-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.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pylongfellow-0.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e7f015456416cf80f8d7a691419b88dbc0841a02da0b7289edd995c72a677ccc
MD5 df8950226cb4b4d1d2d80230c1486a8f
BLAKE2b-256 f8f713d6c94b0567098d1e2efa32b25336d0bc7f666bec413ae381af1ea2cc79

See more details on using hashes here.

Provenance

The following attestation bundles were made for pylongfellow-0.1.0-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