How we built a tamper-evident accounting ledger for retail SMBs using SHA-256 hash chaining

At Momentum (a product by ltiora) (https://ltiora.com/), we build retail and wholesale ERP software. One of the more interesting engineering problems we tackled was making our accounting ledger tamper-evident, meaning retroactive modification of histor…


This content originally appeared on DEV Community and was authored by sahil salma

At Momentum (a product by ltiora) (https://ltiora.com/), we build retail and wholesale ERP software. One of the more interesting engineering problems we tackled was making our accounting ledger tamper-evident, meaning retroactive modification of historical financial records is cryptographically detectable.

The Problem

Most accounting software for SMBs treats historical records as editable data. An administrator with sufficient access can modify a past journal entry, and while most platforms log user actions, those logs are themselves editable. An employee with enough access can modify a transaction and remove the log entry that recorded it.

For retail businesses with multiple staff touching finances, this creates silent audit risk that most operators don't consider until they're in a dispute or undergoing due diligence.

The Solution: Hash Chaining

We applied the same integrity principle used in blockchain systems to each accounting entry.

When a journal entry is written:

  1. We compute SHA-256(entry_data)
  2. The resulting hash is stored in the previous_hash field of the next journal entry
  3. This creates a chain: modifying Entry #N changes its hash, which no longer matches what Entry #N+1 says it should be
interface LedgerEntry {
  id: string;
  sequence_number: number;
  posted_at: string;
  debit_account_id: string;
  credit_account_id: string;
  amount_cents: number;
  description: string;
  previous_entry_hash: string | null; // null for genesis entry
  entry_hash: string; // SHA-256 of all fields above
}

function computeEntryHash(entry: Omit<LedgerEntry, 'entry_hash'>): string {
  const canonical = JSON.stringify({
    id: entry.id,
    sequence_number: entry.sequence_number,
    posted_at: entry.posted_at,
    debit_account_id: entry.debit_account_id,
    credit_account_id: entry.credit_account_id,
    amount_cents: entry.amount_cents,
    description: entry.description,
    previous_entry_hash: entry.previous_entry_hash,
  });
  return createHash('sha256').update(canonical).digest('hex');
}

Verification

We expose a chain verification endpoint that traverses all entries in sequence order and confirms that each entry's previous_entry_hash matches the hash of the preceding entry.

async function verifyLedgerIntegrity(
  tenantId: string
): Promise<{ valid: boolean; broken_at_sequence?: number }> {
  const entries = await db.ledgerEntries
    .where({ tenant_id: tenantId })
    .orderBy('sequence_number', 'asc')
    .all();

  let previousHash: string | null = null;

  for (const entry of entries) {
    if (entry.previous_entry_hash !== previousHash) {
      return { valid: false, broken_at_sequence: entry.sequence_number };
    }
    const expectedHash = computeEntryHash(entry);
    if (entry.entry_hash !== expectedHash) {
      return { valid: false, broken_at_sequence: entry.sequence_number };
    }
    previousHash = entry.entry_hash;
  }

  return { valid: true };
}

Tradeoffs and Edge Cases

Appends only: The hash chain only works for append only ledgers. This maps well to accounting (journal entries are never modified; corrections are made by posting reversing entries), but it means the business logic layer must enforce append only strictly.

Replication: In a multi-region setup, the genesis entry's hash must be agreed upon before any writes. We use a leader election approach for ledger writes to ensure sequence numbers and hashes are assigned deterministically.

Performance: Verification is O(n) in the number of entries. For high-volume retail (millions of transactions/year), we run verification asynchronously on a schedule rather than on every write.

What We Didn't Do

We deliberately didn't implement blockchain style distributed consensus — that's overkill for a single tenant accounting system. The threat model here is internal fraud and accidental modification, not a distributed Byzantine failure. A simple hash chain is sufficient.

If this is interesting to you, we published a user facing explanation of the concept here: https://ltiora.com/blog/tamper-evident-accounting-software



This content originally appeared on DEV Community and was authored by sahil salma


Print Share Comment Cite Upload Translate Updates
APA

sahil salma | Sciencx (2026-05-01T03:47:17+00:00) How we built a tamper-evident accounting ledger for retail SMBs using SHA-256 hash chaining. Retrieved from https://www.scien.cx/2026/05/01/how-we-built-a-tamper-evident-accounting-ledger-for-retail-smbs-using-sha-256-hash-chaining/

MLA
" » How we built a tamper-evident accounting ledger for retail SMBs using SHA-256 hash chaining." sahil salma | Sciencx - Friday May 1, 2026, https://www.scien.cx/2026/05/01/how-we-built-a-tamper-evident-accounting-ledger-for-retail-smbs-using-sha-256-hash-chaining/
HARVARD
sahil salma | Sciencx Friday May 1, 2026 » How we built a tamper-evident accounting ledger for retail SMBs using SHA-256 hash chaining., viewed ,<https://www.scien.cx/2026/05/01/how-we-built-a-tamper-evident-accounting-ledger-for-retail-smbs-using-sha-256-hash-chaining/>
VANCOUVER
sahil salma | Sciencx - » How we built a tamper-evident accounting ledger for retail SMBs using SHA-256 hash chaining. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2026/05/01/how-we-built-a-tamper-evident-accounting-ledger-for-retail-smbs-using-sha-256-hash-chaining/
CHICAGO
" » How we built a tamper-evident accounting ledger for retail SMBs using SHA-256 hash chaining." sahil salma | Sciencx - Accessed . https://www.scien.cx/2026/05/01/how-we-built-a-tamper-evident-accounting-ledger-for-retail-smbs-using-sha-256-hash-chaining/
IEEE
" » How we built a tamper-evident accounting ledger for retail SMBs using SHA-256 hash chaining." sahil salma | Sciencx [Online]. Available: https://www.scien.cx/2026/05/01/how-we-built-a-tamper-evident-accounting-ledger-for-retail-smbs-using-sha-256-hash-chaining/. [Accessed: ]
rf:citation
» How we built a tamper-evident accounting ledger for retail SMBs using SHA-256 hash chaining | sahil salma | Sciencx | https://www.scien.cx/2026/05/01/how-we-built-a-tamper-evident-accounting-ledger-for-retail-smbs-using-sha-256-hash-chaining/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.