github.com/aacfactory/avro@v1.2.12/internal/hashs/crc64/crc64.go (about)

     1  package crc64
     2  
     3  import (
     4  	"hash"
     5  	"sync"
     6  )
     7  
     8  // Size is the of a CRC-64 checksum in bytes.
     9  const Size = 8
    10  
    11  // Empty is the empty checksum.
    12  const Empty = 0xc15d213aa4d7a795
    13  
    14  // Table is a 256-word table representing the polynomial for efficient processing.
    15  type Table [256]uint64
    16  
    17  func makeTable() *Table {
    18  	t := new(Table)
    19  	for i := 0; i < 256; i++ {
    20  		fp := uint64(i)
    21  		for j := 0; j < 8; j++ {
    22  			fp = (fp >> 1) ^ (Empty & -(fp & 1))
    23  		}
    24  		t[i] = fp
    25  	}
    26  	return t
    27  }
    28  
    29  var (
    30  	tableBuildOnce sync.Once
    31  	crc64Table     *Table
    32  )
    33  
    34  func buildTableOnce() {
    35  	tableBuildOnce.Do(buildTable)
    36  }
    37  
    38  func buildTable() {
    39  	crc64Table = makeTable()
    40  }
    41  
    42  type digest struct {
    43  	crc uint64
    44  	tab *Table
    45  }
    46  
    47  // New creates a new hash.Hash64 computing the Avro CRC-64 checksum.
    48  // Its Sum method will lay the value out in big-endian byte order.
    49  func New() hash.Hash64 {
    50  	buildTableOnce()
    51  
    52  	return &digest{
    53  		crc: Empty,
    54  		tab: crc64Table,
    55  	}
    56  }
    57  
    58  // Size returns the bytes size of the checksum.
    59  func (d *digest) Size() int {
    60  	return Size
    61  }
    62  
    63  // BlockSize returns the block size of the checksum.
    64  func (d *digest) BlockSize() int {
    65  	return 1
    66  }
    67  
    68  // Reset resets the hash instance.
    69  func (d *digest) Reset() {
    70  	d.crc = Empty
    71  }
    72  
    73  // Write accumulatively adds the given data to the checksum.
    74  func (d *digest) Write(p []byte) (n int, err error) {
    75  	for i := 0; i < len(p); i++ {
    76  		d.crc = (d.crc >> 8) ^ d.tab[(int)(byte(d.crc)^p[i])&0xff]
    77  	}
    78  
    79  	return len(p), nil
    80  }
    81  
    82  // Sum64 returns the checksum as a uint64.
    83  func (d *digest) Sum64() uint64 {
    84  	return d.crc
    85  }
    86  
    87  // Sum returns the checksum as a byte slice, using the given byte slice.
    88  func (d *digest) Sum(in []byte) []byte {
    89  	s := d.Sum64()
    90  	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))
    91  }