blake2s.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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 blake2s implements the BLAKE2s hash algorithm as
  5. // defined in RFC 7693.
  6. package blake2s // import "golang.org/x/crypto/blake2s"
  7. import (
  8. "encoding/binary"
  9. "errors"
  10. "hash"
  11. )
  12. const (
  13. // The blocksize of BLAKE2s in bytes.
  14. BlockSize = 64
  15. // The hash size of BLAKE2s-256 in bytes.
  16. Size = 32
  17. )
  18. var errKeySize = errors.New("blake2s: invalid key size")
  19. var iv = [8]uint32{
  20. 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
  21. 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
  22. }
  23. // Sum256 returns the BLAKE2s-256 checksum of the data.
  24. func Sum256(data []byte) [Size]byte {
  25. var sum [Size]byte
  26. checkSum(&sum, Size, data)
  27. return sum
  28. }
  29. // New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil
  30. // key turns the hash into a MAC. The key must between zero and 32 bytes long.
  31. func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
  32. func newDigest(hashSize int, key []byte) (*digest, error) {
  33. if len(key) > Size {
  34. return nil, errKeySize
  35. }
  36. d := &digest{
  37. size: hashSize,
  38. keyLen: len(key),
  39. }
  40. copy(d.key[:], key)
  41. d.Reset()
  42. return d, nil
  43. }
  44. func checkSum(sum *[Size]byte, hashSize int, data []byte) {
  45. var (
  46. h [8]uint32
  47. c [2]uint32
  48. )
  49. h = iv
  50. h[0] ^= uint32(hashSize) | (1 << 16) | (1 << 24)
  51. if length := len(data); length > BlockSize {
  52. n := length &^ (BlockSize - 1)
  53. if length == n {
  54. n -= BlockSize
  55. }
  56. hashBlocks(&h, &c, 0, data[:n])
  57. data = data[n:]
  58. }
  59. var block [BlockSize]byte
  60. offset := copy(block[:], data)
  61. remaining := uint32(BlockSize - offset)
  62. if c[0] < remaining {
  63. c[1]--
  64. }
  65. c[0] -= remaining
  66. hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
  67. for i, v := range h {
  68. binary.LittleEndian.PutUint32(sum[4*i:], v)
  69. }
  70. }
  71. type digest struct {
  72. h [8]uint32
  73. c [2]uint32
  74. size int
  75. block [BlockSize]byte
  76. offset int
  77. key [BlockSize]byte
  78. keyLen int
  79. }
  80. func (d *digest) BlockSize() int { return BlockSize }
  81. func (d *digest) Size() int { return d.size }
  82. func (d *digest) Reset() {
  83. d.h = iv
  84. d.h[0] ^= uint32(d.size) | (uint32(d.keyLen) << 8) | (1 << 16) | (1 << 24)
  85. d.offset, d.c[0], d.c[1] = 0, 0, 0
  86. if d.keyLen > 0 {
  87. d.block = d.key
  88. d.offset = BlockSize
  89. }
  90. }
  91. func (d *digest) Write(p []byte) (n int, err error) {
  92. n = len(p)
  93. if d.offset > 0 {
  94. remaining := BlockSize - d.offset
  95. if n <= remaining {
  96. d.offset += copy(d.block[d.offset:], p)
  97. return
  98. }
  99. copy(d.block[d.offset:], p[:remaining])
  100. hashBlocks(&d.h, &d.c, 0, d.block[:])
  101. d.offset = 0
  102. p = p[remaining:]
  103. }
  104. if length := len(p); length > BlockSize {
  105. nn := length &^ (BlockSize - 1)
  106. if length == nn {
  107. nn -= BlockSize
  108. }
  109. hashBlocks(&d.h, &d.c, 0, p[:nn])
  110. p = p[nn:]
  111. }
  112. d.offset += copy(d.block[:], p)
  113. return
  114. }
  115. func (d *digest) Sum(b []byte) []byte {
  116. var block [BlockSize]byte
  117. h := d.h
  118. c := d.c
  119. copy(block[:], d.block[:d.offset])
  120. remaining := uint32(BlockSize - d.offset)
  121. if c[0] < remaining {
  122. c[1]--
  123. }
  124. c[0] -= remaining
  125. hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
  126. var sum [Size]byte
  127. for i, v := range h {
  128. binary.LittleEndian.PutUint32(sum[4*i:], v)
  129. }
  130. return append(b, sum[:d.size]...)
  131. }