github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/hash/crc64/crc64.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 crc64 implements the 64-bit cyclic redundancy check, or CRC-64, 6 // checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for 7 // information. 8 package crc64 9 10 import ( 11 "errors" 12 "hash" 13 ) 14 15 // The size of a CRC-64 checksum in bytes. 16 const Size = 8 17 18 // Predefined polynomials. 19 const ( 20 // The ISO polynomial, defined in ISO 3309 and used in HDLC. 21 ISO = 0xD800000000000000 22 23 // The ECMA polynomial, defined in ECMA 182. 24 ECMA = 0xC96C5795D7870F42 25 ) 26 27 // Table is a 256-word table representing the polynomial for efficient processing. 28 type Table [256]uint64 29 30 var ( 31 slicing8TableISO = makeSlicingBy8Table(makeTable(ISO)) 32 slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA)) 33 ) 34 35 // MakeTable returns a Table constructed from the specified polynomial. 36 // The contents of this Table must not be modified. 37 func MakeTable(poly uint64) *Table { 38 switch poly { 39 case ISO: 40 return &slicing8TableISO[0] 41 case ECMA: 42 return &slicing8TableECMA[0] 43 default: 44 return makeTable(poly) 45 } 46 } 47 48 func makeTable(poly uint64) *Table { 49 t := new(Table) 50 for i := 0; i < 256; i++ { 51 crc := uint64(i) 52 for j := 0; j < 8; j++ { 53 if crc&1 == 1 { 54 crc = (crc >> 1) ^ poly 55 } else { 56 crc >>= 1 57 } 58 } 59 t[i] = crc 60 } 61 return t 62 } 63 64 func makeSlicingBy8Table(t *Table) *[8]Table { 65 var helperTable [8]Table 66 helperTable[0] = *t 67 for i := 0; i < 256; i++ { 68 crc := t[i] 69 for j := 1; j < 8; j++ { 70 crc = t[crc&0xff] ^ (crc >> 8) 71 helperTable[j][i] = crc 72 } 73 } 74 return &helperTable 75 } 76 77 // digest represents the partial evaluation of a checksum. 78 type digest struct { 79 crc uint64 80 tab *Table 81 } 82 83 // New creates a new hash.Hash64 computing the CRC-64 checksum 84 // using the polynomial represented by the Table. 85 // Its Sum method will lay the value out in big-endian byte order. 86 func New(tab *Table) hash.Hash64 { return &digest{0, tab} } 87 88 func (d *digest) Size() int { return Size } 89 90 func (d *digest) BlockSize() int { return 1 } 91 92 func (d *digest) Reset() { d.crc = 0 } 93 94 const ( 95 magic = "crc\x02" 96 marshaledSize = len(magic) + 8 + 8 97 ) 98 99 func (d *digest) MarshalBinary() ([]byte, error) { 100 b := make([]byte, 0, marshaledSize) 101 b = append(b, magic...) 102 b = appendUint64(b, tableSum(d.tab)) 103 b = appendUint64(b, d.crc) 104 return b, nil 105 } 106 107 func (d *digest) UnmarshalBinary(b []byte) error { 108 if len(b) < len(magic) || string(b[:len(magic)]) != magic { 109 return errors.New("hash/crc64: invalid hash state identifier") 110 } 111 if len(b) != marshaledSize { 112 return errors.New("hash/crc64: invalid hash state size") 113 } 114 if tableSum(d.tab) != readUint64(b[4:]) { 115 return errors.New("hash/crc64: tables do not match") 116 } 117 d.crc = readUint64(b[12:]) 118 return nil 119 } 120 121 func appendUint64(b []byte, x uint64) []byte { 122 a := [8]byte{ 123 byte(x >> 56), 124 byte(x >> 48), 125 byte(x >> 40), 126 byte(x >> 32), 127 byte(x >> 24), 128 byte(x >> 16), 129 byte(x >> 8), 130 byte(x), 131 } 132 return append(b, a[:]...) 133 } 134 135 func readUint64(b []byte) uint64 { 136 _ = b[7] 137 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | 138 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 139 } 140 141 func update(crc uint64, tab *Table, p []byte) uint64 { 142 crc = ^crc 143 // Table comparison is somewhat expensive, so avoid it for small sizes 144 for len(p) >= 64 { 145 var helperTable *[8]Table 146 if *tab == slicing8TableECMA[0] { 147 helperTable = slicing8TableECMA 148 } else if *tab == slicing8TableISO[0] { 149 helperTable = slicing8TableISO 150 // For smaller sizes creating extended table takes too much time 151 } else if len(p) > 16384 { 152 helperTable = makeSlicingBy8Table(tab) 153 } else { 154 break 155 } 156 // Update using slicing-by-8 157 for len(p) > 8 { 158 crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | 159 uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 160 crc = helperTable[7][crc&0xff] ^ 161 helperTable[6][(crc>>8)&0xff] ^ 162 helperTable[5][(crc>>16)&0xff] ^ 163 helperTable[4][(crc>>24)&0xff] ^ 164 helperTable[3][(crc>>32)&0xff] ^ 165 helperTable[2][(crc>>40)&0xff] ^ 166 helperTable[1][(crc>>48)&0xff] ^ 167 helperTable[0][crc>>56] 168 p = p[8:] 169 } 170 } 171 // For reminders or small sizes 172 for _, v := range p { 173 crc = tab[byte(crc)^v] ^ (crc >> 8) 174 } 175 return ^crc 176 } 177 178 // Update returns the result of adding the bytes in p to the crc. 179 func Update(crc uint64, tab *Table, p []byte) uint64 { 180 return update(crc, tab, p) 181 } 182 183 func (d *digest) Write(p []byte) (n int, err error) { 184 d.crc = update(d.crc, d.tab, p) 185 return len(p), nil 186 } 187 188 func (d *digest) Sum64() uint64 { return d.crc } 189 190 func (d *digest) Sum(in []byte) []byte { 191 s := d.Sum64() 192 return append(in, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) 193 } 194 195 // Checksum returns the CRC-64 checksum of data 196 // using the polynomial represented by the Table. 197 func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) } 198 199 // tableSum returns the ISO checksum of table t. 200 func tableSum(t *Table) uint64 { 201 var a [2048]byte 202 b := a[:0] 203 if t != nil { 204 for _, x := range t { 205 b = appendUint64(b, x) 206 } 207 } 208 return Checksum(b, MakeTable(ISO)) 209 }