Status: ACCEPTED
Date: 2026-08-02
Author: safeAPIFramework Team
Category: Data Integrity, Redundancy Support
Context
Problem Statement
Safety-critical systems with redundant channels (2oo2, 2oo3, etc.) must detect data corruption during transmission and channel-to-channel communication. Current approach (CRC-32 in examples) is adequate but not aligned with ERTMS/ETCS standards.
Requirements:
- Detect random transmission errors (bit flips, noise)
- Detect systematic data corruption (buffer overflow, memory corruption)
- Work across vital channels and cluster communication
- Deterministic, bounded execution time (safety-critical)
- No dynamic memory (MISRA C:2012 compliance)
- Integrate seamlessly with redundancy voting logic
Existing Approaches
| Approach | Pros | Cons |
| No checksum | Simplest | Can't detect corruption |
| CRC-32 | Fast, proven | Lower error detection |
| CRC-64 | Better error detection, ERTMS standard | Slightly more overhead |
| HMAC/Signature | Cryptographic | Too slow for real-time, not needed for random errors |
Why CRC-64 is Right for SAPI
- ERTMS Compliance: Railway systems standardize on CRC-64-CCITT (polynomial 0x1D4F63B86E40E541)
- Error Detection: Catches ~99.99% of random errors (vs ~99.9% for CRC-32)
- Performance: Lookup-table based (O(1) per byte), deterministic latency
- Simplicity: No keys or secrets, just polynomial-based math
- Integration: Can wrap vital messages transparently
Decision
ACCEPTED: Implement CRC-64 as a built-in SAPI module (sapi_checksum) with:
- CRC-64 Computation
- Lookup-table based (pre-computed at compile-time)
- Three polynomial options: ERTMS (default), ISO, XZ
- O(1) execution per byte (deterministic)
- Full statistics and diagnostics
- Vital Message Wrapper
- sapi_vital_message_t structure with integrated CRC-64
- Automatic CRC computation on send
- Automatic CRC verification on receive
- Sequence number checking (detect reordering)
- Timestamp for latency analysis
- Integration Points
- Core checksum API: sapi_checksum_crc64(data, size)
- Message wrapper: sapi_checksum_vital_message_*
- Statistics: sapi_checksum_get_stats() for monitoring
- Error handling: Return SAPI_STATUS_ERROR on CRC mismatch
Implementation
Module Structure (ADR-007 compliance)
include/safeapi/checksum/
├── sapi_checksum.h # API definition
src/checksum/
├── sapi_checksum.c # Implementation with LUT tables
├── CMakeLists.txt # Build configuration
tests/checksum/
├── test_crc64.c # CRC computation tests
├── test_vital_message.c # Message wrapper tests
└── test_integration.c # Redundancy integration tests
Key Design Decisions
1. Lookup Tables (Pre-computed)
Decision: Generate CRC-64 lookup tables at compile-time (not runtime)
Rationale:
- O(1) execution per byte (critical for determinism)
- Lookup tables are 2KB (acceptable embedded footprint)
- Avoids computation overhead in hot path
Trade-off:
- +2KB code size
- -10-100x CPU time per CRC computation
2. Three Polynomial Options
ERTMS (Default): 0x1D4F63B86E40E541
- Standard for railway signaling (EN 50126/50128)
- Used in ETCS/ERTMS RBC systems
- Recommended for all new projects
ISO: 0x000000000000001B
- ISO 3309, HDLC standard
- Legacy communication protocols
XZ (LZMA): 0x142F0E1EBA9EA3C3
- Alternative for high-reliability systems
- Used in compression algorithms
Selection: Default to ERTMS; user selects at initialization
3. Vital Message Wrapper
Structure:
typedef struct {
uint32_t sequence_number;
uint32_t sender_id;
uint32_t timestamp_ms;
uint8_t payload_size;
uint8_t payload[248];
uint64_t crc64;
Vital channel message with integrated CRC-64.
Usage Pattern:
- Sender: sapi_checksum_vital_message_create() → CRC computed
- Network: Send 256-byte message
- Receiver: sapi_checksum_vital_message_verify() → CRC checked
- Mismatch: Return SAPI_STATUS_ERROR → trigger safe-state
4. Statistics & Monitoring
Track:
- total_checksums — CRC computations performed
- verification_passes — Successful CRC checks
- verification_failures — Detected corruptions (!)
- sequence_errors — Out-of-order messages
- payload_oversize — Oversized payloads
Purpose: Monitor channel health, detect systematic failures
Architectural Fit
With Redundancy Framework (Future v0.4.0+)
Vital Channel (Future sapi_channel_t)
↓
Payload data
↓
[THIS] sapi_checksum_vital_message_create() ← CRC-64 wrapper
↓
Network transmission
↓
[THIS] sapi_checksum_vital_message_verify() ← CRC-64 check
↓
Voting Logic (detect if A vs B payloads differ after CRC OK)
↓
Output or Safe-State
Integration Benefits:
- CRC catches transmission corruption (random errors)
- Voting catches calculation errors (systematic errors)
- Safe-state on ANY error (CRC fail OR voting fail)
With Existing Modules
Depends on:
- safeapi/types — uint64_t, sapi_status_t
- safeapi/log — Logging for diagnostics
- safeapi/safestate — Trigger safe-state on error
- safeapi/timer — Timestamp in vital messages
Used by:
- Application IPC code (wrap payloads)
- Future sapi_channel_t (transparent CRC)
- Service unit diagnostics (monitor stats)
EN 50128 Compliance
Mandatory Techniques Supported
| Technique | How CRC-64 Helps |
| Defensive Programming (7.2.3) | Check all data with CRC before use |
| Error Detection (7.6.1) | Detect corruption via CRC mismatch |
| Fault Tolerance (7.6.1) | Trigger safe-state if CRC fails |
| Requirements Traceability (7.4.1) | REQ-ID links in code & docs |
Random vs Systematic Error Detection
Random Errors (handled by CRC-64):
- Cosmic ray bit flips: ✅ Detected
- Network noise: ✅ Detected
- Transient memory corruption: ✅ Detected
Systematic Errors (prevented by architecture):
- Compiler bugs: ⚠️ Detected by voting (if diverse compilers)
- Design flaws: ⚠️ Detected by voting (if diverse CPUs)
- Algorithm errors: ✅ Detected by voting (channel disagreement)
SIL Implications
SIL 1-2 (Single System)
CRC-64 optional but recommended for data integrity assurance:
if (result.match == 0) {
log_corruption_and_retry();
}
sapi_status_t sapi_checksum_crc64_verify(const uint8_t *data, size_t size, sapi_crc64_t expected_crc, sapi_checksum_result_t *result_out)
Verify CRC-64 of data against stored value.
SIL 3-4 (Redundant Systems)
CRC-64 mandatory for vital channel communication:
sapi_safestate_trigger(REASON_DATA_CORRUPTION);
}
sapi_status_t sapi_checksum_vital_message_verify(const sapi_vital_message_t *msg, uint32_t expected_sequence, uint8_t *payload_out, size_t payload_max_size, uint8_t *payload_size_out)
Verify vital channel message and extract payload.
sapi_status_t sapi_checksum_vital_message_create(sapi_vital_message_t *msg_out, uint32_t sender_id, uint32_t sequence, const uint8_t *payload, size_t payload_size)
Create vital channel message with CRC.
sapi_status_t sapi_ipc_send(sapi_ipc_handle_t handle, const void *message, size_t message_size, sapi_duration_ms_t timeout_ms)
Sends one message, blocking at most timeout_ms.
Implementation Timeline
Phase 1: Core API (v0.3.0)
- CRC-64 computation (ERTMS polynomial)
- Statistics tracking
- Full test suite
Phase 2: Integration (v0.4.0)
- Transparent CRC for vital channels
- Production deployment support
Phase 3: Advanced (Future)
- Additional polynomials (ISO, XZ)
- Hardware acceleration (if available)
- Per-site statistics aggregation
Risk Mitigation
| Risk | Mitigation |
| CRC collision (two different data same CRC) | ERTMS polynomial has good distribution; verify with testing |
| Performance overhead | Lookup-table O(1) keeps overhead <5% for typical 256-byte message |
| Lookup table size | 2KB acceptable for embedded; smaller/larger tables possible |
| Polynomial choice | Default ERTMS (railway standard); others available if needed |
Alternatives Considered
1. No Checksum (Status Quo)
Pros: Simpler code, less overhead
Cons: Can't detect corruption; fails EN 50128 error detection requirement
Decision: Rejected — insufficient error detection
2. CRC-32 Only
Pros: Smaller tables (512 bytes), commonly used
Cons: Lower detection rate; not ERTMS standard
Decision: Rejected — CRC-64 better for railway systems
3. HMAC-SHA256
Pros: Cryptographically strong
Cons: Too slow for real-time (msec → usec), overkill for random errors
Decision: Rejected — not needed for railway safety
4. Hamming Codes
Pros: Can correct single-bit errors
Cons: Much more complex, doesn't help with multi-bit errors
Decision: Rejected — CRC simpler for detect-and-safe-state model
Testing Strategy
Unit Tests
- CRC computation against known vectors
- Vital message creation/verification
- Corrupted payload detection
- Sequence number validation
Integration Tests
- CRC with actual IPC channels
- Multi-site cluster communication
- Failover with CRC verification
- Statistics collection
Property Tests
- CRC collision probability
- Performance benchmarks
- Execution time bounds
- Memory usage
Documentation
API Documentation
- Full Doxygen in sapi_checksum.h
- Example code for each function
- Integration examples with redundancy
Architectural Documentation
- This ADR (architecture decision)
- How CRC fits with voting logic
- Troubleshooting guide
Certification Documentation
- EN 50128 compliance argument
- Safety case material
- Test reports
Rollout Plan
- Merge: Implement in v0.3.0 alongside watchdog
- Document: Add examples to HARDWARE_PATTERNS_GUIDE.md
- Test: Full test suite and benchmarks
- Integrate: Use in redundancy APIs (v0.4.0)
- Release: Production support in v1.0
References
Approval
- Architect: Approved
- Safety Lead: Approved (meets EN 50128 error detection requirement)
- Performance: Approved (O(1) lookup, <5% overhead)
- Testing: Ready for implementation