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.

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