github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/hash/crc64/crc64.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package crc64 implements the 64-bit cyclic redundancy check, or CRC-64,
     6  // checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for
     7  // information.
     8  package crc64
     9  
    10  import (
    11  	"errors"
    12  	"hash"
    13  )
    14  
    15  // The size of a CRC-64 checksum in bytes.
    16  const Size = 8
    17  
    18  // Predefined polynomials.
    19  const (
    20  	// The ISO polynomial, defined in ISO 3309 and used in HDLC.
    21  	ISO = 0xD800000000000000
    22  
    23  	// The ECMA polynomial, defined in ECMA 182.
    24  	ECMA = 0xC96C5795D7870F42
    25  )
    26  
    27  // Table is a 256-word table representing the polynomial for efficient processing.
    28  type Table [256]uint64
    29  
    30  var (
    31  	slicing8TableISO  = makeSlicingBy8Table(makeTable(ISO))
    32  	slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA))
    33  )
    34  
    35  // MakeTable returns a Table constructed from the specified polynomial.
    36  // The contents of this Table must not be modified.
    37  func MakeTable(poly uint64) *Table {
    38  	switch poly {
    39  	case ISO:
    40  		return &slicing8TableISO[0]
    41  	case ECMA:
    42  		return &slicing8TableECMA[0]
    43  	default:
    44  		return makeTable(poly)
    45  	}
    46  }
    47  
    48  func makeTable(poly uint64) *Table {
    49  	t := new(Table)
    50  	for i := 0; i < 256; i++ {
    51  		crc := uint64(i)
    52  		for j := 0; j < 8; j++ {
    53  			if crc&1 == 1 {
    54  				crc = (crc >> 1) ^ poly
    55  			} else {
    56  				crc >>= 1
    57  			}
    58  		}
    59  		t[i] = crc
    60  	}
    61  	return t
    62  }
    63  
    64  func makeSlicingBy8Table(t *Table) *[8]Table {
    65  	var helperTable [8]Table
    66  	helperTable[0] = *t
    67  	for i := 0; i < 256; i++ {
    68  		crc := t[i]
    69  		for j := 1; j < 8; j++ {
    70  			crc = t[crc&0xff] ^ (crc >> 8)
    71  			helperTable[j][i] = crc
    72  		}
    73  	}
    74  	return &helperTable
    75  }
    76  
    77  // digest represents the partial evaluation of a checksum.
    78  type digest struct {
    79  	crc uint64
    80  	tab *Table
    81  }
    82  
    83  // New creates a new hash.Hash64 computing the CRC-64 checksum
    84  // using the polynomial represented by the Table.
    85  // Its Sum method will lay the value out in big-endian byte order.
    86  func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
    87  
    88  func (d *digest) Size() int { return Size }
    89  
    90  func (d *digest) BlockSize() int { return 1 }
    91  
    92  func (d *digest) Reset() { d.crc = 0 }
    93  
    94  const (
    95  	magic         = "crc\x02"
    96  	marshaledSize = len(magic) + 8 + 8
    97  )
    98  
    99  func (d *digest) MarshalBinary() ([]byte, error) {
   100  	b := make([]byte, 0, marshaledSize)
   101  	b = append(b, magic...)
   102  	b = appendUint64(b, tableSum(d.tab))
   103  	b = appendUint64(b, d.crc)
   104  	return b, nil
   105  }
   106  
   107  func (d *digest) UnmarshalBinary(b []byte) error {
   108  	if len(b) < len(magic) || string(b[:len(magic)]) != magic {
   109  		return errors.New("hash/crc64: invalid hash state identifier")
   110  	}
   111  	if len(b) != marshaledSize {
   112  		return errors.New("hash/crc64: invalid hash state size")
   113  	}
   114  	if tableSum(d.tab) != readUint64(b[4:]) {
   115  		return errors.New("hash/crc64: tables do not match")
   116  	}
   117  	d.crc = readUint64(b[12:])
   118  	return nil
   119  }
   120  
   121  func appendUint64(b []byte, x uint64) []byte {
   122  	a := [8]byte{
   123  		byte(x >> 56),
   124  		byte(x >> 48),
   125  		byte(x >> 40),
   126  		byte(x >> 32),
   127  		byte(x >> 24),
   128  		byte(x >> 16),
   129  		byte(x >> 8),
   130  		byte(x),
   131  	}
   132  	return append(b, a[:]...)
   133  }
   134  
   135  func readUint64(b []byte) uint64 {
   136  	_ = b[7]
   137  	return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
   138  		uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
   139  }
   140  
   141  func update(crc uint64, tab *Table, p []byte) uint64 {
   142  	crc = ^crc
   143  	// Table comparison is somewhat expensive, so avoid it for small sizes
   144  	for len(p) >= 64 {
   145  		var helperTable *[8]Table
   146  		if *tab == slicing8TableECMA[0] {
   147  			helperTable = slicing8TableECMA
   148  		} else if *tab == slicing8TableISO[0] {
   149  			helperTable = slicing8TableISO
   150  			// For smaller sizes creating extended table takes too much time
   151  		} else if len(p) > 16384 {
   152  			helperTable = makeSlicingBy8Table(tab)
   153  		} else {
   154  			break
   155  		}
   156  		// Update using slicing-by-8
   157  		for len(p) > 8 {
   158  			crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 |
   159  				uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
   160  			crc = helperTable[7][crc&0xff] ^
   161  				helperTable[6][(crc>>8)&0xff] ^
   162  				helperTable[5][(crc>>16)&0xff] ^
   163  				helperTable[4][(crc>>24)&0xff] ^
   164  				helperTable[3][(crc>>32)&0xff] ^
   165  				helperTable[2][(crc>>40)&0xff] ^
   166  				helperTable[1][(crc>>48)&0xff] ^
   167  				helperTable[0][crc>>56]
   168  			p = p[8:]
   169  		}
   170  	}
   171  	// For reminders or small sizes
   172  	for _, v := range p {
   173  		crc = tab[byte(crc)^v] ^ (crc >> 8)
   174  	}
   175  	return ^crc
   176  }
   177  
   178  // Update returns the result of adding the bytes in p to the crc.
   179  func Update(crc uint64, tab *Table, p []byte) uint64 {
   180  	return update(crc, tab, p)
   181  }
   182  
   183  func (d *digest) Write(p []byte) (n int, err error) {
   184  	d.crc = update(d.crc, d.tab, p)
   185  	return len(p), nil
   186  }
   187  
   188  func (d *digest) Sum64() uint64 { return d.crc }
   189  
   190  func (d *digest) Sum(in []byte) []byte {
   191  	s := d.Sum64()
   192  	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))
   193  }
   194  
   195  // Checksum returns the CRC-64 checksum of data
   196  // using the polynomial represented by the Table.
   197  func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) }
   198  
   199  // tableSum returns the ISO checksum of table t.
   200  func tableSum(t *Table) uint64 {
   201  	var a [2048]byte
   202  	b := a[:0]
   203  	if t != nil {
   204  		for _, x := range t {
   205  			b = appendUint64(b, x)
   206  		}
   207  	}
   208  	return Checksum(b, MakeTable(ISO))
   209  }