What parameters is golang crc32 using?

468 Views Asked by At

I have a crc32 polynomial:

poly=0xF4ACFB13
seed=0
xorout=0
refin=no
refout=no
check=0x6c9f84a8

I cannot get golang builtin crc32 package to give me the correct checksums.

This website https://www.lddgo.net/en/encrypt/crc yields the correct sums. (sum for string "0" should be 0xC45441EB)

This website https://simplycalc.com/crc32-text.php yields the same as go (if I reverse poly). (sum for string "0" shows 0x1D62A0AB instead same as go)

Can someone help me understand why a function with such basic parameters isn't matching?

1

There are 1 best solutions below

1
chuckx On

Using https://www.lddgo.net/en/encrypt/crc, the following parameters produce a result which matches the Go hash/crc32 implementation and the Javascript implementation at https://simplycalc.com/crc32-source.php:

  • Bit Width: 32
  • Polynomial Formula (HEX): F4ACFB13
  • Initial Value (HEX): FFFFFFFF
  • XOROUT (HEX): FFFFFFFF
  • REFIN: true
  • REFOUT: true

This answers the initial question, "what parameters are being used?"

If you're open to considering an alternative implementation, you might use one that's designed to be more flexible. See https://github.com/snksoft/crc.

Note that With hash/crc32, you can use an alternative initial value via the first argument of func Update(crc uint32, tab *Table, p []byte) uint32. Otherwise, the parameters are hardcoded. Note that these hardcoded parameters are shared between the predefined polynomials (i.e. IEEE, Castagnoli, and Koopman). Adding support for more parameters to hash/crc32 doesn't look straightforward, as it would require modifying the binary marshaling/unmarshaling functionality, which is subject to the backwards compatibility guarantee (see the last paragraph in https://pkg.go.dev/hash#Hash).


Here's an example comparing usage of hash/crc32 and github.com/snksoft/crc:

package main

import (
    "fmt"
    "hash/crc32"
    "math/bits"

    "github.com/snksoft/crc"
)

func crcSnksoft(params *crc.Parameters, input []byte) uint32 {
    h := crc.NewHash(params)
    h.Update(input)
    return h.CRC32()
}

func crcGo(poly uint32, input []byte) uint32 {
    reversedPoly := bits.Reverse32(poly)
    t := crc32.MakeTable(reversedPoly)
    return crc32.Checksum(input, t)
}

func main() {
    poly := 0xF4ACFB13
    data := []byte("0")

    params := &crc.Parameters{
        Width:      32,
        Polynomial: uint64(poly),
        Init:       0x00000000,
        ReflectIn:  false,
        ReflectOut: false,
        FinalXor:   0x00000000,
    }

    mimicGoParams := &crc.Parameters{
        Width:      32,
        Polynomial: uint64(poly),
        Init:       0xFFFFFFFF,
        ReflectIn:  true,
        ReflectOut: true,
        FinalXor:   0xFFFFFFFF,
    }

    fmt.Printf("snksoft/crc: 0x%X\n", crcSnksoft(params, data))
    fmt.Printf("snksoft/crc (matching hash/crc32): 0x%X\n", crcSnksoft(mimicGoParams, data))
    fmt.Printf("Go standard library (hash/crc32): 0x%X\n", crcGo(uint32(poly), data))
}

Output:

snksoft/crc: 0xC45441EB
snksoft/crc (matching hash/crc32): 0x1D62A0AB
Go standard library (hash/crc32): 0x1D62A0AB

Go Playground