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