OXYGENHUB
# f2f91ceb0e9f oxygen / vendor / crc-fast / .kiro / specs / crc-width32-shared-base / design.md
10.9 KiB · Markdown · last changed Strata: the cloud stores send through ureq, so every release target links 1 month ago renderedsource blame history raw
1
# Design Document: CRC Width-32 Shared Base
2
3
## Overview
4
5
This design refactors the CRC-16 and CRC-32 algorithm implementations to share a common base module. Since CRC-16 operates in 32-bit space (scaling 16-bit values up for processing, then down for results), both widths use nearly identical SIMD operations. By extracting this shared logic into `src/crc32/width32_ops.rs`, we eliminate ~200 lines of duplicated code and prepare the codebase for future CRC width additions.
6
7
## Architecture
8
9
### Current Structure
10
11
```
12
src/
13
├── crc16/
14
│   ├── algorithm.rs    # Width16 impl + process_0_to_15 (duplicated)
15
│   ├── consts.rs
16
│   └── mod.rs
17
├── crc32/
18
│   ├── algorithm.rs    # Width32 impl + process_0_to_15 (duplicated)
19
│   ├── consts.rs
20
│   └── mod.rs
21
├── crc64/
22
│   ├── algorithm.rs    # Width64 impl + process_0_to_15 (unique)
23
│   ├── consts.rs
24
│   └── mod.rs
25
└── algorithm.rs        # Shared algorithm infrastructure
26
```
27
28
### Proposed Structure
29
30
```
31
src/
32
├── crc16/
33
│   ├── algorithm.rs    # Width16 impl (delegates to width32_ops)
34
│   ├── consts.rs
35
│   └── mod.rs
36
├── crc32/
37
│   ├── algorithm.rs    # Width32 impl (delegates to width32_ops)
38
│   ├── consts.rs
39
│   ├── mod.rs
40
│   └── width32_ops.rs  # NEW: Shared 32-bit-space operations
41
├── crc64/
42
│   ├── algorithm.rs    # Width64 impl + process_0_to_15 (unchanged)
43
│   ├── consts.rs
44
│   └── mod.rs
45
└── algorithm.rs        # Shared algorithm infrastructure
46
```
47
48
## Components and Interfaces
49
50
### 1. New Module: `src/crc32/width32_ops.rs`
51
52
This module contains all shared 32-bit-space operations:
53
54
```rust
55
//! Shared operations for CRC widths that operate in 32-bit space (CRC-16, CRC-32).
56
//!
57
//! CRC-16 computation scales 16-bit values to 32-bit space, uses these operations,
58
//! then scales results back to 16 bits. CRC-32 uses these operations directly.
59
60
use crate::algorithm;
61
use crate::consts::CRC_CHUNK_SIZE;
62
use crate::crc32::consts::{PSHUFB_SHF_TABLE_FORWARD, PSHUFB_SHF_TABLE_REVERSE, SIMD_CONSTANTS};
63
use crate::enums::Reflector;
64
use crate::structs::CrcState;
65
use crate::traits::{ArchOps, EnhancedCrcWidth};
66
67
/// SIMD constants shared by CRC-16 and CRC-32
68
pub const WIDTH32_CONSTANTS_REFLECTED: [[u64; 2]; 4] = [
69
    [0x08090a0b0c0d0e0f, 0x0001020304050607], // smask
70
    [0x8080808080808080, 0x8080808080808080], // mask1
71
    [0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFF], // mask2 reverse
72
    [0x0000000000000000, 0x0000000000000000], // unused
73
];
74
75
pub const WIDTH32_CONSTANTS_FORWARD: [[u64; 2]; 4] = [
76
    [0x08090a0b0c0d0e0f, 0x0001020304050607], // smask
77
    [0x8080808080808080, 0x8080808080808080], // mask1
78
    [0xffffffffffffffff, 0x00000000ffffffff], // mask2 forward
79
    [0x0000000000000000, 0x0000000000000000], // unused
80
];
81
82
/// Load constants for 32-bit-space CRC operations
83
#[inline(always)]
84
pub fn load_constants(reflected: bool) -> [[u64; 2]; 4] {
85
    if reflected {
86
        WIDTH32_CONSTANTS_REFLECTED
87
    } else {
88
        WIDTH32_CONSTANTS_FORWARD
89
    }
90
}
91
92
/// Fold 16 bytes for 32-bit-space CRC operations
93
#[inline(always)]
94
pub unsafe fn fold_16<T: ArchOps>(
95
    state: &mut CrcState<T::Vector>,
96
    coeff: T::Vector,
97
    data_to_xor: T::Vector,
98
    ops: &T,
99
) where
100
    T::Vector: Copy,
101
{
102
    let (h, l) = if state.reflected {
103
        (
104
            ops.carryless_mul_10(state.value, coeff),
105
            ops.carryless_mul_01(state.value, coeff),
106
        )
107
    } else {
108
        (
109
            ops.carryless_mul_00(state.value, coeff),
110
            ops.carryless_mul_11(state.value, coeff),
111
        )
112
    };
113
    state.value = ops.xor3_vectors(h, l, data_to_xor);
114
}
115
116
/// Fold to width for 32-bit-space CRC operations
117
#[inline(always)]
118
pub unsafe fn fold_width<T: ArchOps>(
119
    state: &mut CrcState<T::Vector>,
120
    high: u64,
121
    low: u64,
122
    ops: &T,
123
) where
124
    T::Vector: Copy,
125
{
126
    let coeff_vector_low = ops.create_vector_from_u64_pair_non_reflected(0, low);
127
    let coeff_vector_high = ops.create_vector_from_u64_pair_non_reflected(high, 0);
128
129
    state.value = if state.reflected {
130
        ops.xor_vectors(
131
            ops.carryless_mul_00(state.value, coeff_vector_low),
132
            ops.shift_right_8(state.value),
133
        )
134
    } else {
135
        ops.xor_vectors(
136
            ops.carryless_mul_01(state.value, coeff_vector_low),
137
            ops.shift_left_8(state.value),
138
        )
139
    };
140
141
    let (clmul, masked) = if state.reflected {
142
        let mask2 = ops.load_aligned(&[0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFF]);
143
        let masked = ops.and_vectors(state.value, mask2);
144
        let shifted = ops.shift_left_12(state.value);
145
        let clmul = ops.carryless_mul_11(shifted, coeff_vector_high);
146
        (clmul, masked)
147
    } else {
148
        let mask2 = ops.load_aligned(&[0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF]);
149
        let masked = ops.and_vectors(state.value, mask2);
150
        let shifted = ops.shift_right_12(state.value);
151
        let clmul = ops.carryless_mul_10(shifted, coeff_vector_high);
152
        (clmul, masked)
153
    };
154
155
    state.value = ops.xor_vectors(clmul, masked);
156
}
157
158
/// Barrett reduction for 32-bit-space CRC operations
159
/// Returns the full u64 result; caller extracts appropriate bits
160
#[inline(always)]
161
pub unsafe fn barrett_reduction<T: ArchOps>(
162
    state: &CrcState<T::Vector>,
163
    poly: u64,
164
    mu: u64,
165
    ops: &T,
166
) -> [u64; 2]
167
where
168
    T::Vector: Copy,
169
{
170
    let x = state.value;
171
    let mu_poly = ops.create_vector_from_u64_pair_non_reflected(poly, mu);
172
173
    if state.reflected {
174
        let clmul1 = ops.carryless_mul_00(x, mu_poly);
175
        let clmul2 = ops.carryless_mul_10(clmul1, mu_poly);
176
        let xorred = ops.xor_vectors(x, clmul2);
177
        ops.extract_u64s(xorred)
178
    } else {
179
        let clmul1 = ops.shift_left_4(ops.carryless_mul_01(x, mu_poly));
180
        let clmul2_shifted = ops.shift_left_4(ops.carryless_mul_11(clmul1, mu_poly));
181
        let final_xor = ops.xor_vectors(clmul2_shifted, x);
182
        ops.extract_u64s(final_xor)
183
    }
184
}
185
186
/// Create coefficient vector for 32-bit-space CRC operations
187
#[inline(always)]
188
pub unsafe fn create_coefficient<T: ArchOps>(
189
    high: u64,
190
    low: u64,
191
    ops: &T,
192
) -> T::Vector
193
where
194
    T::Vector: Copy,
195
{
196
    ops.create_vector_from_u64_pair_non_reflected(high, low)
197
}
198
199
/// Get shuffle table pointer for 32-bit-space CRC operations
200
#[inline(always)]
201
pub fn get_last_bytes_table_ptr(reflected: bool, remaining_len: usize) -> (*const u8, usize) {
202
    if reflected {
203
        let base_ptr = &PSHUFB_SHF_TABLE_REVERSE as *const _ as *const u8;
204
        (base_ptr, remaining_len)
205
    } else {
206
        let base_ptr = &PSHUFB_SHF_TABLE_FORWARD as *const _ as *const u8;
207
        (base_ptr, 16 - remaining_len)
208
    }
209
}
210
211
/// Process inputs smaller than 16 bytes for 32-bit-space CRC operations
212
#[inline]
213
#[cfg_attr(
214
    any(target_arch = "x86", target_arch = "x86_64"),
215
    target_feature(enable = "ssse3,sse4.1,pclmulqdq")
216
)]
217
#[cfg_attr(target_arch = "aarch64", target_feature(enable = "aes"))]
218
pub unsafe fn process_0_to_15<T: ArchOps, W: EnhancedCrcWidth>(
219
    data: &[u8],
220
    state: &mut CrcState<T::Vector>,
221
    reflector: &Reflector<T::Vector>,
222
    keys: [u64; 23],
223
    ops: &T,
224
) -> W::Value
225
where
226
    T::Vector: Copy,
227
{
228
    // Implementation shared by CRC-16 and CRC-32
229
    // ... (full implementation)
230
}
231
```
232
233
### 2. Updated `src/crc16/algorithm.rs`
234
235
The Width16 implementation delegates to shared operations:
236
237
```rust
238
impl EnhancedCrcWidth for Width16 {
239
    #[inline(always)]
240
    fn load_constants(reflected: bool) -> [[u64; 2]; 4] {
241
        crate::crc32::width32_ops::load_constants(reflected)
242
    }
243
244
    #[inline(always)]
245
    unsafe fn fold_16<T: ArchOps>(...) {
246
        crate::crc32::width32_ops::fold_16(state, coeff, data_to_xor, ops)
247
    }
248
249
    #[inline(always)]
250
    unsafe fn barrett_reduction<T: ArchOps>(...) -> Self::Value {
251
        let u64s = crate::crc32::width32_ops::barrett_reduction(state, poly, mu, ops);
252
        // Extract 16-bit result
253
        if state.reflected {
254
            u64s[1] as u16
255
        } else {
256
            ((u64s[0] >> 32) >> 16) as u16
257
        }
258
    }
259
    
260
    // ... other delegating methods
261
}
262
263
// process_0_to_15 delegates to shared implementation
264
pub(crate) unsafe fn process_0_to_15<T: ArchOps, W: EnhancedCrcWidth>(...) -> W::Value {
265
    crate::crc32::width32_ops::process_0_to_15::<T, W>(data, state, reflector, keys, ops)
266
}
267
```
268
269
### 3. Updated `src/crc32/algorithm.rs`
270
271
The Width32 implementation also delegates to shared operations:
272
273
```rust
274
impl EnhancedCrcWidth for Width32 {
275
    #[inline(always)]
276
    fn load_constants(reflected: bool) -> [[u64; 2]; 4] {
277
        crate::crc32::width32_ops::load_constants(reflected)
278
    }
279
280
    #[inline(always)]
281
    unsafe fn barrett_reduction<T: ArchOps>(...) -> Self::Value {
282
        let u64s = crate::crc32::width32_ops::barrett_reduction(state, poly, mu, ops);
283
        // Extract 32-bit result
284
        if state.reflected {
285
            u64s[1] as u32
286
        } else {
287
            (u64s[0] >> 32) as u32
288
        }
289
    }
290
    
291
    // ... other delegating methods
292
}
293
294
// process_0_to_15 delegates to shared implementation
295
pub(crate) unsafe fn process_0_to_15<T: ArchOps, W: EnhancedCrcWidth>(...) -> W::Value {
296
    crate::crc32::width32_ops::process_0_to_15::<T, W>(data, state, reflector, keys, ops)
297
}
298
```
299
300
### 4. Updated `src/crc32/mod.rs`
301
302
Export the new module:
303
304
```rust
305
pub mod algorithm;
306
pub mod consts;
307
pub(crate) mod width32_ops;  // NEW
308
```
309
310
## Data Models
311
312
No changes to data models. The refactoring only affects internal implementation.
313
314
## Correctness Properties
315
316
*A property is a characteristic or behavior that should hold true across all valid executions of a system.*
317
318
### Property 1: CRC-16 Computation Unchanged
319
320
*For any* input byte sequence and any CRC-16 parameters, the computed checksum after refactoring SHALL equal the checksum computed before refactoring.
321
322
**Validates: Requirements 4.1**
323
324
### Property 2: CRC-32 Computation Unchanged
325
326
*For any* input byte sequence and any CRC-32 parameters, the computed checksum after refactoring SHALL equal the checksum computed before refactoring.
327
328
**Validates: Requirements 4.2**
329
330
### Property 3: CRC-64 Computation Unchanged
331
332
*For any* input byte sequence and any CRC-64 parameters, the computed checksum after refactoring SHALL equal the checksum computed before refactoring.
333
334
**Validates: Requirements 4.3**
335
336
## Error Handling
337
338
No changes to error handling. The refactoring is purely internal.
339
340
## Testing Strategy
341
342
### Existing Tests
343
344
All existing tests serve as regression tests:
345
- CRC-16 check value tests (0x906E, 0xD0DB)
346
- CRC-32 check value tests
347
- CRC-64 check value tests
348
- Property-based tests comparing against `crc` crate
349
- Length-based tests for various input sizes
350
351
### Verification Approach
352
353
1. Run `cargo test` before refactoring to establish baseline
354
2. Perform refactoring
355
3. Run `cargo test` after refactoring to verify no regressions
356
4. Run `cargo fmt --check` and `cargo clippy -- -D warnings`
357
358
No new tests are needed since this is a pure refactoring with no behavior changes.