// Package crc64 implements the Avro CRC-64 checksum. // See https://avro.apache.org/docs/current/spec.html#schema_fingerprints for information.
package crc64 import ( ) func init() { buildTable() } // Size is the of a CRC-64 checksum in bytes. const Size = 8 // ByteOrder denotes how integers are encoded into bytes. The ByteOrder // interface in encoding/binary cancels some optimizations, so use a more // direct implementation. type ByteOrder int // ByteOrder constants. const ( LittleEndian ByteOrder = iota BigEndian ) // Empty is the empty checksum. const Empty = 0xc15d213aa4d7a795 // Table is a 256-word table representing the polynomial for efficient processing. type Table [256]uint64 func makeTable() *Table { := new(Table) for := range 256 { := uint64() for range 8 { = ( >> 1) ^ (Empty & -( & 1)) } [] = } return } var crc64Table *Table func buildTable() { crc64Table = makeTable() } type digest struct { crc uint64 tab *Table byteOrder ByteOrder } // New creates a new hash.Hash64 computing the Avro CRC-64 checksum. // Its Sum method will lay the value out in big-endian byte order. func () hash.Hash64 { return newDigest(BigEndian) } // NewWithByteOrder creates a new hash.Hash64 computing the Avro CRC-64 // checksum. Its Sum method will lay the value out in specified byte order. func ( ByteOrder) hash.Hash64 { return newDigest() } func newDigest( ByteOrder) *digest { return &digest{ crc: Empty, tab: crc64Table, byteOrder: , } } // Size returns the bytes size of the checksum. func ( *digest) () int { return Size } // BlockSize returns the block size of the checksum. func ( *digest) () int { return 1 } // Reset resets the hash instance. func ( *digest) () { .crc = Empty } // Write accumulatively adds the given data to the checksum. func ( *digest) ( []byte) ( int, error) { for := range { .crc = (.crc >> 8) ^ .tab[(int)(byte(.crc)^[])&0xff] } return len(), nil } // Sum64 returns the checksum as a uint64. func ( *digest) () uint64 { return .crc } // Sum returns the checksum as a byte slice, using the given byte slice. func ( *digest) ( []byte) []byte { := .sumBytes() return append(, [:]...) } // sumBytes returns the checksum as a byte array in digest byte order. func ( *digest) () [Size]byte { := .Sum64() switch .byteOrder { case LittleEndian: return [Size]byte{ byte(), byte( >> 8), byte( >> 16), byte( >> 24), byte( >> 32), byte( >> 40), byte( >> 48), byte( >> 56), } case BigEndian: return [Size]byte{ byte( >> 56), byte( >> 48), byte( >> 40), byte( >> 32), byte( >> 24), byte( >> 16), byte( >> 8), byte(), } } panic("unknown byte order") } // Sum returns the CRC64 checksum of the data, in big-endian byte order. func ( []byte) [Size]byte { return SumWithByteOrder(, BigEndian) } // SumWithByteOrder returns the CRC64 checksum of the data, in specified byte // order. func ( []byte, ByteOrder) [Size]byte { := newDigest() _, _ = .Write() return .sumBytes() }