github.com/aliyun/aliyun-oss-go-sdk@v3.0.2+incompatible/oss/crc.go (about)

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