github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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 // appendUint32 is semantically the same as [binary.BigEndian.AppendUint32] 195 // We copied this function because we can not import "encoding/binary" here. 196 func appendUint32(b []byte, x uint32) []byte { 197 return append(b, 198 byte(x>>24), 199 byte(x>>16), 200 byte(x>>8), 201 byte(x), 202 ) 203 } 204 205 // readUint32 is semantically the same as [binary.BigEndian.Uint32] 206 // We copied this function because we can not import "encoding/binary" here. 207 func readUint32(b []byte) uint32 { 208 _ = b[3] 209 return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 210 } 211 212 func update(crc uint32, tab *Table, p []byte, checkInitIEEE bool) uint32 { 213 switch { 214 case haveCastagnoli.Load() && tab == castagnoliTable: 215 return updateCastagnoli(crc, p) 216 case tab == IEEETable: 217 if checkInitIEEE { 218 ieeeOnce.Do(ieeeInit) 219 } 220 return updateIEEE(crc, p) 221 default: 222 return simpleUpdate(crc, tab, p) 223 } 224 } 225 226 // Update returns the result of adding the bytes in p to the crc. 227 func Update(crc uint32, tab *Table, p []byte) uint32 { 228 // Unfortunately, because IEEETable is exported, IEEE may be used without a 229 // call to MakeTable. We have to make sure it gets initialized in that case. 230 return update(crc, tab, p, true) 231 } 232 233 func (d *digest) Write(p []byte) (n int, err error) { 234 // We only create digest objects through New() which takes care of 235 // initialization in this case. 236 d.crc = update(d.crc, d.tab, p, false) 237 return len(p), nil 238 } 239 240 func (d *digest) Sum32() uint32 { return d.crc } 241 242 func (d *digest) Sum(in []byte) []byte { 243 s := d.Sum32() 244 return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) 245 } 246 247 // Checksum returns the CRC-32 checksum of data 248 // using the polynomial represented by the [Table]. 249 func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) } 250 251 // ChecksumIEEE returns the CRC-32 checksum of data 252 // using the [IEEE] polynomial. 253 func ChecksumIEEE(data []byte) uint32 { 254 ieeeOnce.Do(ieeeInit) 255 return updateIEEE(0, data) 256 } 257 258 // tableSum returns the IEEE checksum of table t. 259 func tableSum(t *Table) uint32 { 260 var a [1024]byte 261 b := a[:0] 262 if t != nil { 263 for _, x := range t { 264 b = appendUint32(b, x) 265 } 266 } 267 return ChecksumIEEE(b) 268 }