github.com/hamba/avro@v1.8.0/pkg/crc64/crc64.go (about)

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