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