Skip to main content

pamoja-audit

A tamper-evident, hash-chained log; altering, reordering, or dropping a record breaks verification. One capability of pamoja, one memory-safe Rust core with bindings for TypeScript, Python, and C#.

read the guide documentation API reference

Install

pip install pamoja-audit
from pamoja import audit

This pulls in pamoja-native, the compiled engine, and pamoja-security. pip install pamoja is the whole framework in one package.

Example

The script the test suite runs, spliced here as it ran.

From bindings/python/guides/audit.py:

from pamoja.audit import AuditEntry, AuditLog, verify_chain
from pamoja.core import PamojaError
from pamoja.security import DeviceIdentity

# The controller signs its own log with a provisioned seed and an auditor holds only the
# public half, so a log can be checked anywhere without the device present.
seed = bytes([7]) * 32
keeper = DeviceIdentity.from_seed(seed)
auditor = keeper.public_key

log = AuditLog(keeper)
lit = log.append(b"burner=on")
stopped = log.append(b"burner=off")
print(f"recorded  burner=on as record {lit.index} and burner=off as record {stopped.index}")

# Each record hashes its own index, the digest of the record before it, and what it
# carries, so the chain fixes the order as well as the contents.
linked = "carries" if stopped.previous == lit.digest else "does not carry"
print(f"chained   record {stopped.index} {linked} the digest of record {lit.index}")
try:
    verify_chain(auditor, [lit, stopped])
    print("verified  the whole log is authentic and in order")
except PamojaError as error:
    print(f"rejected  {error}")

# Editing a stored record changes the digest its signature covers.
edited = bytearray(stopped.to_bytes())
edited[-1] ^= 0xFF
tampered = AuditEntry.from_bytes(bytes(edited))
try:
    verify_chain(auditor, [lit, tampered])
    print("an edited record verified, which should never happen")
except PamojaError as error:
    print(f"edited    caught: {error}")

# Dropping the first record, or swapping the two, leaves a record where its index says it
# cannot be, so a shortened or reordered log is caught as readily as an edited one.
try:
    verify_chain(auditor, [stopped])
    print("a shortened log verified, which should never happen")
except PamojaError as error:
    print(f"shortened caught: {error}")
try:
    verify_chain(auditor, [stopped, lit])
    print("a reordered log verified, which should never happen")
except PamojaError as error:
    print(f"reordered caught: {error}")

# A log checked against another device's key fails on the first signature.
stranger = DeviceIdentity.from_seed(bytes([8]) * 32).public_key
try:
    verify_chain(stranger, [lit, stopped])
    print("another device's key verified the log, which should never happen")
except PamojaError as error:
    print(f"stranger  caught: {error}")

# After a restart the controller loads its seed again and resumes from the last record in
# storage, so the log carries on as one chain rather than starting a second.
resumed = AuditLog.resume(DeviceIdentity.from_seed(seed), stopped)
relit = resumed.append(b"burner=on")
try:
    verify_chain(auditor, [lit, stopped, relit])
    print(f"resumed   burner=on again as record {relit.index}, and the whole log still verifies")
except PamojaError as error:
    print(f"rejected  {error}")

# What a chain cannot show is a record cut from its end, because what is left is still a
# valid chain. The auditor catches it against the last index the device reported.
reported = relit.index
cut = [lit, stopped]
verify_chain(auditor, cut)
ends = cut[-1].index
verdict = "a record is missing" if ends < reported else "nothing is missing"
print(
    f"cut       the log verifies but ends at record {ends}, "
    f"and the device reported record {reported}: {verdict}"
)

The same capability in every language

Language Package Reference
Rust pamoja-audit reference, docs.rs, install
TypeScript @pamoja/audit reference, install
Python pamoja-audit reference, install
C# Pamoja.Audit reference, install

Documentation

License

MIT

Release files for pamoja-audit 0.2.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 pamoja-audit 0.2.0
File Size Uploaded
pamoja_audit-0.2.0.tar.gz 4.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pamoja-audit 0.2.0
File Interpreter ABI Platform
pamoja_audit-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 9.8 kB

Release files / pamoja_audit-0.2.0.tar.gz

Download URL pamoja_audit-0.2.0.tar.gz
Size 4.6 kB
Tags Source
SHA-256 checksum
How to use checksums
d24f088d22970f2cd870c28a7c22391832966e65f6aa79fa9790a146f069f638
BLAKE2b-256 checksum
How to use checksums
0d4ec9103a7fac070765fa254f4831d1aa1df3cadcadace13befc2f7547f64a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / pamoja_audit-0.2.0-py3-none-any.whl

Download URL pamoja_audit-0.2.0-py3-none-any.whl
Size 5.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
938b0152c5b9730ef22daff074946f0d311451fa33d0b1ebe21d652ae9018de3
BLAKE2b-256 checksum
How to use checksums
fbc7a7595681ec1a26dbd7094a4b5099fe07653e7f4dc43942b07223179fa3d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.18

2 release files

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