// 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.

// Package crc64 implements the 64-bit cyclic redundancy check, or CRC-64, // checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for // information.
package crc64 import ( ) // The size of a CRC-64 checksum in bytes. const Size = 8 // Predefined polynomials. const ( // The ISO polynomial, defined in ISO 3309 and used in HDLC. ISO = 0xD800000000000000 // The ECMA polynomial, defined in ECMA 182. ECMA = 0xC96C5795D7870F42 ) // Table is a 256-word table representing the polynomial for efficient processing. type Table [256]uint64 var ( slicing8TablesBuildOnce sync.Once slicing8TableISO *[8]Table slicing8TableECMA *[8]Table ) func buildSlicing8TablesOnce() { slicing8TablesBuildOnce.Do(buildSlicing8Tables) } func buildSlicing8Tables() { slicing8TableISO = makeSlicingBy8Table(makeTable(ISO)) slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA)) } // MakeTable returns a [Table] constructed from the specified polynomial. // The contents of this [Table] must not be modified. func ( uint64) *Table { buildSlicing8TablesOnce() switch { case ISO: return &slicing8TableISO[0] case ECMA: return &slicing8TableECMA[0] default: return makeTable() } } func makeTable( uint64) *Table { := new(Table) for := 0; < 256; ++ { := uint64() for := 0; < 8; ++ { if &1 == 1 { = ( >> 1) ^ } else { >>= 1 } } [] = } return } func makeSlicingBy8Table( *Table) *[8]Table { var [8]Table [0] = * for := 0; < 256; ++ { := [] for := 1; < 8; ++ { = [&0xff] ^ ( >> 8) [][] = } } return & } // digest represents the partial evaluation of a checksum. type digest struct { crc uint64 tab *Table } // New creates a new hash.Hash64 computing the CRC-64 checksum using the // polynomial represented by the [Table]. Its Sum method will lay the // value out in big-endian byte order. The returned Hash64 also // implements [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to // marshal and unmarshal the internal state of the hash. func ( *Table) hash.Hash64 { return &digest{0, } } func ( *digest) () int { return Size } func ( *digest) () int { return 1 } func ( *digest) () { .crc = 0 } const ( magic = "crc\x02" marshaledSize = len(magic) + 8 + 8 ) func ( *digest) () ([]byte, error) { := make([]byte, 0, marshaledSize) = append(, magic...) = appendUint64(, tableSum(.tab)) = appendUint64(, .crc) return , nil } func ( *digest) ( []byte) error { if len() < len(magic) || string([:len(magic)]) != magic { return errors.New("hash/crc64: invalid hash state identifier") } if len() != marshaledSize { return errors.New("hash/crc64: invalid hash state size") } if tableSum(.tab) != readUint64([4:]) { return errors.New("hash/crc64: tables do not match") } .crc = readUint64([12:]) return nil } // appendUint64 is semantically the same as [binary.BigEndian.AppendUint64] // We copied this function because we can not import "encoding/binary" here. func appendUint64( []byte, uint64) []byte { return append(, byte(>>56), byte(>>48), byte(>>40), byte(>>32), byte(>>24), byte(>>16), byte(>>8), byte(), ) } // readUint64 is semantically the same as [binary.BigEndian.Uint64] // We copied this function because we can not import "encoding/binary" here. func readUint64( []byte) uint64 { _ = [7] return uint64([7]) | uint64([6])<<8 | uint64([5])<<16 | uint64([4])<<24 | uint64([3])<<32 | uint64([2])<<40 | uint64([1])<<48 | uint64([0])<<56 } func update( uint64, *Table, []byte) uint64 { buildSlicing8TablesOnce() = ^ // Table comparison is somewhat expensive, so avoid it for small sizes for len() >= 64 { var *[8]Table if * == slicing8TableECMA[0] { = slicing8TableECMA } else if * == slicing8TableISO[0] { = slicing8TableISO // For smaller sizes creating extended table takes too much time } else if len() >= 2048 { // According to the tests between various x86 and arm CPUs, 2k is a reasonable // threshold for now. This may change in the future. = makeSlicingBy8Table() } else { break } // Update using slicing-by-8 for len() > 8 { ^= uint64([0]) | uint64([1])<<8 | uint64([2])<<16 | uint64([3])<<24 | uint64([4])<<32 | uint64([5])<<40 | uint64([6])<<48 | uint64([7])<<56 = [7][&0xff] ^ [6][(>>8)&0xff] ^ [5][(>>16)&0xff] ^ [4][(>>24)&0xff] ^ [3][(>>32)&0xff] ^ [2][(>>40)&0xff] ^ [1][(>>48)&0xff] ^ [0][>>56] = [8:] } } // For reminders or small sizes for , := range { = [byte()^] ^ ( >> 8) } return ^ } // Update returns the result of adding the bytes in p to the crc. func ( uint64, *Table, []byte) uint64 { return update(, , ) } func ( *digest) ( []byte) ( int, error) { .crc = update(.crc, .tab, ) return len(), nil } func ( *digest) () uint64 { return .crc } func ( *digest) ( []byte) []byte { := .Sum64() return append(, byte(>>56), byte(>>48), byte(>>40), byte(>>32), byte(>>24), byte(>>16), byte(>>8), byte()) } // Checksum returns the CRC-64 checksum of data // using the polynomial represented by the [Table]. func ( []byte, *Table) uint64 { return update(0, , ) } // tableSum returns the ISO checksum of table t. func tableSum( *Table) uint64 { var [2048]byte := [:0] if != nil { for , := range { = appendUint64(, ) } } return Checksum(, MakeTable(ISO)) }