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