@@ -240,7 +240,7 @@ brute force search:
240240 ^ 1 => 11101001 (0xe9 != 0x3b)
241241 ^ 1 => 01110101 (0x75 != 0x3b)
242242 ^ 1 => 00111011 (0x3b == 0x3b) !!! found our bit-error
243- ^- note no CRC repeats
243+
244244corrected message:
245245 = 01101000 01101001 00100001 00000000 => 00111011 (0x3b == 0x3b)
246246```
@@ -264,83 +264,103 @@ There are a couple implementation tricks worth noting in ramcrc32bd:
264264 makes sense to only search for more bit-errors when a solution with
265265 fewer bit-errors can't be found.
266266
267- This means ramcrc32bd should read quite quickly in the common case of
268- few/none bit-errors. Though this does risk reads sort of slowing down
269- as bit-errors develop.
267+ By trying fewer bit-errors first, ramcrc32bd should return quickly in
268+ the common case of few/no bit-errors.
270269
271- 2 . We don't actually need to permute the message for every bit-flip.
270+ Though this does risk degraded performance over time as bit-errors
271+ develop.
272272
273- CRCs are pretty nifty in that they're linear. The CRC of the xor
274- of two messages is equivalent to the xor of the two CRCS:
273+ 2 . We don't actually need to permute the message to try every bit-flip.
275274
276- ```
277- crc(a xor b):
278- = 01101000 01101001 01100001 00000000
279- ^ 1
280- -------------------------------------
281- = 01101000 01101001 00100001 00000000 => 00111011 (0x3b == 0x3b)
275+ First note that since CRCs are a glorified remainder operation,
276+ shifting a message (multiplying by $x$ in GF(2)) and then calculating
277+ the CRC is equivalent to shifting the CRC and then calculating the
278+ remainder:
282279
283- crc(a) xor crc(b):
284- = 01101000 01101001 01100001 00000000 => 11111100 (0xfc)
285- ^ 1 => ^ 11000111 (0xc7)
286- ----------
287- = 00111011 (0x3b == 0x3b)
280+ ```
281+ crc(a << 1):
282+ = 00111001 10110100 00110110 00000000 => 01000010 (0x42)
283+ s 01110011 01101000 01101100 00000000 => 10000100 (0x84)
284+ s 11100110 11010000 11011000 00000000 => 00001111 (0x0f)
285+
286+ (crc(a) << 1) % p:
287+ = 00111001 10110100 00110110 00000000 => 01000010 (0x42)
288+ s 0 10000100
289+ ^ 0 00000000
290+ = 10000100 (0x84)
291+ s 1 00001000
292+ ^ 1 00000111
293+ = 00001111 (0x0f)
288294 ```
289295
290- This means we can quickly check the effect of a bit-flip by xoring our
291- CRC with the CRC of the bit flip.
292-
293- If this wasn't convenient enough, shifting (multiplying by 2) is also
294- preserved over CRCs:
296+ We can use this to quickly iterate through all CRCs that represent a
297+ single bit:
295298
296299 ```
297- crc(a << 1):
298- = 1 => 11100000 (0xe0)
299- s 1 => 11000111 (0xc7)
300-
301- crc(crc(a) << 1):
302- = 1 => 11100000 (0xe0)
303- s 1 11000000
304- ^ 1 00000111
305- ------------
306- = 0 11000111 (0xc7)
300+ a = (a << 1) % p:
301+ = 00000001 => 00000001 (0x01)
302+ s 00000010 => 00000010 (0x02)
303+ s 00000100 => 00000100 (0x04)
304+ s 00001000 => 00001000 (0x08)
305+ s 00010000 => 00010000 (0x10)
306+ s 00100000 => 00100000 (0x20)
307+ s 01000000 => 01000000 (0x40)
308+ s 10000000 => 10000000 (0x80)
309+ s (1)00000000 => 00001110 (0x0e)
310+ s (1) 00000000 => 00011100 (0x1c)
311+ s (1) 00000000 => 00111000 (0x38)
312+ s (1) 00000000 => 01110000 (0x70)
313+ s (1) 00000000 => 11100000 (0xe0)
314+ s (1) 00000000 => 11000111 (0xc7)
315+ s (1) 00000000 => 10001001 (0x89)
316+ s (1) 00000000 => 00010101 (0x15)
307317 ```
308318
309- So testing every bit-flip requires only a single register that we
310- repeatedly shift and xor until we find a CRC match (or don't).
319+ Combining this with the fact that CRCs are linear, i.e. the CRC of the
320+ xor of two messages (addition in GF(2)) is equivalent to the xor of
321+ two CRCs:
311322
312- Once we find a match, we can use the number of shifts to figure out
313- which bit we needed to flip in the original message:
323+ ```
324+ crc(a ^ b):
325+ = 01100001 01100100 01100100 00000000
326+ ^ 00011001 00001011 00010110 00000000
327+ = 01111000 01101111 01110010 00000000 => 01011001 (0x59)
328+
329+ crc(a) ^ crc(b):
330+ = 01100001 01100100 01100100 00000000 => 00110100 (0x34)
331+ ^ 00011001 00001011 00010110 00000000 => ^ 01101101 (0x6d)
332+ = 01011001 (0x59)
333+ ```
334+
335+ And we can quickly test the affect of every possible bit-flip by
336+ shifting a single register per simulated bit-flip and xoring it
337+ into our original CRC:
314338
315339 ```
316340 fancy brute force search:
317341 = 01101000 01101001 01100001 00000000 => 11111100 (0xfc != 0x3b)
318- s 0 00000001 => 11111101 (0xfd != 0x3b)
319- s 0 00000010 => 11111110 (0xfe != 0x3b)
320- s 0 00000100 => 11111000 (0xf8 != 0x3b)
321- s 0 00001000 => 11110100 (0xf4 != 0x3b)
322- s 0 00010000 => 11101100 (0xec != 0x3b)
323- s 0 00100000 => 11011100 (0xdc != 0x3b)
324- s 0 01000000 => 10111100 (0xbc != 0x3b)
325- s 0 10000000 => 01111100 (0x7c != 0x3b)
326- s 1 00000000
327- ^ 1 00000111
328- = (1)00000111 => 11111011 (0xfb != 0x3b)
329- s (1) 00001110 => 11110010 (0xf2 != 0x3b)
330- s (1)0 00011100 => 11100000 (0xe0 != 0x3b)
331- s (1) 0 00111000 => 11000100 (0xc4 != 0x3b)
332- s (1) 0 01110000 => 10001100 (0x8c != 0x3b)
333- s (1) 0 11100000 => 00011100 (0x1c != 0x3b)
334- s 1 11000000
335- ^ 1 00000111
336- = (1) 0 11000111 => 00111011 (0x3b == 0x3b) !!! found our bit-error
337- ^- note no CRC repeats
342+ ^ 00000001 => 11111101 (0xfd != 0x3b)
343+ ^ 00000010 => 11111110 (0xfe != 0x3b)
344+ ^ 00000100 => 11111000 (0xf8 != 0x3b)
345+ ^ 00001000 => 11110100 (0xf4 != 0x3b)
346+ ^ 00010000 => 11101100 (0xec != 0x3b)
347+ ^ 00100000 => 11011100 (0xdc != 0x3b)
348+ ^ 01000000 => 10111100 (0xbc != 0x3b)
349+ ^ 10000000 => 01111100 (0x7c != 0x3b)
350+ ^ (1)00000111 => 11111011 (0xfb != 0x3b)
351+ ^ (1) 00001110 => 11110010 (0xf2 != 0x3b)
352+ ^ (1) 00011100 => 11100000 (0xe0 != 0x3b)
353+ ^ (1) 00111000 => 11000100 (0xc4 != 0x3b)
354+ ^ (1) 01110000 => 10001100 (0x8c != 0x3b)
355+ ^ (1) 11100000 => 00011100 (0x1c != 0x3b)
356+ ^ (1) 11000111 => 00111011 (0x3b == 0x3b) !!! found our bit-error
357+
338358 corrected message:
339359 = 01101000 01101001 00100001 00000000 => 00111011 (0x3b == 0x3b)
340360 ```
341361
342- Still $O(n^e)$, but limited only by your CPU's shift, xor, and
343- branching hardware. No memory accesses required.
362+ The end result is still $O(n^e)$, but limited only by your CPU's
363+ shift, xor, and branching hardware. No memory accesses required.
344364
345365 See [ ramcrc32bd_read] [ ramcrc32bd_read ] for an implementation of this.
346366
0 commit comments