Adding Cryptographic Audit Trails to FIX Without Touching Your Trading Engine

Published: (December 22, 2025 at 04:46 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

Why Traditional Logging Falls Short

┌─────────────────────────────────────────┐
│          Traditional Logging            │
├─────────────────────────────────────────┤
│  ✗ Admin can modify logs                │
│  ✗ No proof of completeness             │
│  ✗ Timestamp ≠ proof of time            │
│  ✗ Auditor must trust submitter         │
│  ✗ Deletion is undetectable             │
└─────────────────────────────────────────┘

MiFID II RTS 25 requires clock sync to 100 µs. Even with perfect timestamps there is no cryptographic proof that:

  • the log wasn’t modified,
  • no entries were deleted,
  • the sequence is complete.

The Sidecar Solution

What if you could add cryptographic proof to every trading event without touching your FIX engine?

┌─────────────────────────────────────────────────────────┐
│                    Trading System                       │
│                                                         │
│   ┌──────────┐     ┌──────────┐     ┌──────────┐       │
│   │  Algo    │────▶│  Order   │────▶│   FIX    │──────▶│ Venue
│   │  Engine  │     │  Manager │     │  Engine  │       │
│   └────┬─────┘     └────┬─────┘     └────┬─────┘       │
│        │                │                │           │
│        │    ┌───────────┴────────────────┘           │
│        │    │  Event Tap (async copy)                │
│        ▼    ▼                                        │
│   ┌─────────────────────────────────────┐           │
│   │         VCP Sidecar Process         │           │
│   │  ┌─────────┐ ┌─────────┐ ┌───────┐ │           │
│   │  │ Collect │▶│  Hash   │▶│ Sign  │ │──▶ Auditor│
│   │  │ Events  │ │  Chain  │ │Ed25519│ │           │
│   │  └─────────┘ └─────────┘ └───────┘ │           │
│   └─────────────────────────────────────┘           │
└─────────────────────────────────────────────────────────┘

Key: FIX messages flow unchanged. Zero latency impact.

What the sidecar does

StepActionPurpose
ReceiveEvent copies asynchronously (no blocking)Non‑intrusive
HashSHA‑256 per eventTamper‑evidence
ChainLink to previous hashDetect deletions / re‑ordering
SignEd25519 signatureNon‑repudiation
AnchorBatch Merkle roots (periodic)Efficient external verification

Show Me The Code

FIX ExecutionReport (unchanged)

8=FIX.4.4|9=256|35=8|49=BROKER|56=CLIENT|
11=ORD-2025-001|37=EXE-12345|17=EXEC-67890|
150=F|39=2|55=XAUUSD|54=1|38=100|44=2650.50|
14=100|151=0|31=2650.45|32=100|6=2650.45|
60=20251222-14:30:05.120|10=078|

VCP Audit Event (parallel)

{
  "header": {
    "event_id": "01934e3a-7b2c-7f93-8f2a-1234567890ab",
    "trace_id": "01934e3a-6a1b-7c82-9d1b-0987654321dc",
    "timestamp": "2025-12-22T14:30:05.120000000Z",
    "event_type": "EXE",
    "clock_sync": "PTP_SYNCED",
    "symbol": "XAUUSD"
  },
  "payload": {
    "order_id": "EXE-12345",
    "side": "BUY",
    "price": "2650.50",
    "quantity": "100",
    "filled_qty": "100"
  },
  "security": {
    "event_hash": "sha256:8f2a7b3c4d5e6f...",
    "prev_hash": "sha256:a1b2c3d4e5f6...",
    "signature": "ed25519:7g8h9i0j..."
  }
}

The prev_hash links to the previous event. Break the chain? Instantly detectable.

The Hash Chain Explained

Event 1 (SIG)          Event 2 (ORD)          Event 3 (EXE)
┌──────────────┐       ┌──────────────┐       ┌──────────────┐
│ hash: a1b2c3 │       │ hash: d4e5f6 │       │ hash: g7h8i9 │
│ prev: 000000 │──────▶│ prev: a1b2c3 │──────▶│ prev: d4e5f6 │
│ sig: xxxxx   │       │ sig: yyyyy   │       │ sig: zzzzz   │
└──────────────┘       └──────────────┘       └──────────────┘
     │                      │                      │
     └──────────────────────┴──────────────────────┘

                   Merkle Root: m1n2o3
                   (anchored periodically)
  • Delete Event 2 → Chain breaks at Event 3.
  • Modify Event 1 → Hash changes, Event 2’s prev_hash mismatches.
  • Insert fake event → Signature verification fails.

Mapping to FIX Tags (optional embedding)

TagNameDescription
20001AuditEventHashSHA‑256 hash (first 16 chars)
20002AuditPrevHashLink to previous event
20003AuditTraceIDUUID v7 linking SIG → ORD → EXE
20004ClockSyncStatus0 = Unknown, 1 = NTP, 2 = PTP, 3 = GPS
20005AuditMerkleRootBatch integrity proof

Tags 20001‑20999 are user‑defined per the FIX spec, perfect for a PoC without formal approval.

Why Not Just Use a Public Blockchain?

  • Latency: 12 + seconds per block vs. nanosecond trading.
  • Cost: Gas fees explode at 10 K+ events/day.
  • Privacy: Order flow on a public ledger is undesirable.
  • Complexity: Your ops team will love you (/s).

Sidecar advantages

  • Local hash chains → instant verification.
  • Periodic Merkle‑root anchoring (optional, batched).
  • Private by default.
  • Runs alongside existing infrastructure with zero code changes to the FIX engine.

What About Regulations?

RegulationRequirementHow This Helps
MiFID II RTS 25Clock sync ≤ 100 µsclock_sync field proves sync status
MiFID II RTS 6Algo audit trailsFull, tamper‑evident event chain
SEC Rule 17a‑4Retention & integrityCryptographic hashes & signatures satisfy “integrity”
EMIRTransaction reportingEvent IDs & trace IDs enable end‑to‑end traceability

SIG → ORD → EXE chain

Regulatory Context

  • EU AI Act – Art. 12 – Automatic logging, cryptographic completeness proof
  • SEC Rule 17a‑4 – Tamper‑evident records, hash chain + signatures

The EU AI Act deadline for high‑risk AI systems is August 2027.
Algo‑trading systems are likely in scope.

Getting Started

1. Minimal Python implementation

import hashlib
import json
from datetime import datetime, timezone
import uuid

def generate_uuid_v7() -> str:
    """Placeholder for a UUID‑v7 generator."""
    return str(uuid.uuid4())

def create_event(event_type: str, payload: dict, prev_hash: str) -> dict:
    header = {
        "event_id":   generate_uuid_v7(),
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "event_type": event_type,
        "clock_sync": "NTP_SYNCED"
    }

    # Canonical JSON for consistent hashing
    canonical = json.dumps(
        {"header": header, "payload": payload},
        sort_keys=True,
        separators=(',', ':')
    )
    event_hash = hashlib.sha256(canonical.encode()).hexdigest()

    return {
        "header":   header,
        "payload":  payload,
        "security": {
            "event_hash": event_hash,
            "prev_hash":  prev_hash
        }
    }

# ── Chain events ────────────────────────────────────────
prev = "0" * 64

sig_event = create_event(
    "SIG",
    {"algo": "momentum-v2", "confidence": 0.87},
    prev
)
prev = sig_event["security"]["event_hash"]

ord_event = create_event(
    "ORD",
    {"symbol": "XAUUSD", "side": "BUY", "qty": 100},
    prev
)
prev = ord_event["security"]["event_hash"]

exe_event = create_event(
    "EXE",
    {"fill_price": 2650.45, "fill_qty": 100},
    prev
)

2. Hook into your FIX engine

Most FIX engines expose callback hooks. Below is a QuickFIX example:

void Application::onMessage(const FIX44::ExecutionReport& msg,
                            const FIX::SessionID& session) {
    // Normal processing
    processExecution(msg);

    // Async emit to VCP side‑car (non‑blocking)
    vcpSidecar.emitAsync("EXE", extractPayload(msg));
}

Zero impact on your critical path.

The Full Specification

ItemLink
SpecVCP v1.0
IETF Draftdraft‑kamimura‑scitt‑vcp
GitHubgithub.com/veritaschain
LicenseCC BY 4.0 (spec), Apache 2.0 (code)

No vendor lock‑in, no proprietary formats—just cryptographic proof.

TL;DR

WhatHow
ProblemTrading logs can be modified, deleted, or faked
SolutionHash chain + signatures in a side‑car process
Impact on FIXZero – messages flow unchanged
Impact on latencyZero – async event tap
VerificationAnyone can verify without trusting the submitter

The next time an auditor asks “Can you prove it?” you can answer with a cryptographic proof instead of “trust us”.

Questions?

  • Technical:
  • Reference material:

If you’re building algo‑trading systems and thinking about audit trails, I’d love to hear what challenges you’re facing. Drop a comment below. 👇

Back to Blog

Related posts

Read more »