crc.go 2.9 KB

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