-
Notifications
You must be signed in to change notification settings - Fork 19
/
hash.go
116 lines (96 loc) · 2.62 KB
/
hash.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package crc16
import (
"errors"
"hash"
)
// Hash16 is the common interface implemented by all 16-bit hash functions.
type Hash16 interface {
hash.Hash
Sum16() uint16
}
// New creates a new Hash16 computing the CRC-16 checksum
// using the polynomial represented by the Table.
func New(tab *Table) Hash16 { return &digest{0, tab} }
// NewIBM creates a new Hash16 computing the CRC-16 checksum
// using the IBM polynomial.
func NewIBM() Hash16 { return New(IBMTable) }
// NewCCITT creates a new hash.Hash16 computing the CRC-16 checksum
// using the CCITT polynomial.
func NewCCITT() Hash16 { return New(CCITTTable) }
// NewSCSI creates a new Hash16 computing the CRC-16 checksum
// using the SCSI polynomial.
func NewSCSI() Hash16 { return New(SCSITable) }
// digest represents the partial evaluation of a checksum.
type digest struct {
crc uint16
tab *Table
}
func (d *digest) Size() int { return 2 }
func (d *digest) BlockSize() int { return 1 }
func (d *digest) Reset() { d.crc = 0 }
func (d *digest) Write(p []byte) (n int, err error) {
d.crc = Update(d.crc, d.tab, p)
return len(p), nil
}
func (d *digest) Sum16() uint16 { return d.crc }
func (d *digest) Sum(in []byte) []byte {
s := d.Sum16()
return append(in, byte(s>>8), byte(s))
}
const (
magic = "crc16\x01"
marshaledSize = len(magic) + 2 + 2 + 1
)
func (d *digest) MarshalBinary() ([]byte, error) {
b := make([]byte, 0, marshaledSize)
b = append(b, magic...)
b = appendUint16(b, tableSum(d.tab))
b = appendUint16(b, d.crc)
if d.tab.reversed {
b = append(b, byte(0x01))
} else {
b = append(b, byte(0x00))
}
return b, nil
}
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
return errors.New("hash/crc16: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("hash/crc16: invalid hash state size")
}
if tableSum(d.tab) != readUint16(b[6:]) {
return errors.New("hash/crc16: tables do not match")
}
d.crc = readUint16(b[8:])
if b[10] == 0x01 {
d.tab.reversed = true
}
return nil
}
func appendUint16(b []byte, x uint16) []byte {
a := [2]byte{
byte(x >> 8),
byte(x),
}
return append(b, a[:]...)
}
func readUint16(b []byte) uint16 {
_ = b[1]
return uint16(b[1]) | uint16(b[0])<<8
}
// tableSum returns the IBM checksum of table t.
func tableSum(t *Table) uint16 {
var a [1024]byte
b := a[:0]
if t != nil {
for _, x := range t.entries {
b = appendUint16(b, x)
}
}
return ChecksumIBM(b)
}