github.com/s1s1ty/go@v0.0.0-20180207192209-104445e3140f/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 using the
    84  // polynomial represented by the Table. Its Sum method will lay the
    85  // value out in big-endian byte order. The returned Hash64 also
    86  // implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
    87  // marshal and unmarshal the internal state of the hash.
    88  func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
    89  
    90  func (d *digest) Size() int { return Size }
    91  
    92  func (d *digest) BlockSize() int { return 1 }
    93  
    94  func (d *digest) Reset() { d.crc = 0 }
    95  
    96  const (
    97  	magic         = "crc\x02"
    98  	marshaledSize = len(magic) + 8 + 8
    99  )
   100  
   101  func (d *digest) MarshalBinary() ([]byte, error) {
   102  	b := make([]byte, 0, marshaledSize)
   103  	b = append(b, magic...)
   104  	b = appendUint64(b, tableSum(d.tab))
   105  	b = appendUint64(b, d.crc)
   106  	return b, nil
   107  }
   108  
   109  func (d *digest) UnmarshalBinary(b []byte) error {
   110  	if len(b) < len(magic) || string(b[:len(magic)]) != magic {
   111  		return errors.New("hash/crc64: invalid hash state identifier")
   112  	}
   113  	if len(b) != marshaledSize {
   114  		return errors.New("hash/crc64: invalid hash state size")
   115  	}
   116  	if tableSum(d.tab) != readUint64(b[4:]) {
   117  		return errors.New("hash/crc64: tables do not match")
   118  	}
   119  	d.crc = readUint64(b[12:])
   120  	return nil
   121  }
   122  
   123  func appendUint64(b []byte, x uint64) []byte {
   124  	a := [8]byte{
   125  		byte(x >> 56),
   126  		byte(x >> 48),
   127  		byte(x >> 40),
   128  		byte(x >> 32),
   129  		byte(x >> 24),
   130  		byte(x >> 16),
   131  		byte(x >> 8),
   132  		byte(x),
   133  	}
   134  	return append(b, a[:]...)
   135  }
   136  
   137  func readUint64(b []byte) uint64 {
   138  	_ = b[7]
   139  	return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
   140  		uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
   141  }
   142  
   143  func update(crc uint64, tab *Table, p []byte) uint64 {
   144  	crc = ^crc
   145  	// Table comparison is somewhat expensive, so avoid it for small sizes
   146  	for len(p) >= 64 {
   147  		var helperTable *[8]Table
   148  		if *tab == slicing8TableECMA[0] {
   149  			helperTable = slicing8TableECMA
   150  		} else if *tab == slicing8TableISO[0] {
   151  			helperTable = slicing8TableISO
   152  			// For smaller sizes creating extended table takes too much time
   153  		} else if len(p) > 16384 {
   154  			helperTable = makeSlicingBy8Table(tab)
   155  		} else {
   156  			break
   157  		}
   158  		// Update using slicing-by-8
   159  		for len(p) > 8 {
   160  			crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 |
   161  				uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
   162  			crc = helperTable[7][crc&0xff] ^
   163  				helperTable[6][(crc>>8)&0xff] ^
   164  				helperTable[5][(crc>>16)&0xff] ^
   165  				helperTable[4][(crc>>24)&0xff] ^
   166  				helperTable[3][(crc>>32)&0xff] ^
   167  				helperTable[2][(crc>>40)&0xff] ^
   168  				helperTable[1][(crc>>48)&0xff] ^
   169  				helperTable[0][crc>>56]
   170  			p = p[8:]
   171  		}
   172  	}
   173  	// For reminders or small sizes
   174  	for _, v := range p {
   175  		crc = tab[byte(crc)^v] ^ (crc >> 8)
   176  	}
   177  	return ^crc
   178  }
   179  
   180  // Update returns the result of adding the bytes in p to the crc.
   181  func Update(crc uint64, tab *Table, p []byte) uint64 {
   182  	return update(crc, tab, p)
   183  }
   184  
   185  func (d *digest) Write(p []byte) (n int, err error) {
   186  	d.crc = update(d.crc, d.tab, p)
   187  	return len(p), nil
   188  }
   189  
   190  func (d *digest) Sum64() uint64 { return d.crc }
   191  
   192  func (d *digest) Sum(in []byte) []byte {
   193  	s := d.Sum64()
   194  	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))
   195  }
   196  
   197  // Checksum returns the CRC-64 checksum of data
   198  // using the polynomial represented by the Table.
   199  func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) }
   200  
   201  // tableSum returns the ISO checksum of table t.
   202  func tableSum(t *Table) uint64 {
   203  	var a [2048]byte
   204  	b := a[:0]
   205  	if t != nil {
   206  		for _, x := range t {
   207  			b = appendUint64(b, x)
   208  		}
   209  	}
   210  	return Checksum(b, MakeTable(ISO))
   211  }