Ever tried to prove that a log file wasn't tampered with?
It's surprisingly hard. Hash chains prove sequence integrity. Signatures prove authorship. But neither proves that the signer didn't just... rewrite everything before signing.
This is the core problem in trading systems, especially prop trading where 80-100 firms collapsed in 2024-2025 amid payout disputes. The firm controls the logs. The trader has no recourse.
VCP-XREF solves this with a simple insight: when two independent parties log the same event, discrepancies reveal manipulation.
Let's build it.
The Problem: Single-Party Logs Are Inherently Untrustworthy
# This is what most audit systems look like
class SinglePartyAuditLog:
def __init__(self, signing_key):
self.events = []
self.key = signing_key
def log_event(self, event):
event['hash'] = sha256(canonicalize(event))
event['signature'] = sign(self.key, event['hash'])
self.events.append(event)
def verify(self):
# Looks secure, right?
for event in self.events:
if not verify_signature(event['signature'], event['hash']):
return False
return True
The problem? The owner can:
- Delete events before signing
- Modify events before signing
- Rewrite the entire log and re-sign
- Claim events never happened
Verification passes. Trust fails.
The Solution: VCP-XREF Dual Logging
VCP-XREF creates two independent audit trails that reference each other:
┌─────────────────┐ ┌─────────────────┐
│ Party A │◄──── Trade ───────►│ Party B │
│ (Trader) │ │ (Broker) │
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ VCP Log A │ │ VCP Log B │
│ + XREF ID │◄─── Compare ──────►│ + XREF ID │
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ External │ │ External │
│ Anchor A │ │ Anchor B │
│ (TSA/Chain) │ │ (TSA/Chain) │
└─────────────────┘ └─────────────────┘
Key insight: Unless both parties collude AND compromise both external anchors, manipulation is detectable.
VCP-XREF Schema
Here's the complete schema definition:
{
"VCP-XREF": {
"Version": "1.1",
"CrossReferenceID": "uuid",
"PartyRole": "INITIATOR | COUNTERPARTY | OBSERVER",
"CounterpartyID": "string",
"SharedEventKey": {
"OrderID": "string",
"AlternateKeys": ["string"],
"Timestamp": "int64",
"ToleranceMs": "int32"
},
"ExpectedCounterpartyHash": "string",
"ReconciliationStatus": "PENDING | MATCHED | DISCREPANCY | TIMEOUT",
"DiscrepancyDetails": {
"Field": "string",
"LocalValue": "string",
"CounterpartyValue": "string",
"Severity": "INFO | WARNING | CRITICAL"
}
}
}
Let's break this down:
| Field | Purpose |
|---|---|
CrossReferenceID |
UUID linking events across parties |
PartyRole |
Who logged this: initiator, counterparty, or observer |
SharedEventKey |
Correlation data both parties must agree on |
ToleranceMs |
Allowed timestamp difference (clock sync variance) |
ReconciliationStatus |
Current verification state |
Implementation: Python
Let's build a complete VCP-XREF implementation.
Core Data Structures
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, List
import uuid
import time
import hashlib
import json
class PartyRole(Enum):
INITIATOR = "INITIATOR"
COUNTERPARTY = "COUNTERPARTY"
OBSERVER = "OBSERVER"
class ReconciliationStatus(Enum):
PENDING = "PENDING"
MATCHED = "MATCHED"
DISCREPANCY = "DISCREPANCY"
TIMEOUT = "TIMEOUT"
class Severity(Enum):
INFO = "INFO"
WARNING = "WARNING"
CRITICAL = "CRITICAL"
@dataclass
class SharedEventKey:
order_id: str
timestamp: int # nanoseconds
tolerance_ms: int = 100
alternate_keys: List[str] = field(default_factory=list)
@dataclass
class DiscrepancyDetails:
field: str
local_value: str
counterparty_value: str
severity: Severity
@dataclass
class VCPXREFEvent:
version: str = "1.1"
cross_reference_id: str = field(default_factory=lambda: str(uuid.uuid4()))
party_role: PartyRole = PartyRole.INITIATOR
counterparty_id: str = ""
shared_event_key: SharedEventKey = None
expected_counterparty_hash: Optional[str] = None
reconciliation_status: ReconciliationStatus = ReconciliationStatus.PENDING
discrepancy_details: Optional[DiscrepancyDetails] = None
# VCP Core fields
event_id: str = field(default_factory=lambda: str(uuid.uuid4()))
event_type: str = "XREF"
payload: dict = field(default_factory=dict)
timestamp: int = field(default_factory=lambda: time.time_ns())
def to_dict(self) -> dict:
return {
"Header": {
"EventID": self.event_id,
"EventType": self.event_type,
"Timestamp": self.timestamp
},
"VCP-XREF": {
"Version": self.version,
"CrossReferenceID": self.cross_reference_id,
"PartyRole": self.party_role.value,
"CounterpartyID": self.counterparty_id,
"SharedEventKey": {
"OrderID": self.shared_event_key.order_id,
"Timestamp": self.shared_event_key.timestamp,
"ToleranceMs": self.shared_event_key.tolerance_ms,
"AlternateKeys": self.shared_event_key.alternate_keys
} if self.shared_event_key else None,
"ExpectedCounterpartyHash": self.expected_counterparty_hash,
"ReconciliationStatus": self.reconciliation_status.value,
"DiscrepancyDetails": {
"Field": self.discrepancy_details.field,
"LocalValue": self.discrepancy_details.local_value,
"CounterpartyValue": self.discrepancy_details.counterparty_value,
"Severity": self.discrepancy_details.severity.value
} if self.discrepancy_details else None
},
"Payload": self.payload
}
def compute_hash(self) -> str:
"""Compute SHA-256 hash of canonicalized event"""
canonical = json.dumps(self.to_dict(), sort_keys=True, separators=(',', ':'))
return hashlib.sha256(canonical.encode()).hexdigest()
The XREF Manager
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
import base64
class VCPXREFManager:
def __init__(self, party_id: str, private_key: Ed25519PrivateKey):
self.party_id = party_id
self.private_key = private_key
self.public_key = private_key.public_key()
self.events: dict[str, VCPXREFEvent] = {} # xref_id -> event
self.pending_xrefs: dict[str, VCPXREFEvent] = {}
def create_initiator_event(
self,
counterparty_id: str,
order_id: str,
payload: dict,
tolerance_ms: int = 100
) -> VCPXREFEvent:
"""Create a new XREF event as the initiator"""
xref_id = str(uuid.uuid4())
timestamp = time.time_ns()
event = VCPXREFEvent(
cross_reference_id=xref_id,
party_role=PartyRole.INITIATOR,
counterparty_id=counterparty_id,
shared_event_key=SharedEventKey(
order_id=order_id,
timestamp=timestamp,
tolerance_ms=tolerance_ms
),
reconciliation_status=ReconciliationStatus.PENDING,
payload=payload,
timestamp=timestamp
)
# Sign the event
event_hash = event.compute_hash()
signature = self.private_key.sign(event_hash.encode())
event.payload['_signature'] = base64.b64encode(signature).decode()
event.payload['_signer'] = self.party_id
self.events[xref_id] = event
self.pending_xrefs[xref_id] = event
return event
def create_counterparty_event(
self,
initiator_event: VCPXREFEvent,
payload: dict
) -> VCPXREFEvent:
"""Create a counterparty response to an initiator event"""
xref_id = initiator_event.cross_reference_id
timestamp = time.time_ns()
event = VCPXREFEvent(
cross_reference_id=xref_id,
party_role=PartyRole.COUNTERPARTY,
counterparty_id=initiator_event.payload.get('_signer', 'unknown'),
shared_event_key=SharedEventKey(
order_id=initiator_event.shared_event_key.order_id,
timestamp=timestamp,
tolerance_ms=initiator_event.shared_event_key.tolerance_ms
),
expected_counterparty_hash=initiator_event.compute_hash(),
reconciliation_status=ReconciliationStatus.PENDING,
payload=payload,
timestamp=timestamp
)
# Sign the event
event_hash = event.compute_hash()
signature = self.private_key.sign(event_hash.encode())
event.payload['_signature'] = base64.b64encode(signature).decode()
event.payload['_signer'] = self.party_id
self.events[xref_id] = event
return event
def verify_cross_reference(
self,
initiator_event: VCPXREFEvent,
counterparty_event: VCPXREFEvent
) -> tuple[ReconciliationStatus, Optional[DiscrepancyDetails]]:
"""Verify that two XREF events match"""
# Check CrossReferenceID
if initiator_event.cross_reference_id != counterparty_event.cross_reference_id:
return ReconciliationStatus.DISCREPANCY, DiscrepancyDetails(
field="CrossReferenceID",
local_value=initiator_event.cross_reference_id,
counterparty_value=counterparty_event.cross_reference_id,
severity=Severity.CRITICAL
)
# Check OrderID
if initiator_event.shared_event_key.order_id != counterparty_event.shared_event_key.order_id:
return ReconciliationStatus.DISCREPANCY, DiscrepancyDetails(
field="OrderID",
local_value=initiator_event.shared_event_key.order_id,
counterparty_value=counterparty_event.shared_event_key.order_id,
severity=Severity.CRITICAL
)
# Check timestamp within tolerance
time_diff_ns = abs(
initiator_event.shared_event_key.timestamp -
counterparty_event.shared_event_key.timestamp
)
tolerance_ns = initiator_event.shared_event_key.tolerance_ms * 1_000_000
if time_diff_ns > tolerance_ns:
return ReconciliationStatus.DISCREPANCY, DiscrepancyDetails(
field="Timestamp",
local_value=str(initiator_event.shared_event_key.timestamp),
counterparty_value=str(counterparty_event.shared_event_key.timestamp),
severity=Severity.WARNING if time_diff_ns < tolerance_ns * 2 else Severity.CRITICAL
)
# Check payload critical fields (customizable)
critical_fields = ['symbol', 'side', 'quantity', 'price']
for field in critical_fields:
init_val = initiator_event.payload.get(field)
counter_val = counterparty_event.payload.get(field)
if init_val is not None and counter_val is not None:
if init_val != counter_val:
return ReconciliationStatus.DISCREPANCY, DiscrepancyDetails(
field=field,
local_value=str(init_val),
counterparty_value=str(counter_val),
severity=Severity.CRITICAL
)
return ReconciliationStatus.MATCHED, None
Usage Example
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
# Generate keys for both parties
trader_key = Ed25519PrivateKey.generate()
broker_key = Ed25519PrivateKey.generate()
# Create managers
trader = VCPXREFManager("trader@example.com", trader_key)
broker = VCPXREFManager("broker@example.com", broker_key)
# Trader creates order (INITIATOR)
order_payload = {
"symbol": "EURUSD",
"side": "BUY",
"quantity": 1.0,
"price": 1.0850,
"order_type": "LIMIT"
}
initiator_event = trader.create_initiator_event(
counterparty_id="broker@example.com",
order_id="ORD-2026-001234",
payload=order_payload,
tolerance_ms=100
)
print(f"Initiator XREF ID: {initiator_event.cross_reference_id}")
print(f"Initiator Hash: {initiator_event.compute_hash()[:16]}...")
# Broker receives and logs (COUNTERPARTY)
execution_payload = {
"symbol": "EURUSD",
"side": "BUY",
"quantity": 1.0,
"price": 1.0850, # Same price = no slippage
"fill_type": "FULL",
"execution_venue": "LP-PRIME"
}
counterparty_event = broker.create_counterparty_event(
initiator_event=initiator_event,
payload=execution_payload
)
print(f"Counterparty Hash: {counterparty_event.compute_hash()[:16]}...")
# Verify cross-reference
status, discrepancy = trader.verify_cross_reference(initiator_event, counterparty_event)
print(f"\nReconciliation Status: {status.value}")
if discrepancy:
print(f"Discrepancy: {discrepancy.field} - {discrepancy.severity.value}")
print(f" Local: {discrepancy.local_value}")
print(f" Counterparty: {discrepancy.counterparty_value}")
Output:
Initiator XREF ID: 550e8400-e29b-41d4-a716-446655440000
Initiator Hash: a1b2c3d4e5f6g7h8...
Counterparty Hash: x9y8z7w6v5u4t3s2...
Reconciliation Status: MATCHED
Detecting Manipulation
Let's simulate a slippage manipulation attempt:
# Broker tries to log different price (manipulation attempt)
manipulated_payload = {
"symbol": "EURUSD",
"side": "BUY",
"quantity": 1.0,
"price": 1.0855, # 5 pips slippage added!
"fill_type": "FULL",
"execution_venue": "LP-PRIME"
}
manipulated_event = broker.create_counterparty_event(
initiator_event=initiator_event,
payload=manipulated_payload
)
# Verification catches the discrepancy
status, discrepancy = trader.verify_cross_reference(initiator_event, manipulated_event)
print(f"Reconciliation Status: {status.value}")
print(f"Discrepancy Detected!")
print(f" Field: {discrepancy.field}")
print(f" Trader logged: {discrepancy.local_value}")
print(f" Broker logged: {discrepancy.counterparty_value}")
print(f" Severity: {discrepancy.severity.value}")
Output:
Reconciliation Status: DISCREPANCY
Discrepancy Detected!
Field: price
Trader logged: 1.085
Broker logged: 1.0855
Severity: CRITICAL
The manipulation is caught automatically. Neither party can deny what they logged because both records are signed and anchored.
External Anchoring
Cross-reference alone isn't enough. Both parties could theoretically collude to rewrite history. External anchoring prevents this.
RFC 3161 Timestamp Authority
import requests
from asn1crypto import tsp, core
class RFC3161Anchor:
def __init__(self, tsa_url: str):
self.tsa_url = tsa_url
def anchor(self, data_hash: bytes) -> dict:
"""Get RFC 3161 timestamp token"""
# Build TimeStampReq
message_imprint = tsp.MessageImprint({
'hash_algorithm': {'algorithm': 'sha256'},
'hashed_message': data_hash
})
ts_req = tsp.TimeStampReq({
'version': 1,
'message_imprint': message_imprint,
'cert_req': True
})
# Send to TSA
response = requests.post(
self.tsa_url,
data=ts_req.dump(),
headers={'Content-Type': 'application/timestamp-query'}
)
# Parse response
ts_resp = tsp.TimeStampResp.load(response.content)
return {
'timestamp': ts_resp['time_stamp_token']['content']['encap_content_info']['content'].native,
'token': response.content.hex(),
'tsa': self.tsa_url
}
# Usage
tsa = RFC3161Anchor("https://freetsa.org/tsr")
merkle_root = compute_merkle_root(events)
anchor_proof = tsa.anchor(bytes.fromhex(merkle_root))
Bitcoin Anchoring (via OP_RETURN)
from bitcoinlib.wallets import Wallet
class BitcoinAnchor:
def __init__(self, wallet: Wallet):
self.wallet = wallet
def anchor(self, merkle_root: str) -> dict:
"""Anchor hash to Bitcoin via OP_RETURN"""
# Create OP_RETURN transaction
tx = self.wallet.send_to(
'OP_RETURN',
0,
data=bytes.fromhex(merkle_root)
)
return {
'txid': tx.txid,
'block': None, # Will be set after confirmation
'merkle_root': merkle_root,
'network': 'bitcoin'
}
def verify(self, anchor_proof: dict) -> bool:
"""Verify anchor exists on chain"""
tx = self.wallet.gettransaction(anchor_proof['txid'])
# Check OP_RETURN contains our hash
for output in tx.outputs:
if output.script_type == 'nulldata':
if output.data.hex() == anchor_proof['merkle_root']:
return True
return False
Merkle Tree for Batch Verification
For efficiency, batch events into Merkle trees before anchoring:
import hashlib
from typing import List
class MerkleTree:
def __init__(self, events: List[VCPXREFEvent]):
self.leaves = [bytes.fromhex(e.compute_hash()) for e in events]
self.tree = self._build_tree()
def _hash_pair(self, left: bytes, right: bytes) -> bytes:
return hashlib.sha256(left + right).digest()
def _build_tree(self) -> List[List[bytes]]:
if not self.leaves:
return [[hashlib.sha256(b'').digest()]]
tree = [self.leaves[:]]
while len(tree[-1]) > 1:
level = tree[-1]
next_level = []
for i in range(0, len(level), 2):
left = level[i]
right = level[i + 1] if i + 1 < len(level) else left
next_level.append(self._hash_pair(left, right))
tree.append(next_level)
return tree
@property
def root(self) -> str:
return self.tree[-1][0].hex()
def get_proof(self, index: int) -> List[tuple[str, str]]:
"""Get inclusion proof for event at index"""
proof = []
for level in self.tree[:-1]:
if index % 2 == 0:
sibling_index = index + 1
direction = 'right'
else:
sibling_index = index - 1
direction = 'left'
if sibling_index < len(level):
proof.append((direction, level[sibling_index].hex()))
index //= 2
return proof
@staticmethod
def verify_proof(leaf_hash: str, proof: List[tuple[str, str]], root: str) -> bool:
"""Verify a Merkle inclusion proof"""
current = bytes.fromhex(leaf_hash)
for direction, sibling in proof:
sibling_bytes = bytes.fromhex(sibling)
if direction == 'right':
current = hashlib.sha256(current + sibling_bytes).digest()
else:
current = hashlib.sha256(sibling_bytes + current).digest()
return current.hex() == root
# Usage
events = [event1, event2, event3, ...]
tree = MerkleTree(events)
print(f"Merkle Root: {tree.root}")
# Prove event2 is in the batch
proof = tree.get_proof(1)
verified = MerkleTree.verify_proof(event2.compute_hash(), proof, tree.root)
print(f"Event2 inclusion verified: {verified}")
Complete Flow: Order Lifecycle with XREF
Here's a complete example of an order lifecycle with dual logging:
class TradingSession:
def __init__(self, trader: VCPXREFManager, broker: VCPXREFManager):
self.trader = trader
self.broker = broker
self.xref_pairs: List[tuple[VCPXREFEvent, VCPXREFEvent]] = []
def execute_order(self, order: dict) -> dict:
"""Execute order with full XREF audit trail"""
# 1. Trader logs order request
trader_event = self.trader.create_initiator_event(
counterparty_id=self.broker.party_id,
order_id=order['order_id'],
payload={
'event_subtype': 'ORDER_NEW',
**order
}
)
# 2. Simulate order transmission
xref_id = trader_event.cross_reference_id
# 3. Broker receives and executes
execution_result = self._simulate_execution(order)
# 4. Broker logs execution
broker_event = self.broker.create_counterparty_event(
initiator_event=trader_event,
payload={
'event_subtype': 'ORDER_FILLED',
**execution_result
}
)
# 5. Store pair for verification
self.xref_pairs.append((trader_event, broker_event))
# 6. Immediate verification
status, discrepancy = self.trader.verify_cross_reference(
trader_event, broker_event
)
return {
'xref_id': xref_id,
'status': status.value,
'discrepancy': discrepancy,
'trader_hash': trader_event.compute_hash(),
'broker_hash': broker_event.compute_hash()
}
def _simulate_execution(self, order: dict) -> dict:
"""Simulate broker execution (replace with real execution)"""
return {
'symbol': order['symbol'],
'side': order['side'],
'quantity': order['quantity'],
'price': order['price'], # No slippage in simulation
'fill_type': 'FULL',
'execution_venue': 'SIM'
}
def generate_audit_report(self) -> dict:
"""Generate reconciliation report"""
matched = 0
discrepancies = []
for trader_event, broker_event in self.xref_pairs:
status, details = self.trader.verify_cross_reference(
trader_event, broker_event
)
if status == ReconciliationStatus.MATCHED:
matched += 1
else:
discrepancies.append({
'xref_id': trader_event.cross_reference_id,
'order_id': trader_event.shared_event_key.order_id,
'details': details
})
return {
'total_orders': len(self.xref_pairs),
'matched': matched,
'discrepancy_count': len(discrepancies),
'match_rate': matched / len(self.xref_pairs) if self.xref_pairs else 0,
'discrepancies': discrepancies
}
# Run trading session
session = TradingSession(trader, broker)
orders = [
{'order_id': 'ORD-001', 'symbol': 'EURUSD', 'side': 'BUY', 'quantity': 1.0, 'price': 1.0850},
{'order_id': 'ORD-002', 'symbol': 'GBPUSD', 'side': 'SELL', 'quantity': 0.5, 'price': 1.2650},
{'order_id': 'ORD-003', 'symbol': 'USDJPY', 'side': 'BUY', 'quantity': 2.0, 'price': 149.50},
]
for order in orders:
result = session.execute_order(order)
print(f"Order {order['order_id']}: {result['status']}")
report = session.generate_audit_report()
print(f"\nAudit Report:")
print(f" Match Rate: {report['match_rate']*100:.1f}%")
print(f" Discrepancies: {report['discrepancy_count']}")
Security Considerations
Threat Model
| Threat | VCP-XREF Mitigation |
|---|---|
| Single-party log modification | Counterparty log provides independent evidence |
| Bilateral collusion | External anchors make post-hoc collusion detectable |
| Replay attacks | UUID + timestamp uniqueness |
| Denial of logging | Missing counterparty record is itself evidence |
| Key compromise | Anchor timestamps prove when records existed |
Collusion Resistance
For undetectable manipulation, attackers must compromise:
- ✅ Party A's signing key
- ✅ Party B's signing key
- ✅ Party A's external anchor (e.g., DigiCert TSA)
- ✅ Party B's external anchor (e.g., Bitcoin)
If different anchor systems are used, this becomes practically infeasible.
Recommended Tolerances
| Tier | Timestamp Tolerance | Clock Sync |
|---|---|---|
| Platinum (HFT) | 1-10ms | PTP_LOCKED |
| Gold (Institutional) | 10-100ms | NTP_SYNCED |
| Silver (Retail) | 100-1000ms | BEST_EFFORT |
Regulatory Alignment
VCP-XREF helps meet requirements from:
- EU AI Act Article 12: Automatic logging with third-party verification
- MiFID II RTS 25: Order lifecycle records with precise timestamps
- SEC Rule 17a-4: Audit trail alternative to WORM storage
- MAS TRM Guidelines: Cryptographic integrity for trading records
Getting Started
- Clone the spec:
git clone https://github.com/veritaschain/vcp-spec
- Install reference implementation:
pip install vcp-core
Read the full spec: VCP v1.1 Specification
Join the discussion: GitHub Discussions
Conclusion
Single-party audit logs will always be vulnerable to the fundamental problem: the party controlling the logs controls the truth.
VCP-XREF solves this by requiring:
- Two independent logs of the same event
- External anchoring to prevent retroactive modification
- Cross-reference verification to detect discrepancies
The math is simple. The implementation is straightforward. The trust model is fundamentally different.
"Verify, Don't Trust" isn't just a slogan. It's architecture.
Questions? Find me in the comments or reach out at technical@veritaschain.org
The VCP specification is open-source under CC BY 4.0. Contributions welcome.
Top comments (0)