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