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 runtime dependencies are cffi, cryptography, and cbor2.

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.

Four functions in pylongfellow.mdoc bind no C entry point: create_credential assembles an ISO 18013-5 DeviceResponse test credential under locally held keys, with caller-controlled issuer-signed claims and device namespaces; create_certificate, sign_device_authentication, and verify_device_authentication are its trust-chain and device-signature companions. They run on cryptography and cbor2 alone; signatures are in the API reference.

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.3.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.3-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.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

pylongfellow-0.2.3-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.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

pylongfellow-0.2.3-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.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

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

pylongfellow-0.2.3-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.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.1 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.3.tar.gz.

File metadata

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

File hashes

Hashes for pylongfellow-0.2.3.tar.gz
Algorithm Hash digest
SHA256 26345b663984b4930a62cffd52b9d0f2a88b3ddf351e50bbab9e3a6297469f39
MD5 e331e9148ea75d0b0bb953fb14d66719
BLAKE2b-256 f00169ac7c2545087ed83117ddc1e88903bfa983e798de678bb21c249b5e6fd5

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.3-cp314-cp314-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 d3a6c39fcd52369ee6354de6c99335317717a577e73adb5580450ade6cde0e33
MD5 e6f06e61a997f80140114a6e529dc9b9
BLAKE2b-256 8b2b5e495a974db4d604a04243b5c4fb4488e95988da9417faf88bd5457850f9

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 a69a5994d0fbc6ceb3d188c175621b1ce75695633f891d7c9ac26377aedb976e
MD5 2ae2b89cf95a811c33946895879a3cd2
BLAKE2b-256 ed0e885642a751db3b083870ee3898c14e5be086847d4376ef5af7016f487d29

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.3-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3c06eb5666771b9fbf66908256dec597301ee385e3e23fc600797b33d4a26656
MD5 8e76dae0558c525a0cecb8fe004aa61a
BLAKE2b-256 67a53b74accd2a2f39fa8011c61ee735c5928ba1c89cde4dbfd1e2e156222cc3

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8f3a2be21551ddc535e113f320be7802232bce8747285f88b498edba9f24393e
MD5 e13cc61039230f17fe1315737cf3c30b
BLAKE2b-256 ece23a7e61c1eb24bed333f7203e4d5617a738bf23f26416575843153757ff65

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.3-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 f41563406948e389a554531df0dfcd5603c3b7f1f58e2264dc5390bf3d98b42c
MD5 823d193c84f71aef604b6c0d3502805a
BLAKE2b-256 d6cf781f7bb566f4a6b61ea6ed03e1795118ddfcd546fa29b3609d694a8341a9

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 03056d2e53bf5b57e9318a125dc7044a30b37a7cbe84383742b1c9a95ab8d406
MD5 f98c1610f2fcfeb40a8ada2f65a9c405
BLAKE2b-256 a9f5aafeadfab870e56a30d76971efabae84cfccf7cfa13b2219be62b695ac9b

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.3-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 044fc3578aa6a903d5eccc016497b95ed7ba8aa9e6c2bcfb4df06c1b960fe08b
MD5 3fcb2b52548bd16ff715c02ff4c1dc38
BLAKE2b-256 535e3c225d3819a5eb6520983a47ee8abf3a12633689f9e16f5c84ee76ffbef0

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 24eaa0430907ba60c67cbe86a500c44b5cfeec7a0c5a157b6749a9b29ce69f83
MD5 100b7f3df370c4f5be3500d80796cf40
BLAKE2b-256 dbadf1eaee2b6f3806bb92124ba84f7278506c83a01765cc84fa20bc066ae5a5

See more details on using hashes here.

Provenance

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