blake2b.go (7503B)
1 // Copyright 2016 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 blake2b implements the BLAKE2b hash algorithm defined by RFC 7693 6 // and the extendable output function (XOF) BLAKE2Xb. 7 // 8 // BLAKE2b is optimized for 64-bit platforms—including NEON-enabled ARMs—and 9 // produces digests of any size between 1 and 64 bytes. 10 // For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf 11 // and for BLAKE2Xb see https://blake2.net/blake2x.pdf 12 // 13 // If you aren't sure which function you need, use BLAKE2b (Sum512 or New512). 14 // If you need a secret-key MAC (message authentication code), use the New512 15 // function with a non-nil key. 16 // 17 // BLAKE2X is a construction to compute hash values larger than 64 bytes. It 18 // can produce hash values between 0 and 4 GiB. 19 package blake2b 20 21 import ( 22 "encoding/binary" 23 "errors" 24 "hash" 25 ) 26 27 const ( 28 // The blocksize of BLAKE2b in bytes. 29 BlockSize = 128 30 // The hash size of BLAKE2b-512 in bytes. 31 Size = 64 32 // The hash size of BLAKE2b-384 in bytes. 33 Size384 = 48 34 // The hash size of BLAKE2b-256 in bytes. 35 Size256 = 32 36 ) 37 38 var ( 39 useAVX2 bool 40 useAVX bool 41 useSSE4 bool 42 ) 43 44 var ( 45 errKeySize = errors.New("blake2b: invalid key size") 46 errHashSize = errors.New("blake2b: invalid hash size") 47 ) 48 49 var iv = [8]uint64{ 50 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 51 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, 52 } 53 54 // Sum512 returns the BLAKE2b-512 checksum of the data. 55 func Sum512(data []byte) [Size]byte { 56 var sum [Size]byte 57 checkSum(&sum, Size, data) 58 return sum 59 } 60 61 // Sum384 returns the BLAKE2b-384 checksum of the data. 62 func Sum384(data []byte) [Size384]byte { 63 var sum [Size]byte 64 var sum384 [Size384]byte 65 checkSum(&sum, Size384, data) 66 copy(sum384[:], sum[:Size384]) 67 return sum384 68 } 69 70 // Sum256 returns the BLAKE2b-256 checksum of the data. 71 func Sum256(data []byte) [Size256]byte { 72 var sum [Size]byte 73 var sum256 [Size256]byte 74 checkSum(&sum, Size256, data) 75 copy(sum256[:], sum[:Size256]) 76 return sum256 77 } 78 79 // New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil 80 // key turns the hash into a MAC. The key must be between zero and 64 bytes long. 81 func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) } 82 83 // New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil 84 // key turns the hash into a MAC. The key must be between zero and 64 bytes long. 85 func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) } 86 87 // New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil 88 // key turns the hash into a MAC. The key must be between zero and 64 bytes long. 89 func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) } 90 91 // New returns a new hash.Hash computing the BLAKE2b checksum with a custom length. 92 // A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long. 93 // The hash size can be a value between 1 and 64 but it is highly recommended to use 94 // values equal or greater than: 95 // - 32 if BLAKE2b is used as a hash function (The key is zero bytes long). 96 // - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long). 97 // When the key is nil, the returned hash.Hash implements BinaryMarshaler 98 // and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash. 99 func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) } 100 101 func newDigest(hashSize int, key []byte) (*digest, error) { 102 if hashSize < 1 || hashSize > Size { 103 return nil, errHashSize 104 } 105 if len(key) > Size { 106 return nil, errKeySize 107 } 108 d := &digest{ 109 size: hashSize, 110 keyLen: len(key), 111 } 112 copy(d.key[:], key) 113 d.Reset() 114 return d, nil 115 } 116 117 func checkSum(sum *[Size]byte, hashSize int, data []byte) { 118 h := iv 119 h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24) 120 var c [2]uint64 121 122 if length := len(data); length > BlockSize { 123 n := length &^ (BlockSize - 1) 124 if length == n { 125 n -= BlockSize 126 } 127 hashBlocks(&h, &c, 0, data[:n]) 128 data = data[n:] 129 } 130 131 var block [BlockSize]byte 132 offset := copy(block[:], data) 133 remaining := uint64(BlockSize - offset) 134 if c[0] < remaining { 135 c[1]-- 136 } 137 c[0] -= remaining 138 139 hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) 140 141 for i, v := range h[:(hashSize+7)/8] { 142 binary.LittleEndian.PutUint64(sum[8*i:], v) 143 } 144 } 145 146 type digest struct { 147 h [8]uint64 148 c [2]uint64 149 size int 150 block [BlockSize]byte 151 offset int 152 153 key [BlockSize]byte 154 keyLen int 155 } 156 157 const ( 158 magic = "b2b" 159 marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1 160 ) 161 162 func (d *digest) MarshalBinary() ([]byte, error) { 163 if d.keyLen != 0 { 164 return nil, errors.New("crypto/blake2b: cannot marshal MACs") 165 } 166 b := make([]byte, 0, marshaledSize) 167 b = append(b, magic...) 168 for i := 0; i < 8; i++ { 169 b = appendUint64(b, d.h[i]) 170 } 171 b = appendUint64(b, d.c[0]) 172 b = appendUint64(b, d.c[1]) 173 // Maximum value for size is 64 174 b = append(b, byte(d.size)) 175 b = append(b, d.block[:]...) 176 b = append(b, byte(d.offset)) 177 return b, nil 178 } 179 180 func (d *digest) UnmarshalBinary(b []byte) error { 181 if len(b) < len(magic) || string(b[:len(magic)]) != magic { 182 return errors.New("crypto/blake2b: invalid hash state identifier") 183 } 184 if len(b) != marshaledSize { 185 return errors.New("crypto/blake2b: invalid hash state size") 186 } 187 b = b[len(magic):] 188 for i := 0; i < 8; i++ { 189 b, d.h[i] = consumeUint64(b) 190 } 191 b, d.c[0] = consumeUint64(b) 192 b, d.c[1] = consumeUint64(b) 193 d.size = int(b[0]) 194 b = b[1:] 195 copy(d.block[:], b[:BlockSize]) 196 b = b[BlockSize:] 197 d.offset = int(b[0]) 198 return nil 199 } 200 201 func (d *digest) BlockSize() int { return BlockSize } 202 203 func (d *digest) Size() int { return d.size } 204 205 func (d *digest) Reset() { 206 d.h = iv 207 d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24) 208 d.offset, d.c[0], d.c[1] = 0, 0, 0 209 if d.keyLen > 0 { 210 d.block = d.key 211 d.offset = BlockSize 212 } 213 } 214 215 func (d *digest) Write(p []byte) (n int, err error) { 216 n = len(p) 217 218 if d.offset > 0 { 219 remaining := BlockSize - d.offset 220 if n <= remaining { 221 d.offset += copy(d.block[d.offset:], p) 222 return 223 } 224 copy(d.block[d.offset:], p[:remaining]) 225 hashBlocks(&d.h, &d.c, 0, d.block[:]) 226 d.offset = 0 227 p = p[remaining:] 228 } 229 230 if length := len(p); length > BlockSize { 231 nn := length &^ (BlockSize - 1) 232 if length == nn { 233 nn -= BlockSize 234 } 235 hashBlocks(&d.h, &d.c, 0, p[:nn]) 236 p = p[nn:] 237 } 238 239 if len(p) > 0 { 240 d.offset += copy(d.block[:], p) 241 } 242 243 return 244 } 245 246 func (d *digest) Sum(sum []byte) []byte { 247 var hash [Size]byte 248 d.finalize(&hash) 249 return append(sum, hash[:d.size]...) 250 } 251 252 func (d *digest) finalize(hash *[Size]byte) { 253 var block [BlockSize]byte 254 copy(block[:], d.block[:d.offset]) 255 remaining := uint64(BlockSize - d.offset) 256 257 c := d.c 258 if c[0] < remaining { 259 c[1]-- 260 } 261 c[0] -= remaining 262 263 h := d.h 264 hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) 265 266 for i, v := range h { 267 binary.LittleEndian.PutUint64(hash[8*i:], v) 268 } 269 } 270 271 func appendUint64(b []byte, x uint64) []byte { 272 var a [8]byte 273 binary.BigEndian.PutUint64(a[:], x) 274 return append(b, a[:]...) 275 } 276 277 func appendUint32(b []byte, x uint32) []byte { 278 var a [4]byte 279 binary.BigEndian.PutUint32(a[:], x) 280 return append(b, a[:]...) 281 } 282 283 func consumeUint64(b []byte) ([]byte, uint64) { 284 x := binary.BigEndian.Uint64(b) 285 return b[8:], x 286 } 287 288 func consumeUint32(b []byte) ([]byte, uint32) { 289 x := binary.BigEndian.Uint32(b) 290 return b[4:], x 291 }