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 updateCastagnoli func(crc uint32, p []byte) uint32var haveCastagnoli atomic.Boolvar castagnoliInitOnce = sync.OnceFunc(func() {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 IEEEvar ieeeTable8 *slicing8Tablevar updateIEEE func(crc uint32, p []byte) uint32var ieeeInitOnce = sync.OnceFunc(func() {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:ieeeInitOnce()return IEEETablecase Castagnoli:castagnoliInitOnce()return castagnoliTabledefault: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 {ieeeInitOnce()}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) ([]byte, error) {= append(, magic...)= byteorder.BEAppendUint32(, tableSum(.tab))= byteorder.BEAppendUint32(, .crc)return , nil}func ( *digest) () ([]byte, error) {return .AppendBinary(make([]byte, 0, marshaledSize))}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) != byteorder.BEUint32([4:]) {return errors.New("hash/crc32: tables do not match")}.crc = byteorder.BEUint32([8:])return nil}func ( *digest) () (hash.Cloner, error) {:= *return &, nil}func update( uint32, *Table, []byte, bool) uint32 {switch {case haveCastagnoli.Load() && == castagnoliTable:return updateCastagnoli(, )case == IEEETable:if {ieeeInitOnce()}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 {ieeeInitOnce()return updateIEEE(0, )}// tableSum returns the IEEE checksum of table t.func tableSum( *Table) uint32 {var [1024]byte:= [:0]if != nil {for , := range {= byteorder.BEAppendUint32(, )}}return ChecksumIEEE()}
![]() |
The pages are generated with Golds v0.7.9-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |