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

File metadata

  • Download URL: pylongfellow-0.2.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.2.0.tar.gz
Algorithm Hash digest
SHA256 a8931e9a710918c7f43d2ecfa9d2ee41a9873e26abf66fc5f444d56a322e4ec1
MD5 dfeb90cf203406c67e942bbf6d8446a6
BLAKE2b-256 cba62be7af37e6910668858baa2ec37b72b33b00be5b1f5e5c89a16ed8d79a5b

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.0-cp314-cp314-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 c00bc4e3e841f015f7793e1205bb387d0ea6a7f286f7bf8f78c36dd17041659b
MD5 46fd7770818cecf93ee55f7c0c95c86b
BLAKE2b-256 f8267dd7f328011f6d006b7d602c4ba141b5c4352b534bb698420b8a13925cf8

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e6a115f2c301ba11d79e5b3553b36c701d0a392644c1bdaf4984eff7fb16aa9d
MD5 b62cf40226afd8bcb19c842e2ce2aa21
BLAKE2b-256 a8991056120003a2126fbb43c488c6276f32c62261e78c6960a1a522596d16ea

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 b844295e3d4decf6fe3cd1f760c91da83828266f3b9453398615bee7e7ec51bc
MD5 9c884e1b60f107727085a0c7ac15d6af
BLAKE2b-256 f67cff991bec3d7232b3f4d5ab27d272cea468131665238da19bfc09c5afe421

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b983f6def214a0ac73e933a71f16f779ce2f7b9865225e755414ee4647e8dfcf
MD5 74b44b21151b68750a53a33cddc8c149
BLAKE2b-256 b30f87fdd1f780db98a5626f0c4c66674cae1d2abc9dfebb35484beb19279925

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 577d14676c8709ad86bb0292a17a3ae1db58220e4d1fa8b328ea31fe0bfb9b4d
MD5 a619310a8ccee6a6de3b3f1bb0e290d8
BLAKE2b-256 ec88daa7f2baa4173228e54eaaf8d65fded96f9a51c94d3338057e555573d9da

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 143559340f2b3d0a5594926dcd0a441171b78932b88e97b8ab25eca1f879c9e6
MD5 418c7e21c17b417d6a08ccc82c28c8db
BLAKE2b-256 51063524c9f6650cdbd242f503c6ba919f4783635d5e929ad1588cc5d517346c

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 cb97a67ba881ee53412f6b6d1c3da1b5f0071bdfb75ba6bdf99599dfbc72b5a1
MD5 e9005b009842796b74a98bb0ad483669
BLAKE2b-256 bb9067354d37ef2c00c5b44dea018ce1b107d7f4f942ac0b64693df5089e1ce3

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for pylongfellow-0.2.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 10748520d3b8b1707bef72ab1ae5d9ba64efca1d8b37b00d139867133458d125
MD5 b0974b479652214b012854d6257e84a3
BLAKE2b-256 e8419c3e171e88c83fac97d11c210d53943efd580073dfcb66e114494d887500

See more details on using hashes here.

Provenance

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