Excerpts from Nathan Hartman's message of July 15, 2022 2:59 pm: > On Fri, Jul 15, 2022 at 8:10 AM Karel Kočí <cyn...@email.cz> wrote: >> >> Hi >> >> I hit an issue with crc32 implementation in NuttX's LibC and it took me some >> time to figure out that crc32 is implemented differently in NuttX than I was >> expecting. Let me explain... >> >> Common implementations are using same precomputed table as there is in the >> NuttX, but the initial value is all ones and not zero as in case of the NuttX >> (0xffffffff vs 0x0) and the result is negated while that is not true in the >> NuttX. >> In other words the call `crc32(msg, msgsiz)` gives "unexpected" result while >> `~crc32part(msg, msgsiz, 0xffffffff)` gives the "correct" one. >> >> I can see the idea behind not performing negation twice (`crc32part` would >> have >> to negate `crc32val` at the start and then return it negated again) but using >> the same precomputed table gives then different results. >> >> I am not sure if this weakens the crc32 in some way or just has no side >> effect >> except of not matching with common implementations. Either way this >> discrepancy >> should be at least documented with suggestion to use `~crc32part(msg, msgsiz, >> 0xffffffff)`. What do you think? >> >> With regards >> Karel Kočí > > > Hello, > > That is interesting. Which crc32 implementation are you comparing > against? (i.e., what do you mean by "common implementations"?) Well "common" I mean most of the implementations on the Internet (I know that there are load of variations) and used in our project (honestly just taken from the Internet). It also probably matches what for example others present on Wikipedia: https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm I do not think that the one implementation we are using is "the correct one" but it also seemed that NuttX implementation is not well defined either.
> The CRC RevEng project at SourceForge [1] helps identify CRC > algorithms. Each algorithm is listed with the value it should output > when input the string "123456789" (as 8-bit characters). That is new for mew. I had no idea that there is such project. Looking into it more in depth I for example looked into which CRC32 variant implements zlib and that one uses CRC-32/ISO-HDLC. It is not hard to find it this way. Thanks for pointing this out. > But, when I run our algorithm as you suggest, with an initial value of > 0xffffffff, I get 0x340bc6d9 which is listed as the "check=" value of > "CRC-32/JAMCRC" [3]. You might have missed the binary negation. The difference between those is just a simple negation as it seems. The code `~crc32part("123456789", 9, 0xffffffff)` gives me 0xcbf43926 which matches the ISO-HDLC. Without the negation it gives me the answer you have. It makes sense as the difference is only in the final XOR and xor with zero does nothing while xor with ones simply does negation. > Based on a quick lookup there, it appears to me that the crc32() > implementation in NuttX should be what CRC RevEng calls > "CRC-32/CKSUM": width=32 poly=0x04c11db7 init=0x00000000 refin=false > refout=false xorout=0xffffffff check=0x765e7680 residue=0xc704dd7b > name="CRC-32/CKSUM" [2]. > > However, when I run our algorithm against the input string > "123456789", I don't get the value 0x765e7680 as listed above; I get > 0x2dfd2d88, which isn't listed as the "check=" value of any of the > algorithms. So at minimum this should be stated in the function documentation. I also tried to look into why it does not match that CKSUM algorithm but I pretty much failed. I am trying to tweak my own version that does not use table but still I get the invalid value (0xd202d277 which is negation of what you have and because that algorithm specifies xorout with ones that is probably little bit more correct). The only other difference between CKSUM and ISO-HDCL I can see there is in parameters refin and refout. From RevEng website it seems that it specifies endianess for input and output. The refin=false refout=false is stated as big-endian but I am not sure if I should perform calculation in big endian (which would make no difference if implemented correctly) or if only some part should be in that endianess. Just to be sure I also ran the code on Mips (MSB) but that gave me the same result (expected that). Thus I am not sure what those parameters mean in the end. K.K.
pgpfVHa63vZ3f.pgp
Description: PGP signature