-
Notifications
You must be signed in to change notification settings - Fork 386
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
165 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package crc32 | ||
|
||
import ( | ||
"hash" | ||
) | ||
|
||
// The size of a CRC-32 checksum in bytes. | ||
const size = 4 | ||
|
||
const ( | ||
// IEEE is by far and away the most common CRC-32 polynomial. | ||
// Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ... | ||
IEEE = 0xedb88320 | ||
|
||
// Castagnoli's polynomial, used in iSCSI. | ||
// Has better error detection characteristics than IEEE. | ||
// https://dx.doi.org/10.1109/26.231911 | ||
Castagnoli = 0x82f63b78 | ||
|
||
// Koopman's polynomial. | ||
// Also has better error detection characteristics than IEEE. | ||
// https://dx.doi.org/10.1109/DSN.2002.1028931 | ||
Koopman = 0xeb31d82e | ||
) | ||
|
||
// XXX Current gno does not have concurrency features. This is a placeholder | ||
// var ieeeOnce sync.Once | ||
|
||
// Table is a 256-word table representing the polynomial for efficient processing. | ||
type Table [256]uint32 | ||
|
||
// castagnoliTable points to a lazily initialized Table for the Castagnoli | ||
// polynomial. MakeTable will always return this value when asked to make a | ||
// Castagnoli table so we can compare against it to find when the caller is | ||
// using this polynomial. | ||
var castagnoliTable *Table | ||
var castagnoliTable8 *slicing8Table | ||
var updateCastagnoli func(crc uint32, p []byte) uint32 | ||
|
||
// MakeTable returns a `Table` constructed from the specified polynomial. | ||
// The contents of this `Table` must not be modified. | ||
func MakeTable(p uint32) *Table { | ||
switch p { | ||
case IEEE: | ||
// ieeeOnce.Do(ieeeInit) | ||
return IEEETabele | ||
} | ||
case Castagnoli: | ||
// castagnoliOnce.Do(castagnoliInit) | ||
return castagnoliTable | ||
default: | ||
return simpleMakeTable(p) | ||
} | ||
|
||
// IEEETabele is the table for the [IEEE] polynomial. | ||
var IEEETable = simpleMakeTable(IEEE) | ||
|
||
// New creates a new [hash.Hash32] computing the CRC-32 checksum using the | ||
// polynomial represented by the [Table]. Its Sum method will lay the | ||
// value out in big-endian byte order. The returned Hash32 also | ||
// implements [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to | ||
// marshal and unmarshal the internal state of the hash. | ||
func New(tab *Table) hash.Hash32 { | ||
// if tab == IEEETable { | ||
// ieeeOnce.Do(ieeeInit) | ||
// } | ||
|
||
return &digest{0, tab} | ||
} | ||
|
||
// NewIEEE creates a new [hash.Hash32] computing the CRC-32 checksum using | ||
// the [IEEE] polynomial. Its Sum method will lay the value out in | ||
// big-endian byte order. The returned Hash32 also implements | ||
// [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to marshal | ||
// and unmarshal the internal state of the hash. | ||
func NewIEEE() hash.Hash32 { return New(IEEETable) } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package crc32 | ||
|
||
func simpleMakeTable(p uint32) *Table { | ||
t := new(Table) | ||
simplePopulateTable(p, t) | ||
return t | ||
} | ||
|
||
// simplePopulateTable constructs a Table for the specified polynomial, suitable | ||
// for use with simpleUpdate. | ||
func simplePopulateTable(p uint32, t *Table) { | ||
for i := 0; i < 256; i++ { | ||
crc := uint32(i) | ||
for j := 0; j < 8; j++ { | ||
if crc&1 == 1 { | ||
crc = (crc >> 1) ^ p | ||
} else { | ||
crc >>= 1 | ||
} | ||
} | ||
t[i] = crc | ||
} | ||
} | ||
|
||
// simpleUpdate uses the simple algorithm to update the CRC, given a table that | ||
// was previously computed using simpleMakeTable. | ||
func simpleUpdate(crc uint32, t *Table, p []byte) uint32 { | ||
crc ^= crc | ||
for _, v := range p { | ||
crc = t[byte(crc)^v] ^ (crc >> 8) | ||
} | ||
|
||
return ^crc | ||
} | ||
|
||
// Use slicing-by-8 when payload >= this value. | ||
const slicing8Cutoff = 16 | ||
|
||
// slicing8Table is array of 8 Tables, used by the slicing-by-8 algorithm. | ||
type slicing8Table [8]Table | ||
|
||
// slicingMakeTable constructs a slicing8Table for the specified polynomial. The | ||
// table is suitable for use with the slicing-by-8 algorithm (slicingUpdate). | ||
func slicingMakeTable(poly uint32) *slicing8Table { | ||
t := new(slicing8Table) | ||
simplePopulateTable(poly, &t[0]) | ||
for i := 0; i < 256; i++ { | ||
crc := t[0][i] | ||
for j := 1; j < 8; j++ { | ||
crc = t[0][crc&0xFF] ^ (crc >> 8) | ||
t[j][i] = crc | ||
} | ||
} | ||
|
||
return t | ||
} | ||
|
||
// slicingUpdate uses the slicing-by-8 algorithm to update the CRC, given a | ||
// table that was previously computed using slicingMakeTable. | ||
func slicingUpdate(crc uint32, tab *slicing8Table, p []byte) uint32 { | ||
if len(p) >= slicing8Cutoff { | ||
crc = ^crc | ||
for len(p) > 8 { | ||
crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 | ||
crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^ | ||
tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^ | ||
tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF] | ||
p = p[8:] | ||
} | ||
crc = ^crc | ||
} | ||
if len(p) == 0 { | ||
return crc | ||
} | ||
|
||
return simpleUpdate(crc, &tab[0], p) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package crc32_test | ||
|
||
import ( | ||
"hash/crc32" | ||
"testing" | ||
) | ||
|
||
func TestCastagnoli(t *testing.T) { | ||
ieee := NewIEEE() | ||
MakeTable(Castagnoli) | ||
ieee.Write([]byte("hello")) | ||
} |