package crc64
import (
"errors"
"hash"
"internal/byteorder"
"sync"
)
const Size = 8
const (
ISO = 0xD800000000000000
ECMA = 0xC96C5795D7870F42
)
type Table [256 ]uint64
var (
slicing8TableISO *[8 ]Table
slicing8TableECMA *[8 ]Table
)
var buildSlicing8TablesOnce = sync .OnceFunc (buildSlicing8Tables )
func buildSlicing8Tables() {
slicing8TableISO = makeSlicingBy8Table (makeTable (ISO ))
slicing8TableECMA = makeSlicingBy8Table (makeTable (ECMA ))
}
func MakeTable (poly uint64 ) *Table {
buildSlicing8TablesOnce ()
switch poly {
case ISO :
return &slicing8TableISO [0 ]
case ECMA :
return &slicing8TableECMA [0 ]
default :
return makeTable (poly )
}
}
func makeTable(poly uint64 ) *Table {
t := new (Table )
for i := 0 ; i < 256 ; i ++ {
crc := uint64 (i )
for j := 0 ; j < 8 ; j ++ {
if crc &1 == 1 {
crc = (crc >> 1 ) ^ poly
} else {
crc >>= 1
}
}
t [i ] = crc
}
return t
}
func makeSlicingBy8Table(t *Table ) *[8 ]Table {
var helperTable [8 ]Table
helperTable [0 ] = *t
for i := 0 ; i < 256 ; i ++ {
crc := t [i ]
for j := 1 ; j < 8 ; j ++ {
crc = t [crc &0xff ] ^ (crc >> 8 )
helperTable [j ][i ] = crc
}
}
return &helperTable
}
type digest struct {
crc uint64
tab *Table
}
func New (tab *Table ) hash .Hash64 { return &digest {0 , tab } }
func (d *digest ) Size () int { return Size }
func (d *digest ) BlockSize () int { return 1 }
func (d *digest ) Reset () { d .crc = 0 }
const (
magic = "crc\x02"
marshaledSize = len (magic ) + 8 + 8
)
func (d *digest ) AppendBinary (b []byte ) ([]byte , error ) {
b = append (b , magic ...)
b = byteorder .BEAppendUint64 (b , tableSum (d .tab ))
b = byteorder .BEAppendUint64 (b , d .crc )
return b , nil
}
func (d *digest ) MarshalBinary () ([]byte , error ) {
return d .AppendBinary (make ([]byte , 0 , marshaledSize ))
}
func (d *digest ) UnmarshalBinary (b []byte ) error {
if len (b ) < len (magic ) || string (b [:len (magic )]) != magic {
return errors .New ("hash/crc64: invalid hash state identifier" )
}
if len (b ) != marshaledSize {
return errors .New ("hash/crc64: invalid hash state size" )
}
if tableSum (d .tab ) != byteorder .BEUint64 (b [4 :]) {
return errors .New ("hash/crc64: tables do not match" )
}
d .crc = byteorder .BEUint64 (b [12 :])
return nil
}
func (d *digest ) Clone () (hash .Cloner , error ) {
r := *d
return &r , nil
}
func update(crc uint64 , tab *Table , p []byte ) uint64 {
buildSlicing8TablesOnce ()
crc = ^crc
for len (p ) >= 64 {
var helperTable *[8 ]Table
if *tab == slicing8TableECMA [0 ] {
helperTable = slicing8TableECMA
} else if *tab == slicing8TableISO [0 ] {
helperTable = slicing8TableISO
} else if len (p ) >= 2048 {
helperTable = makeSlicingBy8Table (tab )
} else {
break
}
for len (p ) > 8 {
crc ^= byteorder .LEUint64 (p )
crc = helperTable [7 ][crc &0xff ] ^
helperTable [6 ][(crc >>8 )&0xff ] ^
helperTable [5 ][(crc >>16 )&0xff ] ^
helperTable [4 ][(crc >>24 )&0xff ] ^
helperTable [3 ][(crc >>32 )&0xff ] ^
helperTable [2 ][(crc >>40 )&0xff ] ^
helperTable [1 ][(crc >>48 )&0xff ] ^
helperTable [0 ][crc >>56 ]
p = p [8 :]
}
}
for _ , v := range p {
crc = tab [byte (crc )^v ] ^ (crc >> 8 )
}
return ^crc
}
func Update (crc uint64 , tab *Table , p []byte ) uint64 {
return update (crc , tab , p )
}
func (d *digest ) Write (p []byte ) (n int , err error ) {
d .crc = update (d .crc , d .tab , p )
return len (p ), nil
}
func (d *digest ) Sum64 () uint64 { return d .crc }
func (d *digest ) Sum (in []byte ) []byte {
s := d .Sum64 ()
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 ))
}
func Checksum (data []byte , tab *Table ) uint64 { return update (0 , tab , data ) }
func tableSum(t *Table ) uint64 {
var a [2048 ]byte
b := a [:0 ]
if t != nil {
for _ , x := range t {
b = byteorder .BEAppendUint64 (b , x )
}
}
return Checksum (b , MakeTable (ISO ))
}
The pages are generated with Golds v0.7.7-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .