1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32, 6// checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for 7// information. 8// 9// Polynomials are represented in LSB-first form also known as reversed representation. 10// 11// See https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials 12// for information. 13package crc32 14 15import ( 16 "errors" 17 "hash" 18 "internal/byteorder" 19 "sync" 20 "sync/atomic" 21) 22 23// The size of a CRC-32 checksum in bytes. 24const Size = 4 25 26// Predefined polynomials. 27const ( 28 // IEEE is by far and away the most common CRC-32 polynomial. 29 // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ... 30 IEEE = 0xedb88320 31 32 // Castagnoli's polynomial, used in iSCSI. 33 // Has better error detection characteristics than IEEE. 34 // https://dx.doi.org/10.1109/26.231911 35 Castagnoli = 0x82f63b78 36 37 // Koopman's polynomial. 38 // Also has better error detection characteristics than IEEE. 39 // https://dx.doi.org/10.1109/DSN.2002.1028931 40 Koopman = 0xeb31d82e 41) 42 43// Table is a 256-word table representing the polynomial for efficient processing. 44type Table [256]uint32 45 46// This file makes use of functions implemented in architecture-specific files. 47// The interface that they implement is as follows: 48// 49// // archAvailableIEEE reports whether an architecture-specific CRC32-IEEE 50// // algorithm is available. 51// archAvailableIEEE() bool 52// 53// // archInitIEEE initializes the architecture-specific CRC3-IEEE algorithm. 54// // It can only be called if archAvailableIEEE() returns true. 55// archInitIEEE() 56// 57// // archUpdateIEEE updates the given CRC32-IEEE. It can only be called if 58// // archInitIEEE() was previously called. 59// archUpdateIEEE(crc uint32, p []byte) uint32 60// 61// // archAvailableCastagnoli reports whether an architecture-specific 62// // CRC32-C algorithm is available. 63// archAvailableCastagnoli() bool 64// 65// // archInitCastagnoli initializes the architecture-specific CRC32-C 66// // algorithm. It can only be called if archAvailableCastagnoli() returns 67// // true. 68// archInitCastagnoli() 69// 70// // archUpdateCastagnoli updates the given CRC32-C. It can only be called 71// // if archInitCastagnoli() was previously called. 72// archUpdateCastagnoli(crc uint32, p []byte) uint32 73 74// castagnoliTable points to a lazily initialized Table for the Castagnoli 75// polynomial. MakeTable will always return this value when asked to make a 76// Castagnoli table so we can compare against it to find when the caller is 77// using this polynomial. 78var castagnoliTable *Table 79var castagnoliTable8 *slicing8Table 80var updateCastagnoli func(crc uint32, p []byte) uint32 81var castagnoliOnce sync.Once 82var haveCastagnoli atomic.Bool 83 84func castagnoliInit() { 85 castagnoliTable = simpleMakeTable(Castagnoli) 86 87 if archAvailableCastagnoli() { 88 archInitCastagnoli() 89 updateCastagnoli = archUpdateCastagnoli 90 } else { 91 // Initialize the slicing-by-8 table. 92 castagnoliTable8 = slicingMakeTable(Castagnoli) 93 updateCastagnoli = func(crc uint32, p []byte) uint32 { 94 return slicingUpdate(crc, castagnoliTable8, p) 95 } 96 } 97 98 haveCastagnoli.Store(true) 99} 100 101// IEEETable is the table for the [IEEE] polynomial. 102var IEEETable = simpleMakeTable(IEEE) 103 104// ieeeTable8 is the slicing8Table for IEEE 105var ieeeTable8 *slicing8Table 106var updateIEEE func(crc uint32, p []byte) uint32 107var ieeeOnce sync.Once 108 109func ieeeInit() { 110 if archAvailableIEEE() { 111 archInitIEEE() 112 updateIEEE = archUpdateIEEE 113 } else { 114 // Initialize the slicing-by-8 table. 115 ieeeTable8 = slicingMakeTable(IEEE) 116 updateIEEE = func(crc uint32, p []byte) uint32 { 117 return slicingUpdate(crc, ieeeTable8, p) 118 } 119 } 120} 121 122// MakeTable returns a [Table] constructed from the specified polynomial. 123// The contents of this [Table] must not be modified. 124func MakeTable(poly uint32) *Table { 125 switch poly { 126 case IEEE: 127 ieeeOnce.Do(ieeeInit) 128 return IEEETable 129 case Castagnoli: 130 castagnoliOnce.Do(castagnoliInit) 131 return castagnoliTable 132 default: 133 return simpleMakeTable(poly) 134 } 135} 136 137// digest represents the partial evaluation of a checksum. 138type digest struct { 139 crc uint32 140 tab *Table 141} 142 143// New creates a new [hash.Hash32] computing the CRC-32 checksum using the 144// polynomial represented by the [Table]. Its Sum method will lay the 145// value out in big-endian byte order. The returned Hash32 also 146// implements [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to 147// marshal and unmarshal the internal state of the hash. 148func New(tab *Table) hash.Hash32 { 149 if tab == IEEETable { 150 ieeeOnce.Do(ieeeInit) 151 } 152 return &digest{0, tab} 153} 154 155// NewIEEE creates a new [hash.Hash32] computing the CRC-32 checksum using 156// the [IEEE] polynomial. Its Sum method will lay the value out in 157// big-endian byte order. The returned Hash32 also implements 158// [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to marshal 159// and unmarshal the internal state of the hash. 160func NewIEEE() hash.Hash32 { return New(IEEETable) } 161 162func (d *digest) Size() int { return Size } 163 164func (d *digest) BlockSize() int { return 1 } 165 166func (d *digest) Reset() { d.crc = 0 } 167 168const ( 169 magic = "crc\x01" 170 marshaledSize = len(magic) + 4 + 4 171) 172 173func (d *digest) MarshalBinary() ([]byte, error) { 174 b := make([]byte, 0, marshaledSize) 175 b = append(b, magic...) 176 b = byteorder.BeAppendUint32(b, tableSum(d.tab)) 177 b = byteorder.BeAppendUint32(b, d.crc) 178 return b, nil 179} 180 181func (d *digest) UnmarshalBinary(b []byte) error { 182 if len(b) < len(magic) || string(b[:len(magic)]) != magic { 183 return errors.New("hash/crc32: invalid hash state identifier") 184 } 185 if len(b) != marshaledSize { 186 return errors.New("hash/crc32: invalid hash state size") 187 } 188 if tableSum(d.tab) != byteorder.BeUint32(b[4:]) { 189 return errors.New("hash/crc32: tables do not match") 190 } 191 d.crc = byteorder.BeUint32(b[8:]) 192 return nil 193} 194 195func update(crc uint32, tab *Table, p []byte, checkInitIEEE bool) uint32 { 196 switch { 197 case haveCastagnoli.Load() && tab == castagnoliTable: 198 return updateCastagnoli(crc, p) 199 case tab == IEEETable: 200 if checkInitIEEE { 201 ieeeOnce.Do(ieeeInit) 202 } 203 return updateIEEE(crc, p) 204 default: 205 return simpleUpdate(crc, tab, p) 206 } 207} 208 209// Update returns the result of adding the bytes in p to the crc. 210func Update(crc uint32, tab *Table, p []byte) uint32 { 211 // Unfortunately, because IEEETable is exported, IEEE may be used without a 212 // call to MakeTable. We have to make sure it gets initialized in that case. 213 return update(crc, tab, p, true) 214} 215 216func (d *digest) Write(p []byte) (n int, err error) { 217 // We only create digest objects through New() which takes care of 218 // initialization in this case. 219 d.crc = update(d.crc, d.tab, p, false) 220 return len(p), nil 221} 222 223func (d *digest) Sum32() uint32 { return d.crc } 224 225func (d *digest) Sum(in []byte) []byte { 226 s := d.Sum32() 227 return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) 228} 229 230// Checksum returns the CRC-32 checksum of data 231// using the polynomial represented by the [Table]. 232func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) } 233 234// ChecksumIEEE returns the CRC-32 checksum of data 235// using the [IEEE] polynomial. 236func ChecksumIEEE(data []byte) uint32 { 237 ieeeOnce.Do(ieeeInit) 238 return updateIEEE(0, data) 239} 240 241// tableSum returns the IEEE checksum of table t. 242func tableSum(t *Table) uint32 { 243 var a [1024]byte 244 b := a[:0] 245 if t != nil { 246 for _, x := range t { 247 b = byteorder.BeAppendUint32(b, x) 248 } 249 } 250 return ChecksumIEEE(b) 251} 252