pamoja for TypeScript - v0.1.17
    Preparing search index...

    Module @pamoja/audit

    Ergonomic facade over the generated audit binding.

    A log that can be edited after the fact proves nothing. Each record here is signed and carries the hash of the one before it, so altering a record, dropping one, or reordering two breaks the chain at that point and at every point after it. The index is part of what is signed, which is what makes a record removed from the end detectable too.

    @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#.

    API reference read the guide documentation

    npm install @pamoja/audit
    

    This pulls in @pamoja/native, the compiled engine, and @pamoja/security. npm install pamoja is the whole framework in one package.

    The test that runs in CI, spliced here as it ran.

    From bindings/node/guides/audit.ts:

    import { AuditEntry, AuditLog, verifyChain } from '@pamoja/audit'
    import { DeviceIdentity } from '@pamoja/security'

    // 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.
    const keeper = DeviceIdentity.fromSeed(Buffer.alloc(32, 7))
    const auditor = keeper.publicKey()

    const log = new AuditLog(keeper)
    const lit = log.append(Buffer.from('burner=on'))
    const stopped = log.append(Buffer.from('burner=off'))
    console.log(`recorded ${lit.index} then ${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.
    console.log(`chained ${stopped.previous.equals(lit.digest)}`)
    verifyChain(auditor, [lit, stopped])
    console.log('verified the whole log is authentic and in order')

    // Editing a stored record changes the digest its signature covers.
    const edited = Buffer.from(stopped.toBytes())
    edited[edited.length - 1] ^= 0xff
    const tampered = AuditEntry.fromBytes(edited)
    try {
    verifyChain(auditor, [lit, tampered])
    console.log('an edited record verified, which should never happen')
    } catch (error) {
    console.log(`edited caught: ${(error as Error).message}`)
    }

    // Dropping the first record leaves the survivor chained to a link that is no longer there,
    // so a shortened log is caught as readily as an edited one.
    try {
    verifyChain(auditor, [stopped])
    console.log('a shortened log verified, which should never happen')
    } catch (error) {
    console.log(`shortened caught: ${(error as Error).message}`)
    }
    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

    MIT

    AuditEntry
    AuditLog
    AuditVerifier
    verifyChain