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  }