crc.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package tos
  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 is similar with crc64.New, but you can set the initial value.
  12. // Following methods are copied from package crc64 to implement Hash interface.
  13. func NewCRC(tab *crc64.Table, init uint64) hash.Hash64 { return &digest{init, tab} }
  14. func (d *digest) Size() int { return crc64.Size }
  15. func (d *digest) BlockSize() int { return 1 }
  16. func (d *digest) Reset() { d.crc = 0 }
  17. func (d *digest) Write(p []byte) (n int, err error) {
  18. d.crc = crc64.Update(d.crc, d.tab, p)
  19. return len(p), nil
  20. }
  21. func (d *digest) Sum64() uint64 { return d.crc }
  22. func (d *digest) Sum(in []byte) []byte {
  23. s := d.Sum64()
  24. 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))
  25. }
  26. // gf2Dim dimension of GF(2) vectors (length of CRC)
  27. const gf2Dim int = 64
  28. func gf2MatrixTimes(mat []uint64, vec uint64) uint64 {
  29. var sum uint64
  30. for i := 0; vec != 0; i++ {
  31. if vec&1 != 0 {
  32. sum ^= mat[i]
  33. }
  34. vec >>= 1
  35. }
  36. return sum
  37. }
  38. func gf2MatrixSquare(square []uint64, mat []uint64) {
  39. for n := 0; n < gf2Dim; n++ {
  40. square[n] = gf2MatrixTimes(mat, mat[n])
  41. }
  42. }
  43. // CRC64Combine combines CRC64
  44. func CRC64Combine(crc1 uint64, crc2 uint64, len2 uint64) uint64 {
  45. var even [gf2Dim]uint64 // Even-power-of-two zeros operator
  46. var odd [gf2Dim]uint64 // Odd-power-of-two zeros operator
  47. // Degenerate case
  48. if len2 == 0 {
  49. return crc1
  50. }
  51. // Put operator for one zero bit in odd
  52. odd[0] = crc64.ECMA // CRC64 polynomial
  53. var row uint64 = 1
  54. for n := 1; n < gf2Dim; n++ {
  55. odd[n] = row
  56. row <<= 1
  57. }
  58. // Put operator for two zero bits in even
  59. gf2MatrixSquare(even[:], odd[:])
  60. // Put operator for four zero bits in odd
  61. gf2MatrixSquare(odd[:], even[:])
  62. // Apply len2 zeros to crc1, first square will put the operator for one zero byte, eight zero bits, in even
  63. for {
  64. // Apply zeros operator for this bit of len2
  65. gf2MatrixSquare(even[:], odd[:])
  66. if len2&1 != 0 {
  67. crc1 = gf2MatrixTimes(even[:], crc1)
  68. }
  69. len2 >>= 1
  70. // If no more bits set, then done
  71. if len2 == 0 {
  72. break
  73. }
  74. // Another iteration of the loop with odd and even swapped
  75. gf2MatrixSquare(odd[:], even[:])
  76. if len2&1 != 0 {
  77. crc1 = gf2MatrixTimes(odd[:], crc1)
  78. }
  79. len2 >>= 1
  80. // If no more bits set, then done
  81. if len2 == 0 {
  82. break
  83. }
  84. }
  85. // Return combined CRC
  86. crc1 ^= crc2
  87. return crc1
  88. }