1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package blake2s
20
21 import (
22 "encoding/binary"
23 "errors"
24 "hash"
25 )
26
27 const (
28
29 BlockSize = 64
30
31
32 Size = 32
33
34
35 Size128 = 16
36 )
37
38 var errKeySize = errors.New("blake2s: invalid key size")
39
40 var iv = [8]uint32{
41 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
42 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
43 }
44
45
46 func Sum256(data []byte) [Size]byte {
47 var sum [Size]byte
48 checkSum(&sum, Size, data)
49 return sum
50 }
51
52
53
54
55
56 func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
57
58
59
60
61
62 func New128(key []byte) (hash.Hash, error) {
63 if len(key) == 0 {
64 return nil, errors.New("blake2s: a key is required for a 128-bit hash")
65 }
66 return newDigest(Size128, key)
67 }
68
69 func newDigest(hashSize int, key []byte) (*digest, error) {
70 if len(key) > Size {
71 return nil, errKeySize
72 }
73 d := &digest{
74 size: hashSize,
75 keyLen: len(key),
76 }
77 copy(d.key[:], key)
78 d.Reset()
79 return d, nil
80 }
81
82 func checkSum(sum *[Size]byte, hashSize int, data []byte) {
83 var (
84 h [8]uint32
85 c [2]uint32
86 )
87
88 h = iv
89 h[0] ^= uint32(hashSize) | (1 << 16) | (1 << 24)
90
91 if length := len(data); length > BlockSize {
92 n := length &^ (BlockSize - 1)
93 if length == n {
94 n -= BlockSize
95 }
96 hashBlocks(&h, &c, 0, data[:n])
97 data = data[n:]
98 }
99
100 var block [BlockSize]byte
101 offset := copy(block[:], data)
102 remaining := uint32(BlockSize - offset)
103
104 if c[0] < remaining {
105 c[1]--
106 }
107 c[0] -= remaining
108
109 hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
110
111 for i, v := range h {
112 binary.LittleEndian.PutUint32(sum[4*i:], v)
113 }
114 }
115
116 type digest struct {
117 h [8]uint32
118 c [2]uint32
119 size int
120 block [BlockSize]byte
121 offset int
122
123 key [BlockSize]byte
124 keyLen int
125 }
126
127 const (
128 magic = "b2s"
129 marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1
130 )
131
132 func (d *digest) MarshalBinary() ([]byte, error) {
133 if d.keyLen != 0 {
134 return nil, errors.New("crypto/blake2s: cannot marshal MACs")
135 }
136 b := make([]byte, 0, marshaledSize)
137 b = append(b, magic...)
138 for i := 0; i < 8; i++ {
139 b = appendUint32(b, d.h[i])
140 }
141 b = appendUint32(b, d.c[0])
142 b = appendUint32(b, d.c[1])
143
144 b = append(b, byte(d.size))
145 b = append(b, d.block[:]...)
146 b = append(b, byte(d.offset))
147 return b, nil
148 }
149
150 func (d *digest) UnmarshalBinary(b []byte) error {
151 if len(b) < len(magic) || string(b[:len(magic)]) != magic {
152 return errors.New("crypto/blake2s: invalid hash state identifier")
153 }
154 if len(b) != marshaledSize {
155 return errors.New("crypto/blake2s: invalid hash state size")
156 }
157 b = b[len(magic):]
158 for i := 0; i < 8; i++ {
159 b, d.h[i] = consumeUint32(b)
160 }
161 b, d.c[0] = consumeUint32(b)
162 b, d.c[1] = consumeUint32(b)
163 d.size = int(b[0])
164 b = b[1:]
165 copy(d.block[:], b[:BlockSize])
166 b = b[BlockSize:]
167 d.offset = int(b[0])
168 return nil
169 }
170
171 func (d *digest) BlockSize() int { return BlockSize }
172
173 func (d *digest) Size() int { return d.size }
174
175 func (d *digest) Reset() {
176 d.h = iv
177 d.h[0] ^= uint32(d.size) | (uint32(d.keyLen) << 8) | (1 << 16) | (1 << 24)
178 d.offset, d.c[0], d.c[1] = 0, 0, 0
179 if d.keyLen > 0 {
180 d.block = d.key
181 d.offset = BlockSize
182 }
183 }
184
185 func (d *digest) Write(p []byte) (n int, err error) {
186 n = len(p)
187
188 if d.offset > 0 {
189 remaining := BlockSize - d.offset
190 if n <= remaining {
191 d.offset += copy(d.block[d.offset:], p)
192 return
193 }
194 copy(d.block[d.offset:], p[:remaining])
195 hashBlocks(&d.h, &d.c, 0, d.block[:])
196 d.offset = 0
197 p = p[remaining:]
198 }
199
200 if length := len(p); length > BlockSize {
201 nn := length &^ (BlockSize - 1)
202 if length == nn {
203 nn -= BlockSize
204 }
205 hashBlocks(&d.h, &d.c, 0, p[:nn])
206 p = p[nn:]
207 }
208
209 d.offset += copy(d.block[:], p)
210 return
211 }
212
213 func (d *digest) Sum(sum []byte) []byte {
214 var hash [Size]byte
215 d.finalize(&hash)
216 return append(sum, hash[:d.size]...)
217 }
218
219 func (d *digest) finalize(hash *[Size]byte) {
220 var block [BlockSize]byte
221 h := d.h
222 c := d.c
223
224 copy(block[:], d.block[:d.offset])
225 remaining := uint32(BlockSize - d.offset)
226 if c[0] < remaining {
227 c[1]--
228 }
229 c[0] -= remaining
230
231 hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
232 for i, v := range h {
233 binary.LittleEndian.PutUint32(hash[4*i:], v)
234 }
235 }
236
237 func appendUint32(b []byte, x uint32) []byte {
238 var a [4]byte
239 binary.BigEndian.PutUint32(a[:], x)
240 return append(b, a[:]...)
241 }
242
243 func consumeUint32(b []byte) ([]byte, uint32) {
244 x := binary.BigEndian.Uint32(b)
245 return b[4:], x
246 }
247
View as plain text