{"id":24418703,"url":"https://github.com/littlefs-project/ramcrc32bd","last_synced_at":"2025-04-12T06:05:10.996Z","repository":{"id":258725337,"uuid":"869618496","full_name":"littlefs-project/ramcrc32bd","owner":"littlefs-project","description":"An example of a CRC-32 based error-correcting block device backed by RAM","archived":false,"fork":false,"pushed_at":"2024-10-31T18:02:49.000Z","size":122,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-12T06:04:15.397Z","etag":null,"topics":["embedded","filesystem","microcontroller"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/littlefs-project.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-08T15:45:04.000Z","updated_at":"2025-03-20T16:45:24.000Z","dependencies_parsed_at":"2024-10-26T03:58:53.731Z","dependency_job_id":"b97d6775-a044-4f6e-ab47-7991640a2fab","html_url":"https://github.com/littlefs-project/ramcrc32bd","commit_stats":null,"previous_names":["geky/ramcrc32bd","littlefs-project/ramcrc32bd"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littlefs-project%2Framcrc32bd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littlefs-project%2Framcrc32bd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littlefs-project%2Framcrc32bd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littlefs-project%2Framcrc32bd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/littlefs-project","download_url":"https://codeload.github.com/littlefs-project/ramcrc32bd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248525144,"owners_count":21118618,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["embedded","filesystem","microcontroller"],"created_at":"2025-01-20T09:12:16.209Z","updated_at":"2025-04-12T06:05:10.966Z","avatar_url":"https://github.com/littlefs-project.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"## ramcrc32bd\n\nAn example of a CRC-32 based error-correcting block device backed by RAM.\n\n```\ncorrupted:\n        '         ..:::::::::::.:.                  .:::....:::.. :.'  ''::..:':: '.:.::'.: '':.\n               .:::::::::::::::::::..           .   ::'::::::::...:::.: :'.'::: .' ..:.: :.'  '.\n            '.::::::::::::::::::::::::.          '  ::::::::::' . .' ': .  :'' . ': .: :. ..:::\n           .:::::::::::::::::::::::::::.    .    . ::::':::::   ' . ''.:. ..:. : ::.':.'::. ....\n   .      .::::::::::::::::::::::::::::::    ... :: :'::::::'    :.:....:..:  .  .   ' '':.:   :\n          :::::::::::::::::::::::::.:::'' .. '::: '     '''     :..'::'.'''.:'. :''::. ' '  .'..\n         ::::::::::::'::::::::::::::''..:::::''                 : .'' ::'. : .:'.''  .'' ' .. ..\n         :::::::::::::::::::::::'' ..:::::''                  . ''' :'.: :'.:. :': .':'..': :.'.\n         :::::':::::::::::::'' ..:::::'' .'                    '' .::.   . . :: .''::'.  '.. ...\n     ..:'::::::::::::::''' ..:::::'' ...::                      '' ::..':' :'  .....:'' :'.  ::.\n  . :::'  :::::::::'  ..::::::': ..:::::::        .              '' .::  :. '.: .''': :: .:.'' :\n :::'     ':::'' ...:.::::':...::::::::::                       ': :.:':: ..: .'' : ::..: .'' :\n::'         ...::::::'' ..:::::':':::::'               '      . . .:' :  ''':':'.:..' :'::':.'':\n     ....::::::::' . ::::::::::.::::::'     .                   ::.: :' . '.:. .. .' ...'.:':.'\n'::::::::'''    :::::::::::::::::::''    '                      . :: ::' :' ':' .'...'':  ' ':':\n                  '':::::::::::''' .   .       '          '     ::::. '.'. :::   . . '.' '  '..'\n```\n\n```\ncorrected:\n                  ..:::::::::::...                  .:::....:::.. :.'  '':: .:::: '.:.:::.: '':.\n               .:::::::::::::::::::..               ::::::::::::..:::.: :'.':': .' ..:.: :.'  '.\n             .::::::::::::::::::::::::.             ::::::::::' . .' ': .  :'' . ': .: :. ..:::\n           .:::::::::::::::::::::::::::.         . ::::::::::   ' . ''.:. ..:. : ::.':.'::. ....\n          .::::::::::::::::::::::::::::::    ... :: :'::::::'    :.:....:..:  .  .   ' '':.:   :\n          :::::::::::::::::::::::::::::'' .. '::: '     '''     :..'::'.'''.:'..:''::. ' '  .'..\n         :::::::::::::::::::::::::::''..::::: '                 : .'' ::'. : .::.''  .'' ' .. ..\n         :::::::::::::::::::::::'' ..:::::''                    ''' :'.: ''.:. :': :':'..': :.'.\n         :::::::::::::::::::'' ..:::::'' .                      ' .::.   . . :: .''::'.  '.. ...\n     ..: ::::::::::::::''' ..:::::'' ..:::                      '' ::..':' :'  .....:'' :'.  ::.\n  ..:::'  :::::::::'' ..::::::'' ..:::::::                       '' .::  :. '.: .''': :: .:.'' :\n :::'     ':::'' ...::::::''...::::::::::                       ': ' :':: ..: .'' : ::..: .'' :\n::'         ...::::::'' ..:::::::::::::'                        . .:' :  ''':':'.:..' :'::':.'':\n     ....:::::::'' ..:::::::::::::::::'                         ::.: :' . '.:. .. .' ...'.:':.'\n'::::::::'''    :::::::::::::::::::''                           . :: ::' :' ':' .'...'':  ' ':':\n                  '':::::::::::'''                              :::'. '.'. :::   . . '.' '  '..'\n```\n\nOften overlooked, the humble [CRC][w-crc] can already provide a simple\nform of error detection and correction, capable of repairing a handful of\nbit-errors.\n\nAssuming a Hamming distance `HD` for a given codeword size, ramcrc32bd\ncan correct up to `floor((HD-1)/2)` bit errors. In its current\nconfiguration, ramcrc32bd can correct:\n\n- 1 bit error up to ~512 KiB codewords  (HD=3 up to 4294967263 bits)\n- 2 bit errors up to 371 byte codewords (HD=5 up to 2974 bits)\n- 3 bit errors up to 21 byte codewords  (HD=7 up to 171 bits)\n\nIt does scale poorly, $O(n^e)$, but if you're only worried about the\noccasional one or two bit errors, it may be sufficient. It's hard to\nbeat the simplicity, low-cost, and hardware availability of CRCs.\n\nThis block device uses littlefs's CRC-32, since we assume it's already\navailable. But the same idea can be extended to any other CRC, as long\nas it has a sufficient [Hamming distance](#hamming-distance) for the\ndesired codeword size.\n\nA quick comparison of current ram-ecc-bds:\n\n|            | code   | tables | stack | buffers  | runtime                  |\n|:-----------|-------:|-------:|------:|---------:|-------------------------:|\n| ramcrc32bd |  940 B |   64 B |  88 B |      0 B |      $O\\left(n^e\\right)$ |\n| ramrsbd    | 1506 B |  512 B | 128 B | n + 4e B | $O\\left(ne + e^2\\right)$ |\n\nSee also:\n\n- [littlefs][littlefs]\n- [ramrsbd][ramrsbd]\n\n## RAM?\n\nRight now, [littlefs's][littlefs] block device API is limited in terms of\ncomposability. While it would be great to fix this on a major API change,\nin the meantime, a RAM-backed block device provides a simple example of\nerror-correction that users may be able to reimplement in their own\nblock devices.\n\n## Testing\n\nTesting is a bit jank right now, relying on littlefs's test runner:\n\n``` bash\n$ git clone https://github.com/littlefs-project/littlefs -b v2.9.3 --depth 1\n$ make test -j\n```\n\n## How it works\n\nFirst, a quick primer on [CRCs][w-crc].\n\nSome of why CRCs are so prevalent because they are mathematically quite\npure. You view your message as a big [binary polynomial][w-polynomial-ring],\ndivide it by a predetermined \"generator polynomial\" (choosing a good\npolynomial is the hard part), and the remainder is your CRC:\n\n```\nmessage = \"hi!\":\n    = 01101000 01101001 00100001\n\npolynomial = 0x107:\n    = 1 00000111\n\nbinary division:\n    = 01101000 01101001 00100001 00000000\n    ^  1000001 11\n    = 00101001 10101001 00100001 00000000\n    ^   100000 111\n    = 00001001 01001001 00100001 00000000\n    ^     1000 00111\n    = 00000001 01110001 00100001 00000000\n    ^        1 00000111\n    = 00000000 01110110 00100001 00000000\n    ^           1000001 11\n    = 00000000 00110111 11100001 00000000\n    ^            100000 111\n    = 00000000 00010111 00000001 00000000\n    ^             10000 0111\n    = 00000000 00000111 01110001 00000000\n    ^               100 000111\n    = 00000000 00000011 01101101 00000000\n    ^                10 0000111\n    = 00000000 00000001 01100011 00000000\n    ^                 1 00000111\n    = 00000000 00000000 01100100 00000000\n    ^                    1000001 11\n    = 00000000 00000000 00100101 11000000\n    ^                     100000 111\n    = 00000000 00000000 00000101 00100000\n    ^                        100 000111\n    = 00000000 00000000 00000001 00111100\n    ^                          1 00000111\n    -------------------------------------\n    = 00000000 00000000 00000000 00111011\n                                 '--.---'\n        .---------------------------'\n        v\ncrc = 0x3b\n```\n\nYou can describe this mathematically in [GF(2)][w-gf2], but depending on\nyour experience with GF(2) and other finite-fields, the above example may\nbe easier to understand:\n\n\u003cp align=\"center\"\u003e\n\u003cimg\n    alt=\"C(x) = M(x) x^{|P|} - \\left(M(x) x^{|P|} \\bmod P(x)\\right)\"\n    src=\"https://latex.codecogs.com/svg.image?C%28x%29%20%3d%20M%28x%29%20x%5e%7b%7cP%7c%7d%20%2d%20%5cleft%28M%28x%29%20x%5e%7b%7cP%7c%7d%20%5cbmod%20P%28x%29%5cright%29\"\n\u003e\n\u003c/p\u003e\n\nThe extra $x^{|P|}$ multiplications represent shifting the message to\nmake space for the CRC, and gives us what's called a\n[\"systematic code\"][w-systematic-code]. Alternatively we could actually\nmultiply the message with our polynomial to get valid codewords, but that\nwould just make interacting with the message more annoying without much\nbenefit...\n\nThe neat thing is that this remainder operation does a real good job of\nmixing up all the bits. So if you choose a good CRC polynomial, it's very\nunlikely a message with a bit-error will result in the same CRC:\n\n```\na couple 1-bit errors:\n    = 01101010 01101001 00100001 00000000 =\u003e 11101101 (0xed != 0x3b)\n    = 01101000 01101000 00100001 00000000 =\u003e 00101110 (0x2e != 0x3b)\n    = 01101000 01101001 01100001 00000000 =\u003e 11111100 (0xfc != 0x3b)\n    = 01101000 01101001 00100001 00001000 =\u003e 00110011 (0x33 != 0x3b)\n```\n\n### Hamming distance\n\nHow unlikely? Well thanks to [Philip Koopman's exhaustive CRC work][koopman-crc],\nwe know exactly how many bit-errors we need to see a collision for a\ngiven CRC polynomial and message size. This is called the\n[Hamming distance][w-hd], and is a very useful metric for an\nerror-correcting code.\n\nKoopman's [NOTES page][koopman-notes] may be the best starting point for\ninterpreting these results. They're dense but an amazing resource!\n\nFor this 8-bit CRC, [p=0x107][koopman-p=0x107], Philip Koopman's work\nshows a Hamming distance of 4 up to a message size of\n119 bits (14 bytes), which means our 3-byte message should have no\ncollisions up until 4 bit-errors:\n\n```\na 4-bit collision:\n    = 01101000 01101000 00100110 00000000 =\u003e 00111011 (0x3b == 0x3b)\n```\n\nBut the interesting thing about Hamming distance is that it's, well, a\ndistance.\n\nA Hamming distance of 4 means that there are at least 3 invalid codewords\nbetween every valid codeword:\n\n```\n                      Hamming distance = 4\n.-----------------------------'-----------------------------.\n\no \u003c-bit-flip-\u003e x \u003c-bit-flip-\u003e x \u003c-bit-flip-\u003e x \u003c-bit-flip-\u003e o\n^              '--------------.--------------'              ^\n|                             |                             |\nvalid codeword         invalid codewords       valid codeword\n```\n\nIf we assume our message has a single bit-error, it will be 1 bit-flip\naway from the original codeword, and at least 3 bit-flips away from any\nother codeword. It's not until we have 2 bit-errors that the original\ncodeword becomes ambiguous.\n\nBut this is only an 8-bit CRC. With more bits, we can usually find a\nbetter CRC. littlefs's 32-bit CRC, [p=0x104c11db7][koopman-p=0x104c11db7],\nfor example, has a Hamming distance of 7 up to 171 bits (21 bytes), which\nmeans for any message $\\le$ 21 bytes we can reliably correct up to\n3 bit-errors.\n\nIn general the number of bits we we can reliably correct is\n$\\left\\lfloor\\frac{\\text{HD}-1}{2}\\right\\rfloor$.\n\n### There's always brute force\n\nOk, but that's enough about theory. How do actually correct these\nbit-errors?\n\nThe simple/naive/cheap answer is brute force. Try every bit-flip until we\nfind a matching CRC. Since we know our Hamming distance is $\\ge$ 3, this\nshould only ever find one valid codeword, the original codeword:\n\n```\nbrute force search:\n    = 01101000 01101001 01100001 00000000 =\u003e 11111100 (0xfc != 0x3b)\n    ^ 1                                   =\u003e 11110111 (0xf7 != 0x3b)\n    ^  1                                  =\u003e 01111010 (0x7a != 0x3b)\n    ^   1                                 =\u003e 10111111 (0xbf != 0x3b)\n    ^    1                                =\u003e 01011110 (0x5e != 0x3b)\n    ^     1                               =\u003e 10101101 (0xad != 0x3b)\n    ^      1                              =\u003e 01010111 (0x57 != 0x3b)\n    ^       1                             =\u003e 00101010 (0x2a != 0x3b)\n    ^        1                            =\u003e 10010111 (0x97 != 0x3b)\n    ^          1                          =\u003e 01001010 (0x4a != 0x3b)\n    ^           1                         =\u003e 10100111 (0xa7 != 0x3b)\n    ^            1                        =\u003e 01010010 (0x52 != 0x3b)\n    ^             1                       =\u003e 10101011 (0xab != 0x3b)\n    ^              1                      =\u003e 01010100 (0x54 != 0x3b)\n    ^               1                     =\u003e 10101000 (0xa8 != 0x3b)\n    ^                1                    =\u003e 11010110 (0xd6 != 0x3b)\n    ^                 1                   =\u003e 11101001 (0xe9 != 0x3b)\n    ^                   1                 =\u003e 01110101 (0x75 != 0x3b)\n    ^                    1                =\u003e 00111011 (0x3b == 0x3b) !!! found our bit-error\n\ncorrected message:\n    = 01101000 01101001 00100001 00000000 =\u003e 00111011 (0x3b == 0x3b)\n```\n\nIf we don't find a valid codeword, we must have had at least 2\nbit-errors, making our original codeword unrecoverable.\n\nThis idea can be extended to CRCs with larger Hamming distances by brute\nforce searching multiple bit-errors with nested loops. See\n`ramcrc32bd_read` for an example of up to 3 bit-errors with littlefs's\nCRC-32.\n\n## Tricks\n\nThere are a couple implementation tricks worth noting in ramcrc32bd:\n\n1. Try the faster solutions first.\n\n   Correcting 1 bit-error $O(n)$, is much faster than correcting\n   2 bit-errors $O(n^2)$, and 1 bit-errors are also much more common. It\n   makes sense to only search for more bit-errors when a solution with\n   fewer bit-errors can't be found.\n\n   By trying fewer bit-errors first, ramcrc32bd should return quickly in\n   the common case of few/no bit-errors.\n\n   Though this does risk degraded performance over time as bit-errors\n   develop.\n\n2. We don't actually need to permute the message to try every bit-flip.\n\n   First note that since CRCs are a glorified remainder operation,\n   shifting a message (multiplying by $x$ in GF(2)) and then calculating\n   the CRC is equivalent to shifting the CRC and then calculating the\n   remainder:\n\n   ```\n   crc(a \u003c\u003c 1):\n       = 00111001 10110100 00110110 00000000 =\u003e 01000010 (0x42)\n       s 01110011 01101000 01101100 00000000 =\u003e 10000100 (0x84)\n       s 11100110 11010000 11011000 00000000 =\u003e 00001111 (0x0f)\n\n   (crc(a) \u003c\u003c 1) % p:\n       = 00111001 10110100 00110110 00000000 =\u003e     01000010 (0x42)\n                                                s 0 10000100\n                                                ^ 0 00000000\n                                                =   10000100 (0x84)\n                                                s 1 00001000\n                                                ^ 1 00000111\n                                                =   00001111 (0x0f)\n   ```\n\n   We can use this to quickly iterate through all CRCs that represent a\n   single bit:\n\n   ```\n   a = (a \u003c\u003c 1) % p:\n       =                            00000001 =\u003e 00000001 (0x01)\n       s                            00000010 =\u003e 00000010 (0x02)\n       s                            00000100 =\u003e 00000100 (0x04)\n       s                            00001000 =\u003e 00001000 (0x08)\n       s                            00010000 =\u003e 00010000 (0x10)\n       s                            00100000 =\u003e 00100000 (0x20)\n       s                            01000000 =\u003e 01000000 (0x40)\n       s                            10000000 =\u003e 10000000 (0x80)\n       s                         (1)00000000 =\u003e 00001110 (0x0e)\n       s                        (1) 00000000 =\u003e 00011100 (0x1c)\n       s                       (1)  00000000 =\u003e 00111000 (0x38)\n       s                      (1)   00000000 =\u003e 01110000 (0x70)\n       s                     (1)    00000000 =\u003e 11100000 (0xe0)\n       s                    (1)     00000000 =\u003e 11000111 (0xc7)\n       s                   (1)      00000000 =\u003e 10001001 (0x89)\n       s                  (1)       00000000 =\u003e 00010101 (0x15)\n   ```\n\n   Combining this with the fact that CRCs are linear, i.e. the CRC of the\n   xor of two messages (addition in GF(2)) is equivalent to the xor of\n   two CRCs:\n\n   ```\n   crc(a ^ b):\n       = 01100001 01100100 01100100 00000000\n       ^ 01111000 01101111 01110010 00000000\n       = 00011001 00001011 00010110 00000000 =\u003e 01101101 (0x6d)\n\n   crc(a) ^ crc(b):\n       = 01100001 01100100 01100100 00000000 =\u003e   00110100 (0x34)\n       ^ 01111000 01101111 01110010 00000000 =\u003e ^ 01011001 (0x59)\n                                                = 01101101 (0x6d)\n   ```\n\n   And we can quickly test the affect of every possible bit-flip by\n   shifting a single register per simulated bit-flip and xoring it\n   into our original CRC:\n\n   ```\n   fancy brute force search:\n       = 01101000 01101001 01100001 00000000 =\u003e 11111100 (0xfc != 0x3b)\n       ^                            00000001 =\u003e 11111101 (0xfd != 0x3b)\n       ^                            00000010 =\u003e 11111110 (0xfe != 0x3b)\n       ^                            00000100 =\u003e 11111000 (0xf8 != 0x3b)\n       ^                            00001000 =\u003e 11110100 (0xf4 != 0x3b)\n       ^                            00010000 =\u003e 11101100 (0xec != 0x3b)\n       ^                            00100000 =\u003e 11011100 (0xdc != 0x3b)\n       ^                            01000000 =\u003e 10111100 (0xbc != 0x3b)\n       ^                            10000000 =\u003e 01111100 (0x7c != 0x3b)\n       ^                         (1)00000111 =\u003e 11111011 (0xfb != 0x3b)\n       ^                        (1) 00001110 =\u003e 11110010 (0xf2 != 0x3b)\n       ^                       (1)  00011100 =\u003e 11100000 (0xe0 != 0x3b)\n       ^                      (1)   00111000 =\u003e 11000100 (0xc4 != 0x3b)\n       ^                     (1)    01110000 =\u003e 10001100 (0x8c != 0x3b)\n       ^                    (1)     11100000 =\u003e 00011100 (0x1c != 0x3b)\n       ^                   (1)      11000111 =\u003e 00111011 (0x3b == 0x3b) !!! found our bit-error\n\n   corrected message:\n       = 01101000 01101001 00100001 00000000 =\u003e 00111011 (0x3b == 0x3b)\n   ```\n\n   The end result is still $O(n^e)$, but limited only by your CPU's\n   shift, xor, and branching hardware. No memory accesses required.\n\n   See `ramcrc32bd_read` for an implementation of this.\n\n## Caveats\n\nAnd some caveats:\n\n1. For any error-correcting code, attempting to **correct** errors\n   reduces the code's ability to **detect** errors.\n\n   In the HD=4 example, we assumed 1 bit-error. If we were wrong and\n   there were actually 3 bit-errors, we would have \"corrected\" to the\n   wrong codeword.\n\n   In practice this isn't that big of a problem. Fewer bit-errors are\n   usually more common, and correcting bit-errors is usually more useful.\n   At 4 bit-errors you're going to end up with full collisions anyways.\n\n   Still, it's good to be aware of this tradeoff.\n\n   ramcrc32bd's `error_correction` config option lets you control exactly\n   how many bit-errors to attempt to repair in case better detection is\n   more useful.\n\n2. Brute force doesn't really scale.\n\n   The error-correction implemented here grows $O(n^e)$ for $e$\n   bit-errors, which really isn't great.\n\n   That being said, larger CRC Hamming distances are also pretty limited\n   in terms of message size, so this performance may be excusable if\n   messages are small and bit-errors are rare.\n\n   ramcrc32bd's `error_correction` config option can also help here by\n   limiting how many bit-errors we attempt to repair. If you set\n   `error_correction=1`, for example, the runtime reduces to $O(n)$ worst\n   case, which is roughly the same runtime it takes to read the data from\n   the underlying storage.\n\n   But if you need a performant error-correcting block device, consider\n   ramcrc32bd's big brother, [ramrsbd][ramrsbd], which brings the\n   decoding cost down to $O(ne + e^2)$.\n\n## References\n\n- [Koopman, P. - CRC Polynomial Zoo][koopman-crc]\n- [Koopman, P. - CRC Polynomial Zoo NOTES][koopman-notes]\n\n- [Wikipedia - Cyclic Redundancy Check (CRC)][w-crc]\n- [Wikipedia - Hamming Distance (HD)][w-hd]\n- [Wikipedia - Polynomial Ring][w-polynomial-ring]\n- [Wikipedia - GF(2)][w-gf2]\n- [Wikipedia - Systematic Code][w-systematic-code]\n\n[w-crc]: https://en.wikipedia.org/wiki/Cyclic_redundancy_check\n[w-hd]: https://en.wikipedia.org/wiki/Hamming_distance\n[w-polynomial-ring]: https://en.wikipedia.org/wiki/Polynomial_ring\n[w-gf2]: https://en.wikipedia.org/wiki/GF(2)\n[w-systematic-code]: https://en.wikipedia.org/wiki/Systematic_code\n\n[koopman-crc]: https://users.ece.cmu.edu/~koopman/crc\n[koopman-notes]: https://users.ece.cmu.edu/~koopman/crc/notes.html\n[koopman-p=0x107]: https://users.ece.cmu.edu/~koopman/crc/c08/0x83_len.txt\n[koopman-p=0x104c11db7]: https://users.ece.cmu.edu/~koopman/crc/c32/0x82608edb_len.txt\n\n[littlefs]: https://github.com/littlefs-project/littlefs\n[ramrsbd]: https://github.com/geky/ramrsbd\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flittlefs-project%2Framcrc32bd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flittlefs-project%2Framcrc32bd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flittlefs-project%2Framcrc32bd/lists"}