Source File
crc32.go
Belonging Package
hash/crc32
// 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 crc32import ()// 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.231911Castagnoli = 0x82f63b78// Koopman's polynomial.// Also has better error detection characteristics than IEEE.// https://dx.doi.org/10.1109/DSN.2002.1028931Koopman = 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 *Tablevar castagnoliTable8 *slicing8Tablevar castagnoliArchImpl boolvar updateCastagnoli func(crc uint32, p []byte) uint32var castagnoliOnce sync.Oncevar haveCastagnoli uint32func () {castagnoliTable = simpleMakeTable(Castagnoli)castagnoliArchImpl = archAvailableCastagnoli()if castagnoliArchImpl {archInitCastagnoli()updateCastagnoli = archUpdateCastagnoli} else {// Initialize the slicing-by-8 table.castagnoliTable8 = slicingMakeTable(Castagnoli)updateCastagnoli = func( uint32, []byte) uint32 {return slicingUpdate(, castagnoliTable8, )}}atomic.StoreUint32(&haveCastagnoli, 1)}// IEEETable is the table for the IEEE polynomial.var IEEETable = simpleMakeTable(IEEE)// ieeeTable8 is the slicing8Table for IEEEvar ieeeTable8 *slicing8Tablevar ieeeArchImpl boolvar updateIEEE func(crc uint32, p []byte) uint32var ieeeOnce sync.Oncefunc () {ieeeArchImpl = archAvailableIEEE()if ieeeArchImpl {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 IEEETablecase Castagnoli:castagnoliOnce.Do(castagnoliInit)return castagnoliTable}return simpleMakeTable()}// digest represents the partial evaluation of a checksum.type digest struct {crc uint32tab *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}func ( []byte, uint32) []byte {:= [4]byte{byte( >> 24),byte( >> 16),byte( >> 8),byte(),}return append(, [:]...)}func ( []byte) uint32 {_ = [3]return uint32([3]) | uint32([2])<<8 | uint32([1])<<16 | uint32([0])<<24}// Update returns the result of adding the bytes in p to the crc.func ( uint32, *Table, []byte) uint32 {switch {case atomic.LoadUint32(&haveCastagnoli) != 0 && == castagnoliTable:return updateCastagnoli(, )case == IEEETable:// 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.ieeeOnce.Do(ieeeInit)return updateIEEE(, )default:return simpleUpdate(, , )}}func ( *digest) ( []byte) ( int, error) {switch {case atomic.LoadUint32(&haveCastagnoli) != 0 && .tab == castagnoliTable:.crc = updateCastagnoli(.crc, )case .tab == IEEETable:// We only create digest objects through New() which takes care of// initialization in this case..crc = updateIEEE(.crc, )default:.crc = simpleUpdate(.crc, .tab, )}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 ( *Table) uint32 {var [1024]byte:= [:0]if != nil {for , := range {= appendUint32(, )}}return ChecksumIEEE()}