// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32, // checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for // information. // // Polynomials are represented in LSB-first form also known as reversed representation. // // See https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials // for information.
package crc32 import ( ) // The size of a CRC-32 checksum in bytes. const Size = 4 // Predefined polynomials. const ( // IEEE is by far and away the most common CRC-32 polynomial. // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ... IEEE = 0xedb88320 // Castagnoli's polynomial, used in iSCSI. // Has better error detection characteristics than IEEE. // https://dx.doi.org/10.1109/26.231911 Castagnoli = 0x82f63b78 // Koopman's polynomial. // Also has better error detection characteristics than IEEE. // https://dx.doi.org/10.1109/DSN.2002.1028931 Koopman = 0xeb31d82e ) // Table is a 256-word table representing the polynomial for efficient processing. type Table [256]uint32 // This file makes use of functions implemented in architecture-specific files. // The interface that they implement is as follows: // // // archAvailableIEEE reports whether an architecture-specific CRC32-IEEE // // algorithm is available. // archAvailableIEEE() bool // // // archInitIEEE initializes the architecture-specific CRC3-IEEE algorithm. // // It can only be called if archAvailableIEEE() returns true. // archInitIEEE() // // // archUpdateIEEE updates the given CRC32-IEEE. It can only be called if // // archInitIEEE() was previously called. // archUpdateIEEE(crc uint32, p []byte) uint32 // // // archAvailableCastagnoli reports whether an architecture-specific // // CRC32-C algorithm is available. // archAvailableCastagnoli() bool // // // archInitCastagnoli initializes the architecture-specific CRC32-C // // algorithm. It can only be called if archAvailableCastagnoli() returns // // true. // archInitCastagnoli() // // // archUpdateCastagnoli updates the given CRC32-C. It can only be called // // if archInitCastagnoli() was previously called. // archUpdateCastagnoli(crc uint32, p []byte) uint32 // castagnoliTable points to a lazily initialized Table for the Castagnoli // polynomial. MakeTable will always return this value when asked to make a // Castagnoli table so we can compare against it to find when the caller is // using this polynomial. var castagnoliTable *Table var castagnoliTable8 *slicing8Table var updateCastagnoli func(crc uint32, p []byte) uint32 var castagnoliOnce sync.Once var haveCastagnoli atomic.Bool func castagnoliInit() { castagnoliTable = simpleMakeTable(Castagnoli) if archAvailableCastagnoli() { archInitCastagnoli() updateCastagnoli = archUpdateCastagnoli } else { // Initialize the slicing-by-8 table. castagnoliTable8 = slicingMakeTable(Castagnoli) updateCastagnoli = func( uint32, []byte) uint32 { return slicingUpdate(, castagnoliTable8, ) } } haveCastagnoli.Store(true) } // IEEETable is the table for the [IEEE] polynomial. var IEEETable = simpleMakeTable(IEEE) // ieeeTable8 is the slicing8Table for IEEE var ieeeTable8 *slicing8Table var updateIEEE func(crc uint32, p []byte) uint32 var ieeeOnce sync.Once func ieeeInit() { if archAvailableIEEE() { archInitIEEE() updateIEEE = archUpdateIEEE } else { // Initialize the slicing-by-8 table. ieeeTable8 = slicingMakeTable(IEEE) updateIEEE = func( uint32, []byte) uint32 { return slicingUpdate(, ieeeTable8, ) } } } // MakeTable returns a [Table] constructed from the specified polynomial. // The contents of this [Table] must not be modified. func ( uint32) *Table { switch { case IEEE: ieeeOnce.Do(ieeeInit) return IEEETable case Castagnoli: castagnoliOnce.Do(castagnoliInit) return castagnoliTable default: return simpleMakeTable() } } // digest represents the partial evaluation of a checksum. type digest struct { crc uint32 tab *Table } // New creates a new [hash.Hash32] computing the CRC-32 checksum using the // polynomial represented by the [Table]. Its Sum method will lay the // value out in big-endian byte order. The returned Hash32 also // implements [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to // marshal and unmarshal the internal state of the hash. func ( *Table) hash.Hash32 { if == IEEETable { ieeeOnce.Do(ieeeInit) } return &digest{0, } } // NewIEEE creates a new [hash.Hash32] computing the CRC-32 checksum using // the [IEEE] polynomial. Its Sum method will lay the value out in // big-endian byte order. The returned Hash32 also implements // [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to marshal // and unmarshal the internal state of the hash. func () hash.Hash32 { return New(IEEETable) } func ( *digest) () int { return Size } func ( *digest) () int { return 1 } func ( *digest) () { .crc = 0 } const ( magic = "crc\x01" marshaledSize = len(magic) + 4 + 4 ) func ( *digest) () ([]byte, error) { := make([]byte, 0, marshaledSize) = append(, magic...) = appendUint32(, tableSum(.tab)) = appendUint32(, .crc) return , nil } func ( *digest) ( []byte) error { if len() < len(magic) || string([:len(magic)]) != magic { return errors.New("hash/crc32: invalid hash state identifier") } if len() != marshaledSize { return errors.New("hash/crc32: invalid hash state size") } if tableSum(.tab) != readUint32([4:]) { return errors.New("hash/crc32: tables do not match") } .crc = readUint32([8:]) return nil } // appendUint32 is semantically the same as [binary.BigEndian.AppendUint32] // We copied this function because we can not import "encoding/binary" here. func appendUint32( []byte, uint32) []byte { return append(, byte(>>24), byte(>>16), byte(>>8), byte(), ) } // readUint32 is semantically the same as [binary.BigEndian.Uint32] // We copied this function because we can not import "encoding/binary" here. func readUint32( []byte) uint32 { _ = [3] return uint32([3]) | uint32([2])<<8 | uint32([1])<<16 | uint32([0])<<24 } func update( uint32, *Table, []byte, bool) uint32 { switch { case haveCastagnoli.Load() && == castagnoliTable: return updateCastagnoli(, ) case == IEEETable: if { ieeeOnce.Do(ieeeInit) } return updateIEEE(, ) default: return simpleUpdate(, , ) } } // Update returns the result of adding the bytes in p to the crc. func ( uint32, *Table, []byte) uint32 { // Unfortunately, because IEEETable is exported, IEEE may be used without a // call to MakeTable. We have to make sure it gets initialized in that case. return update(, , , true) } func ( *digest) ( []byte) ( int, error) { // We only create digest objects through New() which takes care of // initialization in this case. .crc = update(.crc, .tab, , false) return len(), nil } func ( *digest) () uint32 { return .crc } func ( *digest) ( []byte) []byte { := .Sum32() return append(, byte(>>24), byte(>>16), byte(>>8), byte()) } // Checksum returns the CRC-32 checksum of data // using the polynomial represented by the [Table]. func ( []byte, *Table) uint32 { return Update(0, , ) } // ChecksumIEEE returns the CRC-32 checksum of data // using the [IEEE] polynomial. func ( []byte) uint32 { ieeeOnce.Do(ieeeInit) return updateIEEE(0, ) } // tableSum returns the IEEE checksum of table t. func tableSum( *Table) uint32 { var [1024]byte := [:0] if != nil { for , := range { = appendUint32(, ) } } return ChecksumIEEE() }