> ## Documentation Index
> Fetch the complete documentation index at: https://docs.enfinitos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Auditor SDK

> Cryptographic verifier — Ed25519 signatures, SHA-256 hash chain, canonical-JSON re-projection. Open source under MIT.

The auditor / verifier is the single most important library EnfinitOS
publishes. It is open source under MIT in three published repositories:

* [github.com/EnfinitOS/sdk-auditor-ts](https://github.com/EnfinitOS/sdk-auditor-ts) — TypeScript / npm
* [github.com/EnfinitOS/sdk-auditor-py](https://github.com/EnfinitOS/sdk-auditor-py) — Python / pip
* [github.com/EnfinitOS/sdk-auditor-rs](https://github.com/EnfinitOS/sdk-auditor-rs) — Rust / cargo

<Note>
  **Don't trust us. Verify.** The library is offline by default — it
  does not call EnfinitOS or any third-party service. Anyone can fork
  it, audit it, fuzz the parser, and ship it inside their own
  compliance pipeline.
</Note>

## What it verifies

A proof pack is a signed, hash-chained document. The auditor does
four things against it:

1. **Ed25519 signature** against the published EnfinitOS
   verification key.
2. **SHA-256 hash chain** walked end-to-end for the tenant.
3. **Metering re-projection** from the source events embedded in
   the pack — re-running the same projection the platform settled
   against.
4. **Settlement reconciliation** re-run, asserting bit-identical
   output.

Any failure on any step fails verification. The auditor never
"warns" — it either verifies cleanly or it doesn't.

<Note>
  **Use SDK 0.0.4 or later.** Settlement verification is version-aware:
  current packs are stamped `settlement.v2` (3-field content-hash
  idemKey — `sha256(meterRecordIdemKey|partyRole|ledgerAccountCode)`)
  and historical `settlement.v1` packs still verify under their legacy
  2-field key. Earlier published SDK versions predate `settlement.v2`
  and report `SETTLEMENT_IDEM_KEY_MISMATCH` on every line of a current
  pack. 0.0.4 also adds **signed-export verification**
  (`verifySignedExport` / `verify_signed_export`) for the
  `?export=true` metering/settlement envelopes, and **cross-pack chain
  anchoring** via `priorAfterHash` — pass the previous pack's tail
  `afterHash` when verifying a later pack in a tenant's sealed series.
</Note>

## Rights-provenance signatures

The platform also signs every **rights-provenance record** — the
basis, right, offer, and challenge lifecycle rows — with Ed25519 at
write time, and the auditor verifies those signatures independently
of any pack. This checks **who** wrote each row; the hash-chain walk
checks **where** it sits in history. Run both.

The signing input is a flat pipe-delimited string — not canonical
JSON — so a verifier in any language reconstructs the exact bytes:

```
rightProvenance.v1|org|eventType|rightId|basisId|offerId|beforeHash|afterHash|keyId
```

with `-` encoding absent fields. One entry point per language:

* **TypeScript** — `verifyProvenanceChain` from
  `@enfinitos/sdk-auditor`
* **Python** — `verify_provenance_chain` from
  `enfinitos_auditor.provenance`
* **Rust** — `enfinitos_auditor::provenance::verify_provenance_chain`

The report partitions signed from unsigned records, so "N of M
records carry write-time signatures" can be quoted directly. Records
written before write-time signing existed (legacy `hmac-sha256`
rows) report an informational **SKIPPED** — there is nothing
write-signed for an independent party to verify — never an INVALID.
Existing exports keep verifying unchanged.

## Three language implementations

<Tabs>
  <Tab title="TypeScript">
    ```sh theme={null}
    npm install @enfinitos/sdk-auditor
    ```

    ```ts theme={null}
    import { EnfinitOSAuditor } from "@enfinitos/sdk-auditor";

    const auditor = new EnfinitOSAuditor({
      verificationKeySource: "platform", // or "local" with localKeys for offline audit
    });

    // Full pipeline: signatures + chain + metering + settlement.
    const report = await auditor.verifyAll({ pack });
    if (report.status !== "VALID") {
      for (const sub of [report.pack, report.chain, report.metering, report.settlement]) {
        for (const step of sub.steps) {
          if (step.status === "INVALID") {
            console.error(`[${step.reason}] ${step.target}: ${step.message}`);
          }
        }
      }
      process.exit(1);
    }

    // Chain-walk only (continuity, genesis-null, issuedAt ordering):
    const chain = await auditor.verifyProofChain(pack.records);
    if (chain.status !== "VALID") {
      console.error("Chain broken:", chain.steps.filter((s) => s.status === "INVALID"));
    }
    ```
  </Tab>

  <Tab title="Python">
    ```sh theme={null}
    pip install enfinitos-sdk-auditor
    ```

    ```python theme={null}
    from enfinitos_auditor import EnfinitOSAuditor

    auditor = EnfinitOSAuditor(verification_key_source="platform")  # or "local" with local_keys

    # Single proof pack: signatures + canonicalisation + chain.
    report = auditor.verify_proof_pack(pack)
    if report.status != "VALID":
        for step in report.steps:
            if step.status == "INVALID":
                print(f"[{step.reason}] {step.target}: {step.message}")
        raise SystemExit("Verification failed")

    # Chain-walk only (continuity, genesis-null, issued_at ordering):
    chain = auditor.verify_proof_chain(pack.records)
    if chain.status != "VALID":
        raise SystemExit("Chain broken")
    ```
  </Tab>

  <Tab title="Rust">
    ```sh theme={null}
    cargo add enfinitos-sdk-auditor
    ```

    ```rust theme={null}
    use enfinitos_auditor::{Auditor, AuditBundle, AuditStepStatus};

    // Offline-first: feed in the pinned verification key set you control.
    let auditor = Auditor::new(keys); // Vec<VerificationKey>

    // Chain-walk only (continuity, genesis-null, issued_at ordering).
    // The second argument anchors cross-pack continuity: None for a
    // tenant's first pack, Some(prior_tail_after_hash) for later packs.
    let chain = auditor.verify_proof_chain(&pack.records, None);
    if chain.status != AuditStepStatus::Valid {
        eprintln!("Chain broken");
    }

    // Full pipeline: signatures + chain + metering + settlement.
    // prior_after_hash (new in 0.0.4) anchors a later pack in a tenant's
    // sealed series; None asserts this is the tenant's first pack.
    let report = auditor.verify_all(&AuditBundle {
        pack,
        metering: None,
        settlement: None,
        prior_after_hash: None,
    });
    if report.status != AuditStepStatus::Valid {
        for s in &report.pack.steps {
            if s.status == AuditStepStatus::Invalid {
                eprintln!("[{:?}] {}: {}", s.reason, s.target, s.message);
            }
        }
        std::process::exit(1);
    }
    ```
  </Tab>
</Tabs>

## Byte compatibility

All three implementations are byte-compatible against a shared
conformance fixture set. A proof pack that verifies under the
TypeScript implementation must verify byte-identically under the
Python and Rust implementations. The canonical fixtures are in the
[sdk-auditor-ts](https://github.com/EnfinitOS/sdk-auditor-ts) repository
under `__tests__/fixtures/`.

## Verification key rotation

The verification key is published — and rotates on a published
schedule — at
[Verification keys](/compliance/verification-keys).

Rotation windows are **at least 90 days** so offline auditors have
time to pick up the new key without service interruption.

## Contributing

PRs welcome. Especially:

* **Fuzzers** for the proof-pack parser (fast-check, Hypothesis,
  cargo-fuzz).
* **New language bindings** — Go, Java, C#, Swift, Kotlin. Match the
  conformance vectors and we'll review.
* **Conformance-suite additions** — edge cases around chain breaks,
  signature mismatch, and metering re-projection.

See `CONTRIBUTING.md` in each repo ([ts](https://github.com/EnfinitOS/sdk-auditor-ts), [py](https://github.com/EnfinitOS/sdk-auditor-py), [rs](https://github.com/EnfinitOS/sdk-auditor-rs)).

## Security disclosure

If you find a vulnerability, **do not file a public issue**. Email
[security@enfinitos.com](mailto:security@enfinitos.com). Full policy
in `SECURITY.md` in each repo ([ts](https://github.com/EnfinitOS/sdk-auditor-ts), [py](https://github.com/EnfinitOS/sdk-auditor-py), [rs](https://github.com/EnfinitOS/sdk-auditor-rs)).
