Skip to content

Concepts

Understand the cryptographic foundations of SealTrail.

What is an audit trail?

An audit trail is a chronological record of actions taken within a system. Traditional audit logs are stored in databases or files — but there's no way to prove they haven't been modified after the fact.

SealTrail solves this by chaining events together with cryptographic hashes. Each event's hash depends on the previous event, creating a tamper-evident chain — similar to how blockchains work, but without the overhead.

Hash chains

Every event in SealTrail is linked to the previous one through a SHA-256 hash. The hash is computed from:

  • The event payload (actor, action, resource, context)
  • The previous event's hash
  • The event timestamp
hash-computation.ts
// Simplified hash computation
hash = SHA256(
  JSON.stringify(payload) + previousHash + timestamp
)

// Example chain:
// Event 1: hash = SHA256(payload1 + GENESIS_HASH + t1)
// Event 2: hash = SHA256(payload2 + event1.hash + t2)
// Event 3: hash = SHA256(payload3 + event2.hash + t3)

If anyone modifies an event's data, its hash changes — and every subsequent hash in the chain becomes invalid. This makes tampering detectable.

Genesis hash

The first event in a chain has no predecessor. It uses a special genesis hash as its previousHash — a well-known constant that marks the beginning of a chain.

The genesis hash is SHA256("GENESIS"). It's a fixed value shared across all SealTrail chains, making the chain start verifiable.

Chain partitioning

By default, all events go into the default chain. For better scalability and organization, you can partition events into independent chains by resource type:

partitioning.ts
// Separate chains for different resource types
await logEvent({
  actor: "user_123",
  action: "invoice.created",
  resource: "inv_456",
  chain: "invoices",     // Goes to the "invoices" chain
});

await logEvent({
  actor: "admin_1",
  action: "user.suspended",
  resource: "user_789",
  chain: "users",        // Goes to the "users" chain
});

// Each chain maintains its own independent hash sequence.
// No cross-chain dependencies = better write throughput.

Benefits of chain partitioning:

  • Scalability — Parallel writes to different chains don't conflict
  • Organization — Group related events logically
  • Verification — Verify one chain without scanning the entire dataset
  • Performance — Reduces 409 CONFLICT errors under high concurrency

Verification

Verification re-computes an event's hash from its stored payload, previous hash, and timestamp. If the computed hash matches the stored hash, the event is intact. If they differ, the data has been tampered with.

verification-flow.ts
// Verification process:
// 1. Fetch the event and its predecessor
// 2. Re-compute: expectedHash = SHA256(payload + prevHash + timestamp)
// 3. Compare expectedHash with storedHash
// 4. Check that event.previousHash matches predecessor.hash

// Result:
{
  valid: true,           // Hash matches
  errors: [],            // No integrity issues
  eventHash: "sha256:a1b2c3...",     // Stored hash
  computedHash: "sha256:a1b2c3...",  // Re-computed hash
  chainIntact: true,     // Previous hash link is valid
  verifiedAt: "2026-03-10T14:32:00Z"
}
Run verification periodically or integrate it into your compliance workflows. You can verify individual events via the API, or verify entire chains programmatically by iterating through events.