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.2.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.2-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.2-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.2-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.2-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.2-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.2-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.2-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.2-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.2.tar.gz.

File metadata

  • Download URL: pylongfellow-0.2.2.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.2.tar.gz
Algorithm Hash digest
SHA256 4f75636a3513f714be68fb355ddd831a9cb7cc7fa6efb2a7f09224fe0b9b9904
MD5 7720159e9098f1fcf729e45d0ffa46e7
BLAKE2b-256 180b79c0533b7daed670a3e0b53bf59796bac0766df6dac0ea6365266e5cabed

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.2-cp314-cp314-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 33d351b94a7599525451fc81d630fc62ac50d5ff11b967240da99788e290d51b
MD5 16d6feb13220b7f13fae83955154aac5
BLAKE2b-256 ad40c582db20e130d4f36ef6cd7cf669263cef1ae802a0a3dc3373830a31993f

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 513d9b88dc686e2770349f29f80c2a7435c42d1fec207c031bbb6862e65bde85
MD5 3ebf2dfc89ffd3f0a9b7684d98849dbf
BLAKE2b-256 97c3bfd9c71c87425dac8162618b18fdc1ade79760742c7c4af144f2979e172a

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.2-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 5c1c14c6fbd9817cba1e82907179a926c3bca1e6ea3aabd966d11fda2a30f1fb
MD5 8041a6721caea285aec1277e33f1e879
BLAKE2b-256 415a8eb8a74c500b6ebd4da0988b041bef7a106d18456f16108a2989be371d6b

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c8222a8d508bfce799e73a6390b8ab2761f895e8dcca392a1128243bd655534c
MD5 972e0b76b230be474477a5cd27280f96
BLAKE2b-256 16d1262dbdcfffdb21b25b872c7fac398bb47cbd63eabcfc71c612259adbdeea

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.2-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 eb428e03d32ea780a4126df227876f807274d5ca2a7ec0cb8282e6ea170f705a
MD5 98b56e54fc0018183a1f9d68670b9c1c
BLAKE2b-256 8d99d695700165536988bc190db545bea6f33f9f81157cb212842175caf23f1d

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 0800201743116bc0517d3dc7241e6a0abb555ddc2d443fbb1151d7027e430ca8
MD5 bf8c2d7188aa1d436518cf47b8af4dda
BLAKE2b-256 fe48fd5d4fb8218416c595795901ac3ee75c54a9ffe7375add8a40ec22872820

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.2-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 6a1e1e4d25ecfdfe4aaf62e04106b9a4a304b7323123228353b3c035153bb0ca
MD5 021449a23a2dc354b12da3f2e737fbb7
BLAKE2b-256 24c70f85823acf36bba3231d7f3e48bf00bdc755b633da61aea3e9c269192911

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6a9feba03083db80582096ef3e4d94c02cf3b1082bd57765108dc57732a1ebe1
MD5 f325e1374b652c8292e4f9aa617ff15a
BLAKE2b-256 ef2344302cd5da24d56963986f6f174bf88946c6933106004deaca15e40eec4c

See more details on using hashes here.

Provenance

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