Skip to main content

ib1-provenance

Python library to create, sign and verify records that follow the IB1 Provenance Records 1.0 specification.

Requires Python 3.11 or later. See CHANGELOG.md for changes between versions.

Install

pip install ib1-provenance

To sign with a key held in AWS KMS, install the kms extra:

pip install "ib1-provenance[kms]"

Use

A record is built from steps, then signed with a signing certificate issued by the Directory. A participant who receives a record verifies it, adds its own steps, and signs it again.

from ib1.provenance import Record
from ib1.provenance.certificates import CertificatesProviderSelfContainedRecord
from ib1.provenance.signing import SignerFiles

TRUST_FRAMEWORK_URL = "https://registry.core.trust.ib1.org/trust-framework"

with open("signing-ca-root.pem", "rb") as f:
    provider = CertificatesProviderSelfContainedRecord(f.read())

# Create and sign a record
record = Record(TRUST_FRAMEWORK_URL)
origin_id = record.add_step({"type": "origin", "scheme": "...", ...})
record.add_step({"type": "transfer", "of": origin_id, "scheme": "...", ...})
signer = SignerFiles(provider, "signing-bundle.pem", "signing-key.pem")
signed = record.sign(signer)
attachment = signed.encoded()  # JSON-serialisable dict to send with the data

# Receive and verify a record
received = Record(TRUST_FRAMEWORK_URL, attachment)
received.verify(provider)
transfer = received.find_step({"type": "transfer", "to": "https://directory.core.trust.ib1.org/member/81524"})
received.require_signer(transfer["id"], role="https://registry.core.trust.ib1.org/scheme/perseus/role/energy-data-provider")

main.py has a full example of a record passed between three members.

Certificate providers

  • CertificatesProviderSelfContainedRecord includes the signing certificate and its issuer chain in the record, and uses them to verify. Use this one unless you have a reason not to.
  • CertificatesProviderLocal reads certificates from a local directory and leaves them out of the record, which makes it smaller.

Both take the signing root CA certificate from the Directory. A root CA certificate included in a record is never trusted.

Signers

  • SignerFiles reads the certificate bundle and private key from PEM files.
  • SignerInMemory takes cryptography certificate and key objects.
  • SignerKMS signs with a key in AWS KMS. It needs the kms extra.

Checks

add_step() and sign() check that new steps follow the specification: step types, timestamps, references between steps, and at least one origin step. They raise ValidationError, and sign() raises before the signer is called.

verify() checks signatures, certificates and the structure of the signed record. It does not repeat the step checks, so records signed by older versions still verify. To check the steps of a received record, call validate() after verify(). It returns a list of problems and does not raise.

Revocation is not checked yet, see directory#272.

Exceptions

All exceptions raised by the library subclass ProvenanceError, which can be imported from ib1.provenance:

  • ValidationError, a record or step does not follow the specification
  • VerificationError, a signed record could not be verified
  • CertificateError, a certificate is missing or does not have the expected contents
  • CertificateNotFoundError, a certificate serial number is not available. It is also a KeyError.

A bad signature raises cryptography.exceptions.InvalidSignature. A certificate chain which is not valid at the signing time raises cryptography.x509.verification.VerificationError.

Develop

pipx install poetry
poetry install
poetry run pytest
poetry run ruff check .

tests/vectors/ holds a signed record and the exact data that was signed, for checking other implementations against this one. tests/vectors/generate.py regenerates them.

Run the example

main.py needs a set of test certificates, which scripts/certmaker.sh creates. The certificates expire, so run it again if the example fails with "cert is not valid at validation time".

mkdir certs
cd certs
sh ../scripts/certmaker.sh
cd ..
poetry run python main.py

Decode a record

poetry run python decode-self-contained-provenance.py path/to/signing-CA-root.pem < record.json

Publish the library

  1. Add the release notes to CHANGELOG.md.
  2. Change version in pyproject.toml.
  3. Merge to main, then tag the merge commit, for example git tag v0.6.0 && git push origin v0.6.0.
  4. Build and publish:
poetry build
poetry publish

Metadata

Release files for ib1-provenance 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ib1-provenance 0.6.0
File Size Uploaded Provenance Actions
ib1_provenance-0.6.0.tar.gz 13.9 kB Without provenance Details for ib1_provenance-0.6.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ib1-provenance 0.6.0
File Interpreter ABI Platform Actions
ib1_provenance-0.6.0-py3-none-any.whl Python 3 none any Details for ib1_provenance-0.6.0-py3-none-any.whl

Total release size: 28.6 kB

Release files / ib1_provenance-0.6.0.tar.gz

Download URL ib1_provenance-0.6.0.tar.gz
Size 13.9 kB
Tags Source
SHA-256 checksum
How to use checksums
884ac0002390bdfafda1d7d62e13617db6406dcc0dd770198565337e71fc06bb
BLAKE2b-256 checksum
How to use checksums
d7dbc0b12aeeea906fe5305acc91b5c66924ef370d39a8a7f00f93c9f5aa0d69
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.3 CPython/3.12.16 Darwin/24.6.0

Release files / ib1_provenance-0.6.0-py3-none-any.whl

Download URL ib1_provenance-0.6.0-py3-none-any.whl
Size 14.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bc650d6677a7c6e3b192907c5941d2d630ad7097118e56ec22112d9dffd3d013
BLAKE2b-256 checksum
How to use checksums
c4fffbfc2e3c0660bb13e33e3cc8405cf74c274b91f0f2a8e48f2001dd87e0e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.3 CPython/3.12.16 Darwin/24.6.0

Security for ib1-provenance 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page