|
| 1 | +# Design Document |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This design implements a future-proof CrcParams structure using an internal enum-based key storage system that can expand to support different key array sizes without breaking compatibility. The approach maintains the simplicity of const definitions while providing safe key access and zero runtime overhead through compiler optimizations. |
| 6 | + |
| 7 | +## Architecture |
| 8 | + |
| 9 | +### Core Components |
| 10 | + |
| 11 | +1. **CrcKeysStorage Enum**: Internal storage that can hold different key array sizes |
| 12 | +2. **CrcParams Structure**: Updated to use CrcKeysStorage internally while maintaining public API |
| 13 | +3. **Safe Accessor Methods**: Bounds-checked key access methods on CrcParams |
| 14 | +4. **Helper Functions**: Const-friendly constructors for CrcKeysStorage variants |
| 15 | + |
| 16 | +### Design Principles |
| 17 | + |
| 18 | +- **Zero Runtime Overhead**: Enum dispatch optimized away by compiler |
| 19 | +- **Backwards Compatibility**: Existing const definitions require minimal changes |
| 20 | +- **Gradual Migration**: Can be implemented in phases without breaking builds |
| 21 | +- **Safety First**: Bounds checking prevents panics from out-of-range access |
| 22 | + |
| 23 | +## Components and Interfaces |
| 24 | + |
| 25 | +### CrcKeysStorage Enum |
| 26 | + |
| 27 | +```rust |
| 28 | +#[derive(Clone, Copy, Debug)] |
| 29 | +enum CrcKeysStorage { |
| 30 | + /// Current 23-key format (for existing algorithms which includes 256 byte folding distances) |
| 31 | + KeysFold256([u64; 23]), |
| 32 | + /// Future 25-key format (for potential future expanded folding distances, for testing purposes only) |
| 33 | + KeysFutureTest([u64; 25]), |
| 34 | + // Additional variants can be added as needed |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | +**Key Methods:** |
| 39 | +- `get_key(index: usize) -> u64`: Safe key access with bounds checking |
| 40 | +- `key_count() -> usize`: Returns actual number of keys available |
| 41 | +- `from_keys_fold_256(keys: [u64; 23]) -> Self`: Const constructor for 23-key arrays |
| 42 | +- `from_keys_fold_future_test(keys: [u64; 25]) -> Self`: Const constructor for 25-key arrays |
| 43 | + |
| 44 | +### Updated CrcParams Structure |
| 45 | + |
| 46 | +```rust |
| 47 | +#[derive(Clone, Copy, Debug)] |
| 48 | +pub struct CrcParams { |
| 49 | + pub algorithm: CrcAlgorithm, |
| 50 | + pub name: &'static str, |
| 51 | + pub width: u8, |
| 52 | + pub poly: u64, |
| 53 | + pub init: u64, |
| 54 | + pub refin: bool, |
| 55 | + pub refout: bool, |
| 56 | + pub xorout: u64, |
| 57 | + pub check: u64, |
| 58 | + pub keys: CrcKeysStorage, // Changed from [u64; 23] |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +**Key Methods:** |
| 63 | +- `get_key(index: usize) -> u64`: Delegates to CrcKeysStorage |
| 64 | +- `get_key_checked(index: usize) -> Option<u64>`: Optional key access |
| 65 | +- `key_count() -> usize`: Returns actual key count |
| 66 | + |
| 67 | +### Const Definition Pattern |
| 68 | + |
| 69 | +```rust |
| 70 | +// Before (Phase 2): |
| 71 | +pub const CRC32_ISCSI: CrcParams = CrcParams { |
| 72 | + // ... other fields unchanged ... |
| 73 | + keys: KEYS_1EDC6F41_REFLECTED, // [u64; 23] |
| 74 | +}; |
| 75 | + |
| 76 | +// After (Phase 3): |
| 77 | +pub const CRC32_ISCSI: CrcParams = CrcParams { |
| 78 | + // ... other fields unchanged ... |
| 79 | + keys: CrcKeysStorage::from_keys_fold_256(KEYS_1EDC6F41_REFLECTED), |
| 80 | +}; |
| 81 | +``` |
| 82 | + |
| 83 | +## Data Models |
| 84 | + |
| 85 | +### Key Storage Variants |
| 86 | + |
| 87 | +| Variant | Array Size | Use Case | |
| 88 | +|---------|------------|----------| |
| 89 | +| KeysFold256 | [u64; 23] | Current implementation (128/256-byte folding) | |
| 90 | +| KeysFutureTest | [u64; 25] | Future expansion | |
| 91 | + |
| 92 | +### Migration States |
| 93 | + |
| 94 | +| Phase | CrcParams.keys Type | Architecture Code | Const Definitions | |
| 95 | +|-------|-------------------|------------------|------------------| |
| 96 | +| 1 | [u64; 23] | Direct access | Unchanged | |
| 97 | +| 2 | [u64; 23] | Safe accessors | Unchanged | |
| 98 | +| 3 | CrcKeysStorage | Safe accessors | Updated | |
| 99 | + |
| 100 | +## Error Handling |
| 101 | + |
| 102 | +### Bounds Checking Strategy |
| 103 | + |
| 104 | +1. **Safe Default**: Out-of-bounds key access returns 0 instead of panicking |
| 105 | +2. **Optional Access**: `get_key_checked()` returns `None` for invalid indices |
| 106 | +3. **Graceful Degradation**: Code continues to function with missing keys |
| 107 | + |
| 108 | +### Error Scenarios |
| 109 | + |
| 110 | +| Scenario | Behavior | Rationale | |
| 111 | +|----------|----------|-----------| |
| 112 | +| Access key[30] with 23-key storage | Returns 0 | Allows future expansion without breaking existing code | |
| 113 | +| Invalid key index | Returns 0 | Prevents panics, maintains stability | |
| 114 | +| Empty key storage | Returns 0 for all indices | Defensive programming | |
| 115 | + |
| 116 | +## Testing Strategy |
| 117 | + |
| 118 | +### Unit Tests |
| 119 | + |
| 120 | +1. **CrcKeysStorage Tests**: |
| 121 | + - Verify correct key storage and retrieval for each variant |
| 122 | + - Test bounds checking behavior |
| 123 | + - Validate const constructor functions |
| 124 | + |
| 125 | +2. **CrcParams Integration Tests**: |
| 126 | + - Verify safe accessor methods work correctly |
| 127 | + - Test backwards compatibility with existing const definitions |
| 128 | + - Validate zero runtime overhead through benchmarks |
| 129 | + |
| 130 | +3. **Migration Tests**: |
| 131 | + - Test each phase independently |
| 132 | + - Verify existing functionality remains intact |
| 133 | + - Validate const definition updates |
| 134 | + |
| 135 | +### Compatibility Tests |
| 136 | + |
| 137 | +1. **Third-Party Simulation**: |
| 138 | + - Create mock third-party const definitions |
| 139 | + - Verify they continue working through all phases |
| 140 | + - Test key access patterns used by external code |
| 141 | + |
| 142 | +2. **Performance Tests**: |
| 143 | + - Benchmark key access performance vs direct array access |
| 144 | + - Verify compiler optimizations eliminate enum dispatch |
| 145 | + - Measure memory usage impact |
| 146 | + |
| 147 | +### Integration Tests |
| 148 | + |
| 149 | +1. **Architecture Code Tests**: |
| 150 | + - Update existing architecture tests to use safe accessors |
| 151 | + - Verify SIMD operations work correctly with new key access |
| 152 | + - Test folding operations across different key storage variants |
| 153 | + |
| 154 | +2. **End-to-End Tests**: |
| 155 | + - Verify CRC calculations remain correct after migration |
| 156 | + - Test custom CrcParams creation and usage |
| 157 | + - Validate `get-custom-params` binary output |
| 158 | + |
| 159 | +## Implementation Phases |
| 160 | + |
| 161 | +### Phase 1: Add New Types |
| 162 | +- Add CrcKeysStorage enum to codebase |
| 163 | +- Add helper methods to CrcParams (delegating to existing keys field) |
| 164 | +- Maintain existing [u64; 23] field for compatibility |
| 165 | +- All tests continue to pass |
| 166 | + |
| 167 | +### Phase 2: Update Architecture Code |
| 168 | +- Replace direct key array access with safe accessor methods |
| 169 | +- Update SIMD and folding code to use `params.get_key(index)` |
| 170 | +- Maintain backwards compatibility |
| 171 | +- Performance remains identical |
| 172 | + |
| 173 | +### Phase 3: Switch to New Storage |
| 174 | +- Change CrcParams.keys field from [u64; 23] to CrcKeysStorage |
| 175 | +- Update all const definitions to use CrcKeysStorage::from_keys_23() |
| 176 | +- Update `get-custom-params` binary output format |
| 177 | +- This is the only breaking change, but minimal impact |
| 178 | + |
| 179 | +## Performance Considerations |
| 180 | + |
| 181 | +### Compiler Optimizations |
| 182 | + |
| 183 | +The Rust compiler optimizes enum dispatch when: |
| 184 | +1. All variants have the same access pattern |
| 185 | +2. The enum is used in hot paths with predictable patterns |
| 186 | +3. Inlining is enabled for accessor methods |
| 187 | + |
| 188 | +Expected assembly output for `params.get_key(21)`: |
| 189 | +```assembly |
| 190 | +; Same as direct array access keys[21] |
| 191 | +mov rax, qword ptr [rdi + 168 + 21*8] |
| 192 | +``` |
| 193 | + |
| 194 | +### Memory Layout |
| 195 | + |
| 196 | +| Storage Type | Memory Usage | Alignment | |
| 197 | +|--------------|--------------|-----------| |
| 198 | +| KeysFold256 | 184 bytes | 8-byte aligned | |
| 199 | +| KeysFutureTest | 200 bytes | 8-byte aligned | |
| 200 | +| Enum overhead | 0 bytes | (optimized away) | |
| 201 | + |
| 202 | +## Security Considerations |
| 203 | + |
| 204 | +### Bounds Safety |
| 205 | + |
| 206 | +The new design eliminates array bounds panics, which could be exploited in unsafe contexts. Safe key access prevents: |
| 207 | +- Buffer overflow attacks through malicious key indices |
| 208 | +- Denial of service through panic-induced crashes |
| 209 | +- Information disclosure through out-of-bounds memory access |
| 210 | + |
| 211 | +### Const Safety |
| 212 | + |
| 213 | +All const definitions remain compile-time validated, preventing: |
| 214 | +- Runtime key generation vulnerabilities |
| 215 | +- Dynamic key modification attacks |
| 216 | +- Timing-based side-channel attacks on key access |
0 commit comments