title: Recreating a C CRC32 algorithm in Python with crcmod
body: <p>I'm attempting to decode a Novatel GPS stream in Python, and I have all of the components for the sync, header, and payload sorted, but I cannot replicate the CRC32 used as part of the messages. The algorithm used to generate the CRC appended on the message is written in c as follows:</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;string&gt;
  
  using namespace std;
  
  #define CRC32_POLYNOMIAL 0xEDB88320L
  //#define CRC32_POLYNOMIAL 0x04C11DB7L
  
  unsigned long CRC32Value(int i)
  {
      int j;
      unsigned long ulCRC;
      ulCRC = i;
      for (j = 8; j &gt; 0; j--)
      {
          if (ulCRC &amp; 1)
              ulCRC = (ulCRC &gt;&gt; 1) ^ CRC32_POLYNOMIAL;
          else
              ulCRC &gt;&gt;= 1;
      }
      return ulCRC;
  }
  unsigned long CalculateBlockCRC32(
      unsigned long ulCount,
      unsigned char *ucBuffer)
  {
      unsigned long ulTemp1;
      unsigned long ulTemp2;
      unsigned long ulCRC = 0;
      while (ulCount-- != 0)
      {
          ulTemp1 = (ulCRC &gt;&gt; 8) &amp; 0x00FFFFFFL;
          ulTemp2 = CRC32Value(((int)ulCRC ^ *ucBuffer++ ) &amp; 0xff );
          ulCRC = ulTemp1 ^ ulTemp2;
      }
      return(ulCRC);
  }
  
  int main()
  {
      unsigned char buffer[] = {0xaa, 0x44, 0x12, 0x1c, 0x2a, 0x00, 0x02, 0x20, 0x48, 0x00, 0x00, 0x00, 0x90, 0xb4, 0x93, 0x05, 0xb0, 0xab, 0xb9, 0x12, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xbc, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1b, 0x04, 0x50, 0xb3, 0xf2, 0x8e, 0x49, 0x40, 0x16, 0xfa, 0x6b, 0xbe, 0x7c, 0x82, 0x5c, 0xc0, 0x00, 0x60, 0x76, 0x9f, 0x44, 0x9f, 0x90, 0x40, 0xa6, 0x2a, 0x82, 0xc1, 0x3d, 0x00, 0x00, 0x00, 0x12, 0x5a, 0xcb, 0x3f, 0xcd, 0x9e, 0x98, 0x3f, 0xdb, 0x66, 0x40, 0x40, 0x00, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03};
  
      unsigned long crc = CalculateBlockCRC32(sizeof(buffer), buffer);
      cout &lt;&lt; hex &lt;&lt; crc &lt;&lt; endl;
  }
  </code></pre>
  
  <p>The result of this is 0x42, 0xdc, 0x4c, 0x48 - which matches the example given in the manual, so that's a nice start.</p>
  
  <p>Whilst I could potentially use this algorithm in the code I am writing I would prefer to remain in Python where possible, so at this point I feel I have two options. I can either translate this into Python myself or hope that there is a built-in Python function or module capable of doing this for me, which is what I have been looking at doing. So far I have found three functions/modules:</p>
  
  <ul>
  <li>binascii.crc32</li>
  <li>zlib.crc32</li>
  <li>crcmod module</li>
  </ul>
  
  <p>Of these the top two give the same incorrect result and I cannot tell any way of changing settings or specifying arguments which might influence this positively. </p>
  
  <p>crcmod on the other hand has a plethora of settings and predefined functions which I think should be able to do what I am looking for. The format to create the CRC function is as follows:</p>
  
  <pre><code>crcmod.mkCrcFun(poly[, initCrc, rev, xorOut])
  </code></pre>
  
  <p>Of of the crucial things I found was there are predefined CRC functions, and the CRC32 version of this matches the results from binascii and zlib:</p>
  
  <pre><code>Name    Polynomial  Reversed?   Init-value  XOR-out Check
  crc-32  0x104C11DB7 True    0x00000000  0xFFFFFFFF  0xCBF43926
  </code></pre>
  
  <p>So at least that helps me understand where the zlib and binascii variants are coming from in terms of the polynomial used. </p>
  
  <p>I'm convinced that I should therefore be able to generate the same result as the C algorithm using this function, but not being well-versed in C I'm not sure how I do this. The polynomial used in the C algorithm is a reversed representation of the polynomial, so this implies that the settings above should work, but they don't generate the answer above as per the C code.</p>
  
  <p>What am I looking for to determine these settings, is there a module/function which will do this that I haven't seen, or is this not going to work and I should instead just start translating that C into Python myself?</p>