2008-11-24 13:30:40 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// CRC-32 checksum.
|
|
|
|
// http://en.wikipedia.org/wiki/Cyclic_redundancy_check for links
|
|
|
|
|
|
|
|
package crc32
|
|
|
|
|
|
|
|
import "os"
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
const (
|
2008-11-24 13:30:40 -07:00
|
|
|
// Far and away the most common CRC-32 polynomial.
|
|
|
|
// Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ...
|
|
|
|
IEEE = 0xedb88320;
|
|
|
|
|
|
|
|
// Castagnoli's polynomial, used in iSCSI.
|
|
|
|
// Has better error detection characteristics than IEEE.
|
|
|
|
// http://dx.doi.org/10.1109/26.231911
|
|
|
|
Castagnoli = 0x82f63b78;
|
|
|
|
|
|
|
|
// Koopman's polynomial.
|
|
|
|
// Also has better error detection characteristics than IEEE.
|
|
|
|
// http://dx.doi.org/10.1109/DSN.2002.1028931
|
|
|
|
Koopman = 0xeb31d82e;
|
|
|
|
)
|
|
|
|
|
2008-12-19 04:05:37 -07:00
|
|
|
// TODO(rsc): Change to [256]uint32 once 6g can handle it.
|
2009-01-20 15:40:40 -07:00
|
|
|
type Table []uint32
|
2008-11-24 13:30:40 -07:00
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func MakeTable(poly uint32) Table {
|
2009-01-06 16:19:02 -07:00
|
|
|
t := make(Table, 256);
|
2008-11-24 13:30:40 -07:00
|
|
|
for i := 0; i < 256; i++ {
|
|
|
|
crc := uint32(i);
|
|
|
|
for j := 0; j < 8; j++ {
|
|
|
|
if crc&1 == 1 {
|
|
|
|
crc = (crc>>1) ^ poly;
|
|
|
|
} else {
|
|
|
|
crc >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t[i] = crc;
|
|
|
|
}
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
var IEEETable = MakeTable(IEEE);
|
2008-11-24 13:30:40 -07:00
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
type Digest struct {
|
2008-11-24 13:30:40 -07:00
|
|
|
crc uint32;
|
2008-12-18 23:37:22 -07:00
|
|
|
tab Table;
|
2008-11-24 13:30:40 -07:00
|
|
|
}
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func NewDigest(tab Table) *Digest {
|
2009-03-03 09:39:12 -07:00
|
|
|
return &Digest{0, tab};
|
2008-11-24 13:30:40 -07:00
|
|
|
}
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
func NewIEEEDigest() *Digest {
|
2009-01-16 11:14:28 -07:00
|
|
|
return NewDigest(IEEETable);
|
2008-11-24 13:30:40 -07:00
|
|
|
}
|
|
|
|
|
2008-12-18 23:37:22 -07:00
|
|
|
func (d *Digest) Write(p []byte) (n int, err *os.Error) {
|
2008-11-24 13:30:40 -07:00
|
|
|
crc := d.crc ^ 0xFFFFFFFF;
|
|
|
|
tab := d.tab;
|
|
|
|
for i := 0; i < len(p); i++ {
|
|
|
|
crc = tab[byte(crc) ^ p[i]] ^ (crc >> 8);
|
|
|
|
}
|
|
|
|
d.crc = crc ^ 0xFFFFFFFF;
|
|
|
|
return len(p), nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Digest) Sum32() uint32 {
|
|
|
|
return d.crc
|
|
|
|
}
|
|
|
|
|
2008-12-18 23:37:22 -07:00
|
|
|
func (d *Digest) Sum() []byte {
|
2009-01-06 16:19:02 -07:00
|
|
|
p := make([]byte, 4);
|
2008-11-24 13:30:40 -07:00
|
|
|
s := d.Sum32();
|
|
|
|
p[0] = byte(s>>24);
|
|
|
|
p[1] = byte(s>>16);
|
|
|
|
p[2] = byte(s>>8);
|
|
|
|
p[3] = byte(s);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|