blake2b.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693
  5. // and the extendable output function (XOF) BLAKE2Xb.
  6. //
  7. // For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf
  8. // and for BLAKE2Xb see https://blake2.net/blake2x.pdf
  9. //
  10. // If you aren't sure which function you need, use BLAKE2b (Sum512 or New512).
  11. // If you need a secret-key MAC (message authentication code), use the New512
  12. // function with a non-nil key.
  13. //
  14. // BLAKE2X is a construction to compute hash values larger than 64 bytes. It
  15. // can produce hash values between 0 and 4 GiB.
  16. package blake2b
  17. import (
  18. "encoding/binary"
  19. "errors"
  20. "hash"
  21. )
  22. const (
  23. // The blocksize of BLAKE2b in bytes.
  24. BlockSize = 128
  25. // The hash size of BLAKE2b-512 in bytes.
  26. Size = 64
  27. // The hash size of BLAKE2b-384 in bytes.
  28. Size384 = 48
  29. // The hash size of BLAKE2b-256 in bytes.
  30. Size256 = 32
  31. )
  32. var (
  33. useAVX2 bool
  34. useAVX bool
  35. useSSE4 bool
  36. )
  37. var errKeySize = errors.New("blake2b: invalid key size")
  38. var iv = [8]uint64{
  39. 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
  40. 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
  41. }
  42. // Sum512 returns the BLAKE2b-512 checksum of the data.
  43. func Sum512(data []byte) [Size]byte {
  44. var sum [Size]byte
  45. checkSum(&sum, Size, data)
  46. return sum
  47. }
  48. // Sum384 returns the BLAKE2b-384 checksum of the data.
  49. func Sum384(data []byte) [Size384]byte {
  50. var sum [Size]byte
  51. var sum384 [Size384]byte
  52. checkSum(&sum, Size384, data)
  53. copy(sum384[:], sum[:Size384])
  54. return sum384
  55. }
  56. // Sum256 returns the BLAKE2b-256 checksum of the data.
  57. func Sum256(data []byte) [Size256]byte {
  58. var sum [Size]byte
  59. var sum256 [Size256]byte
  60. checkSum(&sum, Size256, data)
  61. copy(sum256[:], sum[:Size256])
  62. return sum256
  63. }
  64. // New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
  65. // key turns the hash into a MAC. The key must between zero and 64 bytes long.
  66. func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
  67. // New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
  68. // key turns the hash into a MAC. The key must between zero and 64 bytes long.
  69. func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
  70. // New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
  71. // key turns the hash into a MAC. The key must between zero and 64 bytes long.
  72. func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
  73. func newDigest(hashSize int, key []byte) (*digest, error) {
  74. if len(key) > Size {
  75. return nil, errKeySize
  76. }
  77. d := &digest{
  78. size: hashSize,
  79. keyLen: len(key),
  80. }
  81. copy(d.key[:], key)
  82. d.Reset()
  83. return d, nil
  84. }
  85. func checkSum(sum *[Size]byte, hashSize int, data []byte) {
  86. h := iv
  87. h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24)
  88. var c [2]uint64
  89. if length := len(data); length > BlockSize {
  90. n := length &^ (BlockSize - 1)
  91. if length == n {
  92. n -= BlockSize
  93. }
  94. hashBlocks(&h, &c, 0, data[:n])
  95. data = data[n:]
  96. }
  97. var block [BlockSize]byte
  98. offset := copy(block[:], data)
  99. remaining := uint64(BlockSize - offset)
  100. if c[0] < remaining {
  101. c[1]--
  102. }
  103. c[0] -= remaining
  104. hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
  105. for i, v := range h[:(hashSize+7)/8] {
  106. binary.LittleEndian.PutUint64(sum[8*i:], v)
  107. }
  108. }
  109. type digest struct {
  110. h [8]uint64
  111. c [2]uint64
  112. size int
  113. block [BlockSize]byte
  114. offset int
  115. key [BlockSize]byte
  116. keyLen int
  117. }
  118. func (d *digest) BlockSize() int { return BlockSize }
  119. func (d *digest) Size() int { return d.size }
  120. func (d *digest) Reset() {
  121. d.h = iv
  122. d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24)
  123. d.offset, d.c[0], d.c[1] = 0, 0, 0
  124. if d.keyLen > 0 {
  125. d.block = d.key
  126. d.offset = BlockSize
  127. }
  128. }
  129. func (d *digest) Write(p []byte) (n int, err error) {
  130. n = len(p)
  131. if d.offset > 0 {
  132. remaining := BlockSize - d.offset
  133. if n <= remaining {
  134. d.offset += copy(d.block[d.offset:], p)
  135. return
  136. }
  137. copy(d.block[d.offset:], p[:remaining])
  138. hashBlocks(&d.h, &d.c, 0, d.block[:])
  139. d.offset = 0
  140. p = p[remaining:]
  141. }
  142. if length := len(p); length > BlockSize {
  143. nn := length &^ (BlockSize - 1)
  144. if length == nn {
  145. nn -= BlockSize
  146. }
  147. hashBlocks(&d.h, &d.c, 0, p[:nn])
  148. p = p[nn:]
  149. }
  150. if len(p) > 0 {
  151. d.offset += copy(d.block[:], p)
  152. }
  153. return
  154. }
  155. func (d *digest) Sum(sum []byte) []byte {
  156. var hash [Size]byte
  157. d.finalize(&hash)
  158. return append(sum, hash[:d.size]...)
  159. }
  160. func (d *digest) finalize(hash *[Size]byte) {
  161. var block [BlockSize]byte
  162. copy(block[:], d.block[:d.offset])
  163. remaining := uint64(BlockSize - d.offset)
  164. c := d.c
  165. if c[0] < remaining {
  166. c[1]--
  167. }
  168. c[0] -= remaining
  169. h := d.h
  170. hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
  171. for i, v := range h {
  172. binary.LittleEndian.PutUint64(hash[8*i:], v)
  173. }
  174. }