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