Skip to content

API Reference

pylongfellow

pylongfellow.Pylongfellow

A Longfellow prover and verifier.

Example
longfellow = Pylongfellow(backend="google-cpp")
longfellow.load_circuit(circuit, 7, 1)
proof = longfellow.prove(mdoc, issuer_public_key, transcript, claims, timestamp)
longfellow.verify(issuer_public_key, transcript, claims, timestamp, proof, doctype)

Attributes:

Name Type Description
backend Backend

The selected Backend.

__init__

__init__(*, backend: str | Backend) -> None

Initialize with the selected backend.

Parameters:

Name Type Description Default
backend str | Backend

Registry name (google-cpp or isrg-rust) or a Backend instance.

required

Raises:

Type Description
ValueError

backend is not a registered backend name.

BackendUnavailableError

the backend's native dependency is not installed or built.

load_circuit

load_circuit(circuit: bytes, version: int, num_attributes: int) -> None

Load the circuit this instance proves and verifies with.

A second call replaces the loaded circuit.

Parameters:

Name Type Description Default
circuit bytes

Circuit bytes, as from generate_circuit or from disk.

required
version int

Version of the ZK specification the circuit is declared to be.

required
num_attributes int

Number of attributes the circuit is declared to prove over.

required

Raises:

Type Description
ValueError

No circuit has the declared version and attribute count (google-cpp); version is not 6 or 7 (isrg-rust).

prove

prove(mdoc: bytes, issuer_public_key: PublicKey, transcript: bytes, claims: list[RequestedAttribute], timestamp: datetime) -> bytes

Prove the claims hold over the mdoc, bound to the transcript.

Parameters:

Name Type Description Default
mdoc bytes

CBOR-encoded mdoc credential.

required
issuer_public_key PublicKey

The issuer's public key.

required
transcript bytes

Session transcript to bind the proof to.

required
claims list[RequestedAttribute]

Claims to prove; len(claims) must equal the loaded circuit's num_attributes.

required
timestamp datetime

Timezone-aware verification time.

required

Returns:

Type Description
bytes

Proof bytes.

Raises:

Type Description
RuntimeError

No circuit is loaded.

ValueError

timestamp is naive; len(claims) does not match the loaded circuit's num_attributes (google-cpp); or claims do not share one namespace (isrg-rust).

ProverError

The prover rejected the inputs.

verify

verify(issuer_public_key: PublicKey, transcript: bytes, claims: list[RequestedAttribute], timestamp: datetime, proof: bytes, doctype: str, *, device_namespaces: bytes | None = None) -> None

Verify a proof that the claims hold, against the transcript.

Parameters:

Name Type Description Default
issuer_public_key PublicKey

The issuer's public key.

required
transcript bytes

Session transcript the proof is bound to.

required
claims list[RequestedAttribute]

Claims to verify; len(claims) must equal the loaded circuit's num_attributes.

required
timestamp datetime

Timezone-aware verification time.

required
proof bytes

Proof bytes from prove.

required
doctype str

mdoc doctype the proof is scoped to.

required
device_namespaces bytes | None

Inner bytes of the tag-24 DeviceNameSpacesBytes; required by the isrg-rust backend.

None

Raises:

Type Description
RuntimeError

No circuit is loaded.

ValueError

timestamp is naive; len(claims) does not match the loaded circuit's num_attributes or doctype is 256 bytes or longer (google-cpp); or device_namespaces is None (isrg-rust).

VerifierError

The proof does not hold.

pylongfellow.LongfellowError

Bases: Exception

Base class for all exceptions raised by pylongfellow.

pylongfellow.mdoc

Data types

pylongfellow.mdoc.RequestedAttribute

A claim to prove or verify: attribute (namespace, id) holds cbor_value.

Attributes:

Name Type Description
namespace str

The mdoc namespace of the attribute.

id str

Attribute identifier within the namespace.

cbor_value bytes

Raw CBOR encoding of the value (e.g. b"\xf5" for true).

pylongfellow.mdoc.PublicKey

A public key, as coordinates x and y.

Errors

LongfellowError
└── mdoc.Error
    ├── ProverError      # .code: mdoc.ProverErrorCode or None
    ├── VerifierError    # .code: mdoc.VerifierErrorCode or None
    └── CircuitError     # .code: mdoc.CircuitGenerationErrorCode or None

pylongfellow.mdoc.Error

Bases: LongfellowError

Base class for exceptions raised by pylongfellow.mdoc.

pylongfellow.mdoc.ProverError

Bases: Error

A prover call failed.

Attributes:

Name Type Description
code

The ProverErrorCode when the backend supplies one, else None.

pylongfellow.mdoc.VerifierError

Bases: Error

A verifier call failed.

Attributes:

Name Type Description
code

The VerifierErrorCode when the backend supplies one, else None.

pylongfellow.mdoc.CircuitError

Bases: Error

Circuit generation failed.

Attributes:

Name Type Description
code

The CircuitGenerationErrorCode when the backend supplies one, else None.

pylongfellow.mdoc.ProverErrorCode

Bases: IntEnum

Return codes from run_mdoc_prover.

pylongfellow.mdoc.VerifierErrorCode

Bases: IntEnum

Return codes from run_mdoc_verifier.

pylongfellow.mdoc.CircuitGenerationErrorCode

Bases: IntEnum

Return codes from generate_circuit.

pylongfellow.backends

A Backend implements one longfellow implementation. Pylongfellow takes a registry name ("google-cpp", "isrg-rust") or a Backend instance.

pylongfellow.backends.Backend

Bases: Protocol

The operations a backend provides.

pylongfellow.backends.get_backend

get_backend(name: str) -> Backend

Return the named backend.

Parameters:

Name Type Description Default
name str

Registry name, one of google-cpp or isrg-rust.

required

Returns:

Type Description
Backend

The named backend.

Raises:

Type Description
ValueError

name is not a registered backend name.

pylongfellow.backends.BackendUnavailableError

Bases: LongfellowError

A backend's native dependency is not installed or built.

Backend scope

google-cpp and isrg-rust differ in the following behaviour.

  • Circuit versions. google-cpp accepts versions 5, 6, and 7 at the v0.9 pin, each with attribute counts 1 to 4. isrg-rust accepts versions 6 and 7.
  • Circuit generation. google_cpp.generate_circuit generates the highest table version for an attribute count. isrg-rust generates no circuits.
  • Claims count. google-cpp requires len(claims) to equal the loaded circuit's attribute count on prove and verify. isrg-rust passes the claims through.
  • device_namespaces. isrg-rust's verifier requires device_namespaces. google-cpp does not read it.
  • doctype. google-cpp rejects a doctype of 256 bytes or longer.
  • Error codes. ProverError.code and VerifierError.code carry a code on google-cpp and are None on isrg-rust.

pylongfellow.backends.google_cpp

Binds the vendored google/longfellow-zk C++ library through cffi.

pylongfellow.backends.google_cpp.ZkSpec

A row of the library's circuit table; what find_zk_spec and zk_specs return.

Attributes:

Name Type Description
system str

ZK system name and version (e.g. longfellow-libzk-v*).

circuit_hash str

SHA-256 (hex) pinning which circuit the row describes.

num_attributes int

Number of attributes the circuit proves over.

version int

Version of the ZK specification.

block_enc_hash int

block_enc parameter for the proof (upstream field).

block_enc_sig int

block_enc parameter for the proof (upstream field).

pylongfellow.backends.google_cpp.circuit_id

circuit_id(circuit: bytes) -> str

Recompute a circuit's canonical id from its bytes.

Binds circuit_id. The id is 64 hex chars and equals ZkSpec.circuit_hash.

Parameters:

Name Type Description Default
circuit bytes

Circuit bytes.

required

Returns:

Type Description
str

The canonical id, as 64-char hex.

Raises:

Type Description
Error

The bytes could not be parsed.

pylongfellow.backends.google_cpp.find_zk_spec

find_zk_spec(system: str, circuit_hash: str) -> ZkSpec | None

Look up the built-in ZkSpec for a (system, circuit_hash) pair.

Binds find_zk_spec.

Parameters:

Name Type Description Default
system str

Proof-system identifier the spec is registered under.

required
circuit_hash str

Canonical circuit id, as from circuit_id.

required

Returns:

Type Description
ZkSpec | None

The matching ZkSpec, or None if the build has no spec for that pair.

pylongfellow.backends.google_cpp.zk_specs

zk_specs() -> tuple[ZkSpec, ...]

Return every ZkSpec in the library's circuit table, in table order.

Binds the kZkSpecs table. Entries include superseded circuit versions: for a given num_attributes, several (version, circuit_hash) rows may be present. generate_circuit accepts only the highest version for a given num_attributes.

Returns:

Type Description
tuple[ZkSpec, ...]

The table's ZkSpec entries, in table order.

pylongfellow.backends.google_cpp.generate_circuit

generate_circuit(version: int, num_attributes: int) -> bytes

Generate the circuit with this version and attribute count.

Binds generate_circuit. C generates only the highest version the table holds for an attribute count, so an older version of a known count raises CircuitError.

Parameters:

Name Type Description Default
version int

Version of the ZK specification.

required
num_attributes int

Number of attributes the circuit proves over.

required

Returns:

Type Description
bytes

Circuit bytes.

Raises:

Type Description
ValueError

No circuit has that version and attribute count.

CircuitError

Generation failed.

Logging

PYLONGFELLOW_GOOGLE_CPP_LOG_LEVEL sets the stderr log level of google/longfellow-zk, read once when the backend first loads in the process. 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.

google/longfellow-zk logs to stderr, not through Python logging, and exposes no callback to bridge. There is no Python API and no runtime reconfiguration. The isrg-rust backend emits no log output.

pylongfellow.backends.isrg_rust

Binds the vendored abetterinternet/zk-cred-longfellow Rust library through generated UniFFI bindings.

pylongfellow.mdoc.testing

Functions

pylongfellow.mdoc.testing.create_presentation

create_presentation(doc_type: str, claims: Mapping[str, Mapping[str, object]], transcript: bytes, valid_from: datetime, valid_until: datetime, *, device_namespaces: Mapping[str, Mapping[str, object]] | None = None, issuer_key: EllipticCurvePrivateKey | None = None, device_key: EllipticCurvePrivateKey | None = None, issuer_certificate: Certificate | None = None) -> PresentationSpecimen

Create a presentation under locally held keys.

Assembles a DeviceResponse holding one document. The claims are issuer-signed into an MSO. The device signature covers the transcript, the doctype, and the device namespaces. Both signatures are verified before returning.

Parameters:

Name Type Description Default
doc_type str

Doctype of the single document.

required
claims Mapping[str, Mapping[str, object]]

Issuer-signed claims, as namespace to element identifier to element value. Values are encoded with cbor2; map order is preserved.

required
transcript bytes

CBOR-encoded session transcript the device signature is bound to. Presenting under another transcript requires re-signing, see sign_device_authentication.

required
valid_from datetime

MSO signed/validFrom timestamp, and the generated certificate's window start; timezone-aware.

required
valid_until datetime

MSO validUntil timestamp, and the generated certificate's window end; timezone-aware.

required
device_namespaces Mapping[str, Mapping[str, object]] | None

Device-signed items, as namespace to element identifier to element value. None issues the empty map.

None
issuer_key EllipticCurvePrivateKey | None

Issuer private key; a fresh P-256 key is generated when None.

None
device_key EllipticCurvePrivateKey | None

Device private key; a fresh P-256 key is generated when None.

None
issuer_certificate Certificate | None

Leaf certificate to embed in the x5chain header; must certify issuer_key. A self-signed leaf over issuer_key is generated when None.

None

Returns:

Type Description
PresentationSpecimen

The presentation, with the issuer public key, certificate, and device key.

Raises:

Type Description
ValueError

valid_from or valid_until is naive.

Error

The encoded credential failed its signature self-check; with a caller-supplied issuer_certificate this means the certificate does not certify issuer_key or does not carry an EC key.

pylongfellow.mdoc.testing.create_certificate

create_certificate(subject: str, public_key: EllipticCurvePublicKey, issuer: str, signing_key: EllipticCurvePrivateKey, valid_from: datetime, valid_until: datetime, *, ca: bool = False) -> x509.Certificate

Create a test X.509 certificate, CA or leaf.

The certificate is signed with ECDSA over SHA-256.

Parameters:

Name Type Description Default
subject str

Subject common name.

required
public_key EllipticCurvePublicKey

Public key the certificate certifies.

required
issuer str

Issuer common name; equals subject on a self-signed certificate.

required
signing_key EllipticCurvePrivateKey

Private key that signs the certificate.

required
valid_from datetime

Start of the validity window; timezone-aware.

required
valid_until datetime

End of the validity window; timezone-aware.

required
ca bool

True builds a CA certificate (basicConstraints CA, keyUsage keyCertSign); False builds a leaf (keyUsage digitalSignature).

False

Returns:

Type Description
Certificate

The signed certificate.

Raises:

Type Description
ValueError

valid_from or valid_until is naive.

pylongfellow.mdoc.testing.sign_device_authentication

sign_device_authentication(device_key: EllipticCurvePrivateKey, transcript: bytes, doc_type: str, device_namespaces: object) -> bytes

Sign DeviceAuthentication over a session transcript.

Builds the detached DeviceAuthenticationBytes payload from the transcript, the doctype, and the device namespaces, and signs it as a COSE Signature1 structure with ES256.

Parameters:

Name Type Description Default
device_key EllipticCurvePrivateKey

The credential's device private key.

required
transcript bytes

CBOR-encoded session transcript.

required
doc_type str

The credential's doctype.

required
device_namespaces object

The data item held in the credential's deviceSigned.nameSpaces: tag 24 over the encoded namespace map.

required

Returns:

Type Description
bytes

The 64-byte r || s signature; a document carries it as the final element of its deviceAuth.deviceSignature array.

pylongfellow.mdoc.testing.verify_device_authentication

verify_device_authentication(mdoc: bytes, transcript: bytes) -> None

Verify an mdoc's device signature over a session transcript.

The device key comes from the document's MSO. The signed payload is rebuilt from the document's own doctype and device namespaces.

Parameters:

Name Type Description Default
mdoc bytes

CBOR-encoded mdoc credential.

required
transcript bytes

CBOR-encoded session transcript the signature is bound to.

required

Raises:

Type Description
Error

The device signature does not verify over the transcript.

Data types

pylongfellow.mdoc.testing.PresentationSpecimen

A presentation with the issuer public key, certificate, and device key.

Attributes:

Name Type Description
mdoc bytes

CBOR-encoded DeviceResponse bytes.

issuer_public_key PublicKey

The issuer's public key.

issuer_certificate Certificate

Leaf certificate embedded in issuerAuth's x5chain header.

device_key EllipticCurvePrivateKey

Private key matching the MSO's deviceKeyInfo.