You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
4.2 KiB

  1. // Copyright (c) 2016 Andreas Auernhammer. All rights reserved.
  2. // Use of this source code is governed by a license that can be
  3. // found in the LICENSE file.
  4. package skein256
  5. import (
  6. "github.com/aead/skein"
  7. "github.com/aead/skein/threefish"
  8. )
  9. type hashFunc struct {
  10. hashsize int
  11. hVal, hValCpy [5]uint64
  12. tweak [3]uint64
  13. block [threefish.BlockSize256]byte
  14. off int
  15. hasMsg bool
  16. }
  17. func (s *hashFunc) BlockSize() int { return threefish.BlockSize256 }
  18. func (s *hashFunc) Size() int { return s.hashsize }
  19. func (s *hashFunc) Reset() {
  20. for i := range s.block {
  21. s.block[i] = 0
  22. }
  23. s.off = 0
  24. s.hasMsg = false
  25. s.hVal = s.hValCpy
  26. s.tweak[0] = 0
  27. s.tweak[1] = skein.CfgMessage<<56 | skein.FirstBlock
  28. }
  29. func (s *hashFunc) Write(p []byte) (n int, err error) {
  30. s.hasMsg = true
  31. n = len(p)
  32. var block [4]uint64
  33. dif := threefish.BlockSize256 - s.off
  34. if s.off > 0 && n > dif {
  35. s.off += copy(s.block[s.off:], p[:dif])
  36. p = p[dif:]
  37. if s.off == threefish.BlockSize256 && len(p) > 0 {
  38. bytesToBlock(&block, s.block[:])
  39. s.update(&block)
  40. s.off = 0
  41. }
  42. }
  43. if length := len(p); length > threefish.BlockSize256 {
  44. nn := length & (^(threefish.BlockSize256 - 1)) // length -= (length % BlockSize)
  45. if length == nn {
  46. nn -= threefish.BlockSize256
  47. }
  48. for i := 0; i < len(p[:nn]); i += threefish.BlockSize256 {
  49. bytesToBlock(&block, p[i:])
  50. s.update(&block)
  51. }
  52. p = p[nn:]
  53. }
  54. if len(p) > 0 {
  55. s.off += copy(s.block[s.off:], p)
  56. }
  57. return
  58. }
  59. func (s *hashFunc) Sum(b []byte) []byte {
  60. s0 := *s // copy
  61. if s0.hasMsg {
  62. s0.finalizeHash()
  63. }
  64. var out [threefish.BlockSize256]byte
  65. var ctr uint64
  66. for i := s0.hashsize; i > 0; i -= threefish.BlockSize256 {
  67. s0.output(&out, ctr)
  68. ctr++
  69. b = append(b, out[:]...)
  70. }
  71. return b[:s0.hashsize]
  72. }
  73. func (s *hashFunc) update(block *[4]uint64) {
  74. threefish.IncrementTweak(&(s.tweak), threefish.BlockSize256)
  75. threefish.UBI256(block, &(s.hVal), &(s.tweak))
  76. s.tweak[1] &^= skein.FirstBlock
  77. }
  78. func (s *hashFunc) output(dst *[threefish.BlockSize256]byte, counter uint64) {
  79. var block [4]uint64
  80. block[0] = counter
  81. hVal := s.hVal
  82. var outTweak = [3]uint64{8, skein.CfgOutput<<56 | skein.FirstBlock | skein.FinalBlock, 0}
  83. threefish.UBI256(&block, &hVal, &outTweak)
  84. block[0] ^= counter
  85. blockToBytes(dst[:], &block)
  86. }
  87. func (s *hashFunc) initialize(hashsize int, conf *skein.Config) {
  88. if hashsize < 1 {
  89. panic("skein256: invalid hashsize for Skein-256")
  90. }
  91. s.hashsize = hashsize
  92. var key, pubKey, keyID, nonce, personal []byte
  93. if conf != nil {
  94. key = conf.Key
  95. pubKey = conf.PublicKey
  96. keyID = conf.KeyID
  97. nonce = conf.Nonce
  98. personal = conf.Personal
  99. }
  100. if len(key) > 0 {
  101. s.tweak[0] = 0
  102. s.tweak[1] = skein.CfgKey<<56 | skein.FirstBlock
  103. s.Write(key)
  104. s.finalizeHash()
  105. }
  106. var cfg [32]byte
  107. schemaId := skein.SchemaID
  108. cfg[0] = byte(schemaId)
  109. cfg[1] = byte(schemaId >> 8)
  110. cfg[2] = byte(schemaId >> 16)
  111. cfg[3] = byte(schemaId >> 24)
  112. cfg[4] = byte(schemaId >> 32)
  113. cfg[5] = byte(schemaId >> 40)
  114. cfg[6] = byte(schemaId >> 48)
  115. cfg[7] = byte(schemaId >> 56)
  116. bits := uint64(s.hashsize * 8)
  117. cfg[8] = byte(bits)
  118. cfg[9] = byte(bits >> 8)
  119. cfg[10] = byte(bits >> 16)
  120. cfg[11] = byte(bits >> 24)
  121. cfg[12] = byte(bits >> 32)
  122. cfg[13] = byte(bits >> 40)
  123. cfg[14] = byte(bits >> 48)
  124. cfg[15] = byte(bits >> 56)
  125. s.tweak[0] = 0
  126. s.tweak[1] = skein.CfgConfig<<56 | skein.FirstBlock
  127. s.Write(cfg[:])
  128. s.finalizeHash()
  129. if len(personal) > 0 {
  130. s.tweak[0] = 0
  131. s.tweak[1] = skein.CfgPersonal<<56 | skein.FirstBlock
  132. s.Write(personal)
  133. s.finalizeHash()
  134. }
  135. if len(pubKey) > 0 {
  136. s.tweak[0] = 0
  137. s.tweak[1] = skein.CfgPublicKey<<56 | skein.FirstBlock
  138. s.Write(pubKey)
  139. s.finalizeHash()
  140. }
  141. if len(keyID) > 0 {
  142. s.tweak[0] = 0
  143. s.tweak[1] = skein.CfgKeyID<<56 | skein.FirstBlock
  144. s.Write(keyID)
  145. s.finalizeHash()
  146. }
  147. if len(nonce) > 0 {
  148. s.tweak[0] = 0
  149. s.tweak[1] = skein.CfgNonce<<56 | skein.FirstBlock
  150. s.Write(nonce)
  151. s.finalizeHash()
  152. }
  153. s.hValCpy = s.hVal
  154. s.Reset()
  155. }
  156. func (s *hashFunc) finalizeHash() {
  157. threefish.IncrementTweak(&(s.tweak), uint64(s.off))
  158. s.tweak[1] |= skein.FinalBlock // set the last block flag
  159. for i := s.off; i < len(s.block); i++ {
  160. s.block[i] = 0
  161. }
  162. s.off = 0
  163. var block [4]uint64
  164. bytesToBlock(&block, s.block[:])
  165. threefish.UBI256(&block, &(s.hVal), &(s.tweak))
  166. }