// 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 blake2s implements the BLAKE2s hash algorithm defined by RFC 7693 // and the extendable output function (XOF) BLAKE2Xs. // // BLAKE2s is optimized for 8- to 32-bit platforms and produces digests of any // size between 1 and 32 bytes. // For a detailed specification of BLAKE2s see https://blake2.net/blake2.pdf // and for BLAKE2Xs see https://blake2.net/blake2x.pdf // // If you aren't sure which function you need, use BLAKE2s (Sum256 or New256). // If you need a secret-key MAC (message authentication code), use the New256 // function with a non-nil key. // // BLAKE2X is a construction to compute hash values larger than 32 bytes. It // can produce hash values between 0 and 65535 bytes.
package blake2s import ( ) const ( // The blocksize of BLAKE2s in bytes. BlockSize = 64 // The hash size of BLAKE2s-256 in bytes. Size = 32 // The hash size of BLAKE2s-128 in bytes. Size128 = 16 ) var errKeySize = errors.New("blake2s: invalid key size") var iv = [8]uint32{ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, } // Sum256 returns the BLAKE2s-256 checksum of the data. func ( []byte) [Size]byte { var [Size]byte checkSum(&, Size, ) return } // New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil // key turns the hash into a MAC. The key must between zero and 32 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 ( []byte) (hash.Hash, error) { return newDigest(Size, ) } func init() { crypto.RegisterHash(crypto.BLAKE2s_256, func() hash.Hash { , := New256(nil) return }) } // New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a // non-empty key. Note that a 128-bit digest is too small to be secure as a // cryptographic hash and should only be used as a MAC, thus the key argument // is not optional. func ( []byte) (hash.Hash, error) { if len() == 0 { return nil, errors.New("blake2s: a key is required for a 128-bit hash") } return newDigest(Size128, ) } func newDigest( int, []byte) (*digest, error) { if len() > Size { return nil, errKeySize } := &digest{ size: , keyLen: len(), } copy(.key[:], ) .Reset() return , nil } func checkSum( *[Size]byte, int, []byte) { var ( [8]uint32 [2]uint32 ) = iv [0] ^= uint32() | (1 << 16) | (1 << 24) if := len(); > BlockSize { := &^ (BlockSize - 1) if == { -= BlockSize } hashBlocks(&, &, 0, [:]) = [:] } var [BlockSize]byte := copy([:], ) := uint32(BlockSize - ) if [0] < { [1]-- } [0] -= hashBlocks(&, &, 0xFFFFFFFF, [:]) for , := range { binary.LittleEndian.PutUint32([4*:], ) } } type digest struct { h [8]uint32 c [2]uint32 size int block [BlockSize]byte offset int key [BlockSize]byte keyLen int } const ( magic = "b2s" marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1 ) func ( *digest) () ([]byte, error) { if .keyLen != 0 { return nil, errors.New("crypto/blake2s: cannot marshal MACs") } := make([]byte, 0, marshaledSize) = append(, magic...) for := 0; < 8; ++ { = appendUint32(, .h[]) } = appendUint32(, .c[0]) = appendUint32(, .c[1]) // Maximum value for size is 32 = 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/blake2s: invalid hash state identifier") } if len() != marshaledSize { return errors.New("crypto/blake2s: invalid hash state size") } = [len(magic):] for := 0; < 8; ++ { , .h[] = consumeUint32() } , .c[0] = consumeUint32() , .c[1] = consumeUint32() .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] ^= uint32(.size) | (uint32(.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, [:]) = [:] } .offset += copy(.block[:], ) return } func ( *digest) ( []byte) []byte { var [Size]byte .finalize(&) return append(, [:.size]...) } func ( *digest) ( *[Size]byte) { var [BlockSize]byte := .h := .c copy([:], .block[:.offset]) := uint32(BlockSize - .offset) if [0] < { [1]-- } [0] -= hashBlocks(&, &, 0xFFFFFFFF, [:]) for , := range { binary.LittleEndian.PutUint32([4*:], ) } } func appendUint32( []byte, uint32) []byte { var [4]byte binary.BigEndian.PutUint32([:], ) return append(, [:]...) } func consumeUint32( []byte) ([]byte, uint32) { := binary.BigEndian.Uint32() return [4:], }