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.
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
15 // The size of a CRC-64 checksum in bytes.
18 // Predefined polynomials.
20 // The ISO polynomial, defined in ISO 3309 and used in HDLC.
21 ISO
= 0xD800000000000000
23 // The ECMA polynomial, defined in ECMA 182.
24 ECMA
= 0xC96C5795D7870F42
27 // Table is a 256-word table representing the polynomial for efficient processing.
28 type Table
[256]uint64
31 slicing8TableISO
= makeSlicingBy8Table(makeTable(ISO
))
32 slicing8TableECMA
= makeSlicingBy8Table(makeTable(ECMA
))
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
{
40 return &slicing8TableISO
[0]
42 return &slicing8TableECMA
[0]
44 return makeTable(poly
)
48 func makeTable(poly
uint64) *Table
{
50 for i
:= 0; i
< 256; i
++ {
52 for j
:= 0; j
< 8; j
++ {
54 crc
= (crc
>> 1) ^ poly
64 func makeSlicingBy8Table(t
*Table
) *[8]Table
{
65 var helperTable
[8]Table
67 for i
:= 0; i
< 256; i
++ {
69 for j
:= 1; j
< 8; j
++ {
70 crc
= t
[crc
&0xff] ^ (crc
>> 8)
71 helperTable
[j
][i
] = crc
77 // digest represents the partial evaluation of a checksum.
83 // New creates a new hash.Hash64 computing the CRC-64 checksum using the
84 // polynomial represented by the Table. Its Sum method will lay the
85 // value out in big-endian byte order. The returned Hash64 also
86 // implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
87 // marshal and unmarshal the internal state of the hash.
88 func New(tab
*Table
) hash
.Hash64
{ return &digest
{0, tab
} }
90 func (d
*digest
) Size() int { return Size
}
92 func (d
*digest
) BlockSize() int { return 1 }
94 func (d
*digest
) Reset() { d
.crc
= 0 }
98 marshaledSize
= len(magic
) + 8 + 8
101 func (d
*digest
) MarshalBinary() ([]byte, error
) {
102 b
:= make([]byte, 0, marshaledSize
)
103 b
= append(b
, magic
...)
104 b
= appendUint64(b
, tableSum(d
.tab
))
105 b
= appendUint64(b
, d
.crc
)
109 func (d
*digest
) UnmarshalBinary(b
[]byte) error
{
110 if len(b
) < len(magic
) ||
string(b
[:len(magic
)]) != magic
{
111 return errors
.New("hash/crc64: invalid hash state identifier")
113 if len(b
) != marshaledSize
{
114 return errors
.New("hash/crc64: invalid hash state size")
116 if tableSum(d
.tab
) != readUint64(b
[4:]) {
117 return errors
.New("hash/crc64: tables do not match")
119 d
.crc
= readUint64(b
[12:])
123 func appendUint64(b
[]byte, x
uint64) []byte {
134 return append(b
, a
[:]...)
137 func readUint64(b
[]byte) uint64 {
139 return uint64(b
[7]) |
uint64(b
[6])<<8 |
uint64(b
[5])<<16 |
uint64(b
[4])<<24 |
140 uint64(b
[3])<<32 |
uint64(b
[2])<<40 |
uint64(b
[1])<<48 |
uint64(b
[0])<<56
143 func update(crc
uint64, tab
*Table
, p
[]byte) uint64 {
145 // Table comparison is somewhat expensive, so avoid it for small sizes
147 var helperTable
*[8]Table
148 if *tab
== slicing8TableECMA
[0] {
149 helperTable
= slicing8TableECMA
150 } else if *tab
== slicing8TableISO
[0] {
151 helperTable
= slicing8TableISO
152 // For smaller sizes creating extended table takes too much time
153 } else if len(p
) > 16384 {
154 helperTable
= makeSlicingBy8Table(tab
)
158 // Update using slicing-by-8
160 crc
^= uint64(p
[0]) |
uint64(p
[1])<<8 |
uint64(p
[2])<<16 |
uint64(p
[3])<<24 |
161 uint64(p
[4])<<32 |
uint64(p
[5])<<40 |
uint64(p
[6])<<48 |
uint64(p
[7])<<56
162 crc
= helperTable
[7][crc
&0xff] ^
163 helperTable
[6][(crc
>>8)&0xff] ^
164 helperTable
[5][(crc
>>16)&0xff] ^
165 helperTable
[4][(crc
>>24)&0xff] ^
166 helperTable
[3][(crc
>>32)&0xff] ^
167 helperTable
[2][(crc
>>40)&0xff] ^
168 helperTable
[1][(crc
>>48)&0xff] ^
169 helperTable
[0][crc
>>56]
173 // For reminders or small sizes
174 for _
, v
:= range p
{
175 crc
= tab
[byte(crc
)^v
] ^ (crc
>> 8)
180 // Update returns the result of adding the bytes in p to the crc.
181 func Update(crc
uint64, tab
*Table
, p
[]byte) uint64 {
182 return update(crc
, tab
, p
)
185 func (d
*digest
) Write(p
[]byte) (n
int, err error
) {
186 d
.crc
= update(d
.crc
, d
.tab
, p
)
190 func (d
*digest
) Sum64() uint64 { return d
.crc
}
192 func (d
*digest
) Sum(in
[]byte) []byte {
194 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
))
197 // Checksum returns the CRC-64 checksum of data
198 // using the polynomial represented by the Table.
199 func Checksum(data
[]byte, tab
*Table
) uint64 { return update(0, tab
, data
) }
201 // tableSum returns the ISO checksum of table t.
202 func tableSum(t
*Table
) uint64 {
206 for _
, x
:= range t
{
207 b
= appendUint64(b
, x
)
210 return Checksum(b
, MakeTable(ISO
))