// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693 // and the extendable output function (XOF) BLAKE2Xb. // // BLAKE2b is optimized for 64-bit platforms—including NEON-enabled ARMs—and // produces digests of any size between 1 and 64 bytes. // For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf // and for BLAKE2Xb see https://blake2.net/blake2x.pdf // // If you aren't sure which function you need, use BLAKE2b (Sum512 or New512). // If you need a secret-key MAC (message authentication code), use the New512 // function with a non-nil key. // // BLAKE2X is a construction to compute hash values larger than 64 bytes. It // can produce hash values between 0 and 4 GiB.
package blake2b import ( ) const ( // The blocksize of BLAKE2b in bytes. BlockSize = 128 // The hash size of BLAKE2b-512 in bytes. Size = 64 // The hash size of BLAKE2b-384 in bytes. Size384 = 48 // The hash size of BLAKE2b-256 in bytes. Size256 = 32 ) var ( useAVX2 bool useAVX bool useSSE4 bool ) var ( errKeySize = errors.New("blake2b: invalid key size") errHashSize = errors.New("blake2b: invalid hash size") ) var iv = [8]uint64{ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, } // Sum512 returns the BLAKE2b-512 checksum of the data. func ( []byte) [Size]byte { var [Size]byte checkSum(&, Size, ) return } // Sum384 returns the BLAKE2b-384 checksum of the data. func ( []byte) [Size384]byte { var [Size]byte var [Size384]byte checkSum(&, Size384, ) copy([:], [:Size384]) return } // Sum256 returns the BLAKE2b-256 checksum of the data. func ( []byte) [Size256]byte { var [Size]byte var [Size256]byte checkSum(&, Size256, ) copy([:], [:Size256]) return } // New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil // key turns the hash into a MAC. The key must be between zero and 64 bytes long. func ( []byte) (hash.Hash, error) { return newDigest(Size, ) } // New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil // key turns the hash into a MAC. The key must be between zero and 64 bytes long. func ( []byte) (hash.Hash, error) { return newDigest(Size384, ) } // New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil // key turns the hash into a MAC. The key must be between zero and 64 bytes long. func ( []byte) (hash.Hash, error) { return newDigest(Size256, ) } // New returns a new hash.Hash computing the BLAKE2b checksum with a custom length. // A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long. // The hash size can be a value between 1 and 64 but it is highly recommended to use // values equal or greater than: // - 32 if BLAKE2b is used as a hash function (The key is zero bytes long). // - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long). // When the key is nil, the returned hash.Hash implements BinaryMarshaler // and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash. func ( int, []byte) (hash.Hash, error) { return newDigest(, ) } func ( int, []byte) (*digest, error) { if < 1 || > Size { return nil, errHashSize } if len() > Size { return nil, errKeySize } := &digest{ size: , keyLen: len(), } copy(.key[:], ) .Reset() return , nil } func ( *[Size]byte, int, []byte) { := iv [0] ^= uint64() | (1 << 16) | (1 << 24) var [2]uint64 if := len(); > BlockSize { := &^ (BlockSize - 1) if == { -= BlockSize } hashBlocks(&, &, 0, [:]) = [:] } var [BlockSize]byte := copy([:], ) := uint64(BlockSize - ) if [0] < { [1]-- } [0] -= hashBlocks(&, &, 0xFFFFFFFFFFFFFFFF, [:]) for , := range [:(+7)/8] { binary.LittleEndian.PutUint64([8*:], ) } } type digest struct { h [8]uint64 c [2]uint64 size int block [BlockSize]byte offset int key [BlockSize]byte keyLen int } const ( magic = "b2b" marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1 ) func ( *digest) () ([]byte, error) { if .keyLen != 0 { return nil, errors.New("crypto/blake2b: cannot marshal MACs") } := make([]byte, 0, marshaledSize) = append(, magic...) for := 0; < 8; ++ { = appendUint64(, .h[]) } = appendUint64(, .c[0]) = appendUint64(, .c[1]) // Maximum value for size is 64 = append(, byte(.size)) = append(, .block[:]...) = append(, byte(.offset)) return , nil } func ( *digest) ( []byte) error { if len() < len(magic) || string([:len(magic)]) != magic { return errors.New("crypto/blake2b: invalid hash state identifier") } if len() != marshaledSize { return errors.New("crypto/blake2b: invalid hash state size") } = [len(magic):] for := 0; < 8; ++ { , .h[] = consumeUint64() } , .c[0] = consumeUint64() , .c[1] = consumeUint64() .size = int([0]) = [1:] copy(.block[:], [:BlockSize]) = [BlockSize:] .offset = int([0]) return nil } func ( *digest) () int { return BlockSize } func ( *digest) () int { return .size } func ( *digest) () { .h = iv .h[0] ^= uint64(.size) | (uint64(.keyLen) << 8) | (1 << 16) | (1 << 24) .offset, .c[0], .c[1] = 0, 0, 0 if .keyLen > 0 { .block = .key .offset = BlockSize } } func ( *digest) ( []byte) ( int, error) { = len() if .offset > 0 { := BlockSize - .offset if <= { .offset += copy(.block[.offset:], ) return } copy(.block[.offset:], [:]) hashBlocks(&.h, &.c, 0, .block[:]) .offset = 0 = [:] } if := len(); > BlockSize { := &^ (BlockSize - 1) if == { -= BlockSize } hashBlocks(&.h, &.c, 0, [:]) = [:] } if len() > 0 { .offset += copy(.block[:], ) } return } func ( *digest) ( []byte) []byte { var [Size]byte .finalize(&) return append(, [:.size]...) } func ( *digest) ( *[Size]byte) { var [BlockSize]byte copy([:], .block[:.offset]) := uint64(BlockSize - .offset) := .c if [0] < { [1]-- } [0] -= := .h hashBlocks(&, &, 0xFFFFFFFFFFFFFFFF, [:]) for , := range { binary.LittleEndian.PutUint64([8*:], ) } } func ( []byte, uint64) []byte { var [8]byte binary.BigEndian.PutUint64([:], ) return append(, [:]...) } func ( []byte, uint32) []byte { var [4]byte binary.BigEndian.PutUint32([:], ) return append(, [:]...) } func ( []byte) ([]byte, uint64) { := binary.BigEndian.Uint64() return [8:], } func ( []byte) ([]byte, uint32) { := binary.BigEndian.Uint32() return [4:], }