github.com/euank/go@v0.0.0-20160829210321-495514729181/src/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 http://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 http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials 12 // for information. 13 package crc32 14 15 import ( 16 "hash" 17 "sync" 18 ) 19 20 // The size of a CRC-32 checksum in bytes. 21 const Size = 4 22 23 // Use "slice by 8" when payload >= this value. 24 const sliceBy8Cutoff = 16 25 26 // Predefined polynomials. 27 const ( 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 // http://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 // http://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. 44 type Table [256]uint32 45 46 // castagnoliTable points to a lazily initialized Table for the Castagnoli 47 // polynomial. MakeTable will always return this value when asked to make a 48 // Castagnoli table so we can compare against it to find when the caller is 49 // using this polynomial. 50 var castagnoliTable *Table 51 var castagnoliTable8 *slicing8Table 52 var castagnoliOnce sync.Once 53 54 func castagnoliInit() { 55 // Call the arch-specific init function and let it decide if we will need 56 // the tables for the generic implementation. 57 needGenericTables := castagnoliInitArch() 58 59 if needGenericTables { 60 castagnoliTable8 = makeTable8(Castagnoli) 61 } 62 63 // Even if we don't need the contents of this table, we use it as a handle 64 // returned by MakeTable. We should find a way to clean this up (see #16909). 65 castagnoliTable = makeTable(Castagnoli) 66 } 67 68 // IEEETable is the table for the IEEE polynomial. 69 var IEEETable = makeTable(IEEE) 70 71 // slicing8Table is array of 8 Tables 72 type slicing8Table [8]Table 73 74 // ieeeTable8 is the slicing8Table for IEEE 75 var ieeeTable8 *slicing8Table 76 var ieeeTable8Once sync.Once 77 78 // MakeTable returns a Table constructed from the specified polynomial. 79 // The contents of this Table must not be modified. 80 func MakeTable(poly uint32) *Table { 81 switch poly { 82 case IEEE: 83 return IEEETable 84 case Castagnoli: 85 castagnoliOnce.Do(castagnoliInit) 86 return castagnoliTable 87 } 88 return makeTable(poly) 89 } 90 91 // makeTable returns the Table constructed from the specified polynomial. 92 func makeTable(poly uint32) *Table { 93 t := new(Table) 94 for i := 0; i < 256; i++ { 95 crc := uint32(i) 96 for j := 0; j < 8; j++ { 97 if crc&1 == 1 { 98 crc = (crc >> 1) ^ poly 99 } else { 100 crc >>= 1 101 } 102 } 103 t[i] = crc 104 } 105 return t 106 } 107 108 // makeTable8 returns slicing8Table constructed from the specified polynomial. 109 func makeTable8(poly uint32) *slicing8Table { 110 t := new(slicing8Table) 111 t[0] = *makeTable(poly) 112 for i := 0; i < 256; i++ { 113 crc := t[0][i] 114 for j := 1; j < 8; j++ { 115 crc = t[0][crc&0xFF] ^ (crc >> 8) 116 t[j][i] = crc 117 } 118 } 119 return t 120 } 121 122 // digest represents the partial evaluation of a checksum. 123 type digest struct { 124 crc uint32 125 tab *Table 126 } 127 128 // New creates a new hash.Hash32 computing the CRC-32 checksum 129 // using the polynomial represented by the Table. 130 // Its Sum method will lay the value out in big-endian byte order. 131 func New(tab *Table) hash.Hash32 { return &digest{0, tab} } 132 133 // NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum 134 // using the IEEE polynomial. 135 // Its Sum method will lay the value out in big-endian byte order. 136 func NewIEEE() hash.Hash32 { return New(IEEETable) } 137 138 func (d *digest) Size() int { return Size } 139 140 func (d *digest) BlockSize() int { return 1 } 141 142 func (d *digest) Reset() { d.crc = 0 } 143 144 func update(crc uint32, tab *Table, p []byte) uint32 { 145 crc = ^crc 146 for _, v := range p { 147 crc = tab[byte(crc)^v] ^ (crc >> 8) 148 } 149 return ^crc 150 } 151 152 // updateSlicingBy8 updates CRC using Slicing-by-8 153 func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 { 154 crc = ^crc 155 for len(p) > 8 { 156 crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 157 crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^ 158 tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^ 159 tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF] 160 p = p[8:] 161 } 162 crc = ^crc 163 if len(p) == 0 { 164 return crc 165 } 166 return update(crc, &tab[0], p) 167 } 168 169 // Update returns the result of adding the bytes in p to the crc. 170 func Update(crc uint32, tab *Table, p []byte) uint32 { 171 switch tab { 172 case castagnoliTable: 173 return updateCastagnoli(crc, p) 174 case IEEETable: 175 return updateIEEE(crc, p) 176 } 177 return update(crc, tab, p) 178 } 179 180 func (d *digest) Write(p []byte) (n int, err error) { 181 d.crc = Update(d.crc, d.tab, p) 182 return len(p), nil 183 } 184 185 func (d *digest) Sum32() uint32 { return d.crc } 186 187 func (d *digest) Sum(in []byte) []byte { 188 s := d.Sum32() 189 return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) 190 } 191 192 // Checksum returns the CRC-32 checksum of data 193 // using the polynomial represented by the Table. 194 func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) } 195 196 // ChecksumIEEE returns the CRC-32 checksum of data 197 // using the IEEE polynomial. 198 func ChecksumIEEE(data []byte) uint32 { return updateIEEE(0, data) }