crc64.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package crc
  2. import (
  3. "hash"
  4. "hash/crc64"
  5. )
  6. // digest represents the partial evaluation of a checksum.
  7. type digest struct {
  8. crc uint64
  9. tab *crc64.Table
  10. }
  11. // NewCRC creates a new hash.Hash64 computing the CRC64 checksum
  12. // using the polynomial represented by the Table.
  13. func NewCRC(tab *crc64.Table, init uint64) hash.Hash64 { return &digest{init, tab} }
  14. var CrcTable = func() *crc64.Table {
  15. return crc64.MakeTable(crc64.ECMA)
  16. }
  17. // Size returns the number of bytes sum will return.
  18. func (d *digest) Size() int { return crc64.Size }
  19. // BlockSize returns the hash's underlying block size.
  20. // The Write method must be able to accept any amount
  21. // of data, but it may operate more efficiently if all writes
  22. // are a multiple of the block size.
  23. func (d *digest) BlockSize() int { return 1 }
  24. // Reset resets the hash to its initial state.
  25. func (d *digest) Reset() { d.crc = 0 }
  26. // Write (via the embedded io.Writer interface) adds more data to the running hash.
  27. // It never returns an error.
  28. func (d *digest) Write(p []byte) (n int, err error) {
  29. d.crc = crc64.Update(d.crc, d.tab, p)
  30. return len(p), nil
  31. }
  32. // Sum64 returns CRC64 value.
  33. func (d *digest) Sum64() uint64 { return d.crc }
  34. // Sum returns hash value.
  35. func (d *digest) Sum(in []byte) []byte {
  36. s := d.Sum64()
  37. 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))
  38. }
  39. // gf2Dim dimension of GF(2) vectors (length of CRC)
  40. const gf2Dim int = 64
  41. func gf2MatrixTimes(mat []uint64, vec uint64) uint64 {
  42. var sum uint64
  43. for i := 0; vec != 0; i++ {
  44. if vec&1 != 0 {
  45. sum ^= mat[i]
  46. }
  47. vec >>= 1
  48. }
  49. return sum
  50. }
  51. func gf2MatrixSquare(square []uint64, mat []uint64) {
  52. for n := 0; n < gf2Dim; n++ {
  53. square[n] = gf2MatrixTimes(mat, mat[n])
  54. }
  55. }
  56. // CRC64Combine combines CRC64
  57. func CRC64Combine(crc1 uint64, crc2 uint64, len2 uint64) uint64 {
  58. var even [gf2Dim]uint64 // Even-power-of-two zeros operator
  59. var odd [gf2Dim]uint64 // Odd-power-of-two zeros operator
  60. // Degenerate case
  61. if len2 == 0 {
  62. return crc1
  63. }
  64. // Put operator for one zero bit in odd
  65. odd[0] = crc64.ECMA // CRC64 polynomial
  66. var row uint64 = 1
  67. for n := 1; n < gf2Dim; n++ {
  68. odd[n] = row
  69. row <<= 1
  70. }
  71. // Put operator for two zero bits in even
  72. gf2MatrixSquare(even[:], odd[:])
  73. // Put operator for four zero bits in odd
  74. gf2MatrixSquare(odd[:], even[:])
  75. // Apply len2 zeros to crc1, first square will put the operator for one zero byte, eight zero bits, in even
  76. for {
  77. // Apply zeros operator for this bit of len2
  78. gf2MatrixSquare(even[:], odd[:])
  79. if len2&1 != 0 {
  80. crc1 = gf2MatrixTimes(even[:], crc1)
  81. }
  82. len2 >>= 1
  83. // If no more bits set, then done
  84. if len2 == 0 {
  85. break
  86. }
  87. // Another iteration of the loop with odd and even swapped
  88. gf2MatrixSquare(odd[:], even[:])
  89. if len2&1 != 0 {
  90. crc1 = gf2MatrixTimes(odd[:], crc1)
  91. }
  92. len2 >>= 1
  93. // If no more bits set, then done
  94. if len2 == 0 {
  95. break
  96. }
  97. }
  98. // Return combined CRC
  99. crc1 ^= crc2
  100. return crc1
  101. }