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.

396 lines
7.7 KiB

  1. // Use of this source code is governed by an ISC
  2. // license that can be found in the LICENSE file.
  3. package skein
  4. import (
  5. "fmt"
  6. "gitlab.com/nitya-sattva/go-x11/hash"
  7. )
  8. // HashSize holds the size of a hash in bytes.
  9. const HashSize = int(64)
  10. // BlockSize holds the size of a block in bytes.
  11. const BlockSize = uintptr(64)
  12. ////////////////
  13. type digest struct {
  14. ptr uintptr
  15. cnt uint64
  16. h [8]uint64
  17. b [BlockSize]byte
  18. }
  19. // New returns a new digest to compute a BLAKE512 hash.
  20. func New() hash.Digest {
  21. ref := &digest{}
  22. ref.Reset()
  23. return ref
  24. }
  25. ////////////////
  26. // Reset resets the digest to its initial state.
  27. func (ref *digest) Reset() {
  28. ref.ptr, ref.cnt = 0, 0
  29. copy(ref.h[:], kInit[:])
  30. }
  31. // Sum appends the current hash to dst and returns the result
  32. // as a slice. It does not change the underlying hash state.
  33. func (ref *digest) Sum(dst []byte) []byte {
  34. dgt := *ref
  35. hsh := [64]byte{}
  36. dgt.Close(hsh[:], 0, 0)
  37. return append(dst, hsh[:]...)
  38. }
  39. // Write more data to the running hash, never returns an error.
  40. func (ref *digest) Write(src []byte) (int, error) {
  41. sln := uintptr(len(src))
  42. fln := len(src)
  43. ptr := ref.ptr
  44. if sln <= (BlockSize - ptr) {
  45. copy(ref.b[ptr:], src)
  46. ref.ptr += sln
  47. return int(sln), nil
  48. }
  49. cnt := ref.cnt
  50. b := ref.b[:]
  51. h := [27]uint64{}
  52. h[0] = ref.h[0]
  53. h[1] = ref.h[1]
  54. h[2] = ref.h[2]
  55. h[3] = ref.h[3]
  56. h[4] = ref.h[4]
  57. h[5] = ref.h[5]
  58. h[6] = ref.h[6]
  59. h[7] = ref.h[7]
  60. var first uint8
  61. if cnt == 0 {
  62. first = uint8(1 << 7)
  63. }
  64. if ptr == BlockSize {
  65. cnt += 1
  66. compress(b, h[:], uint64(96+first), cnt, 0)
  67. first = 0
  68. ptr = 0
  69. }
  70. cln := BlockSize - ptr
  71. if cln > sln {
  72. cln = sln
  73. }
  74. sln -= cln
  75. copy(b[ptr:], src[:cln])
  76. src = src[cln:]
  77. ptr += cln
  78. for sln > 0 {
  79. if ptr == BlockSize {
  80. cnt += 1
  81. compress(b, h[:], uint64(96+first), cnt, 0)
  82. first = 0
  83. ptr = 0
  84. }
  85. cln := BlockSize - ptr
  86. if cln > sln {
  87. cln = sln
  88. }
  89. sln -= cln
  90. copy(b[ptr:], src[:cln])
  91. src = src[cln:]
  92. ptr += cln
  93. }
  94. ref.h[0] = h[0]
  95. ref.h[1] = h[1]
  96. ref.h[2] = h[2]
  97. ref.h[3] = h[3]
  98. ref.h[4] = h[4]
  99. ref.h[5] = h[5]
  100. ref.h[6] = h[6]
  101. ref.h[7] = h[7]
  102. ref.ptr = ptr
  103. ref.cnt = cnt
  104. return fln, nil
  105. }
  106. // Close the digest by writing the last bits and storing the hash
  107. // in dst. This prepares the digest for reuse by calling reset. A call
  108. // to Close with a dst that is smaller then HashSize will return an error.
  109. func (ref *digest) Close(dst []byte, bits uint8, bcnt uint8) error {
  110. if ln := len(dst); HashSize > ln {
  111. return fmt.Errorf("Skein Close: dst min length: %d, got %d", HashSize, ln)
  112. }
  113. if bcnt != 0 {
  114. off := uint8(0x80) >> bcnt
  115. x := [1]uint8{uint8((bits & -off) | off)}
  116. ref.Write(x[:])
  117. }
  118. ptr := ref.ptr
  119. cnt := ref.cnt
  120. b := ref.b[:]
  121. h := [27]uint64{}
  122. h[0] = ref.h[0]
  123. h[1] = ref.h[1]
  124. h[2] = ref.h[2]
  125. h[3] = ref.h[3]
  126. h[4] = ref.h[4]
  127. h[5] = ref.h[5]
  128. h[6] = ref.h[6]
  129. h[7] = ref.h[7]
  130. memset(b[ptr:ptr+(BlockSize-ptr)], 0)
  131. var etv uint64
  132. if cnt == 0 {
  133. etv = 352 + uint64(1<<7)
  134. } else {
  135. etv = 352
  136. }
  137. if bcnt != 0 {
  138. etv += 1
  139. }
  140. for i := uintptr(0); i < 2; i++ {
  141. compress(b, h[:], etv, cnt, ptr)
  142. if i == 0 {
  143. memset(b[:], 0)
  144. etv = 510
  145. ptr = 8
  146. cnt = 0
  147. }
  148. }
  149. for u := uintptr(0); u < 64; u += 8 {
  150. encUInt64le(dst[u:], h[u>>3])
  151. }
  152. ref.Reset()
  153. return nil
  154. }
  155. // Size returns the number of bytes required to store the hash.
  156. func (*digest) Size() int {
  157. return HashSize
  158. }
  159. // BlockSize returns the block size of the hash.
  160. func (*digest) BlockSize() int {
  161. return int(BlockSize)
  162. }
  163. ////////////////
  164. func memset(dst []byte, src byte) {
  165. for i := range dst {
  166. dst[i] = src
  167. }
  168. }
  169. func decUInt64le(src []byte) uint64 {
  170. return (uint64(src[0]) |
  171. uint64(src[1])<<8 |
  172. uint64(src[2])<<16 |
  173. uint64(src[3])<<24 |
  174. uint64(src[4])<<32 |
  175. uint64(src[5])<<40 |
  176. uint64(src[6])<<48 |
  177. uint64(src[7])<<56)
  178. }
  179. func encUInt64le(dst []byte, src uint64) {
  180. dst[0] = uint8(src)
  181. dst[1] = uint8(src >> 8)
  182. dst[2] = uint8(src >> 16)
  183. dst[3] = uint8(src >> 24)
  184. dst[4] = uint8(src >> 32)
  185. dst[5] = uint8(src >> 40)
  186. dst[6] = uint8(src >> 48)
  187. dst[7] = uint8(src >> 56)
  188. }
  189. func compress(buf []uint8, h []uint64, etv, cnt uint64, ext uintptr) {
  190. var t0, t1, t2 uint64
  191. m0 := decUInt64le(buf[0:])
  192. m1 := decUInt64le(buf[8:])
  193. m2 := decUInt64le(buf[16:])
  194. m3 := decUInt64le(buf[24:])
  195. m4 := decUInt64le(buf[32:])
  196. m5 := decUInt64le(buf[40:])
  197. m6 := decUInt64le(buf[48:])
  198. m7 := decUInt64le(buf[56:])
  199. p0 := m0
  200. p1 := m1
  201. p2 := m2
  202. p3 := m3
  203. p4 := m4
  204. p5 := m5
  205. p6 := m6
  206. p7 := m7
  207. t0 = uint64(cnt<<6) + uint64(ext)
  208. t1 = (cnt >> 58) + (uint64(etv) << 55)
  209. t2 = t0 ^ t1
  210. h[8] = (((h[0] ^ h[1]) ^ (h[2] ^ h[3])) ^
  211. ((h[4] ^ h[5]) ^ (h[6] ^ h[7])) ^
  212. uint64(0x1BD11BDAA9FC1A22))
  213. for u := uintptr(0); u <= 15; u += 3 {
  214. h[u+9] = h[u+0]
  215. h[u+10] = h[u+1]
  216. h[u+11] = h[u+2]
  217. }
  218. var tmp uint64
  219. for u := uintptr(0); u < 9; u++ {
  220. s := uint64(u << 1)
  221. p0 = uint64(p0 + h[s+0])
  222. p1 = uint64(p1 + h[s+1])
  223. p2 = uint64(p2 + h[s+2])
  224. p3 = uint64(p3 + h[s+3])
  225. p4 = uint64(p4 + h[s+4])
  226. p5 = uint64(p5 + h[s+5] + t0)
  227. p6 = uint64(p6 + h[s+6] + t1)
  228. p7 = uint64(p7 + h[s+7] + s)
  229. p0 = (p0 + p1)
  230. p1 = ((p1 << 46) | (p1 >> (64 - 46))) ^ p0
  231. p2 = (p2 + p3)
  232. p3 = ((p3 << 36) | (p3 >> (64 - 36))) ^ p2
  233. p4 = (p4 + p5)
  234. p5 = ((p5 << 19) | (p5 >> (64 - 19))) ^ p4
  235. p6 = (p6 + p7)
  236. p7 = ((p7 << 37) | (p7 >> (64 - 37))) ^ p6
  237. p2 = (p2 + p1)
  238. p1 = ((p1 << 33) | (p1 >> (64 - 33))) ^ p2
  239. p4 = (p4 + p7)
  240. p7 = ((p7 << 27) | (p7 >> (64 - 27))) ^ p4
  241. p6 = (p6 + p5)
  242. p5 = ((p5 << 14) | (p5 >> (64 - 14))) ^ p6
  243. p0 = (p0 + p3)
  244. p3 = ((p3 << 42) | (p3 >> (64 - 42))) ^ p0
  245. p4 = (p4 + p1)
  246. p1 = ((p1 << 17) | (p1 >> (64 - 17))) ^ p4
  247. p6 = (p6 + p3)
  248. p3 = ((p3 << 49) | (p3 >> (64 - 49))) ^ p6
  249. p0 = (p0 + p5)
  250. p5 = ((p5 << 36) | (p5 >> (64 - 36))) ^ p0
  251. p2 = (p2 + p7)
  252. p7 = ((p7 << 39) | (p7 >> (64 - 39))) ^ p2
  253. p6 = (p6 + p1)
  254. p1 = ((p1 << 44) | (p1 >> (64 - 44))) ^ p6
  255. p0 = (p0 + p7)
  256. p7 = ((p7 << 9) | (p7 >> (64 - 9))) ^ p0
  257. p2 = (p2 + p5)
  258. p5 = ((p5 << 54) | (p5 >> (64 - 54))) ^ p2
  259. p4 = (p4 + p3)
  260. p3 = ((p3 << 56) | (p3 >> (64 - 56))) ^ p4
  261. p0 = (p0 + h[s+1])
  262. p1 = (p1 + h[s+2])
  263. p2 = (p2 + h[s+3])
  264. p3 = (p3 + h[s+4])
  265. p4 = (p4 + h[s+5])
  266. p5 = (p5 + h[s+6] + t1)
  267. p6 = (p6 + h[s+7] + t2)
  268. p7 = (p7 + h[s+8] + (s + 1))
  269. p0 = (p0 + p1)
  270. p1 = ((p1 << 39) | (p1 >> (64 - 39))) ^ p0
  271. p2 = (p2 + p3)
  272. p3 = ((p3 << 30) | (p3 >> (64 - 30))) ^ p2
  273. p4 = (p4 + p5)
  274. p5 = ((p5 << 34) | (p5 >> (64 - 34))) ^ p4
  275. p6 = (p6 + p7)
  276. p7 = ((p7 << 24) | (p7 >> (64 - 24))) ^ p6
  277. p2 = (p2 + p1)
  278. p1 = ((p1 << 13) | (p1 >> (64 - 13))) ^ p2
  279. p4 = (p4 + p7)
  280. p7 = ((p7 << 50) | (p7 >> (64 - 50))) ^ p4
  281. p6 = (p6 + p5)
  282. p5 = ((p5 << 10) | (p5 >> (64 - 10))) ^ p6
  283. p0 = (p0 + p3)
  284. p3 = ((p3 << 17) | (p3 >> (64 - 17))) ^ p0
  285. p4 = (p4 + p1)
  286. p1 = ((p1 << 25) | (p1 >> (64 - 25))) ^ p4
  287. p6 = (p6 + p3)
  288. p3 = ((p3 << 29) | (p3 >> (64 - 29))) ^ p6
  289. p0 = (p0 + p5)
  290. p5 = ((p5 << 39) | (p5 >> (64 - 39))) ^ p0
  291. p2 = (p2 + p7)
  292. p7 = ((p7 << 43) | (p7 >> (64 - 43))) ^ p2
  293. p6 = (p6 + p1)
  294. p1 = ((p1 << 8) | (p1 >> (64 - 8))) ^ p6
  295. p0 = (p0 + p7)
  296. p7 = ((p7 << 35) | (p7 >> (64 - 35))) ^ p0
  297. p2 = (p2 + p5)
  298. p5 = ((p5 << 56) | (p5 >> (64 - 56))) ^ p2
  299. p4 = (p4 + p3)
  300. p3 = ((p3 << 22) | (p3 >> (64 - 22))) ^ p4
  301. tmp = t2
  302. t2 = t1
  303. t1 = t0
  304. t0 = tmp
  305. }
  306. p0 += h[18+0]
  307. p1 += h[18+1]
  308. p2 += h[18+2]
  309. p3 += h[18+3]
  310. p4 += h[18+4]
  311. p5 += h[18+5] + t0
  312. p6 += h[18+6] + t1
  313. p7 += h[18+7] + 18
  314. h[0] = m0 ^ p0
  315. h[1] = m1 ^ p1
  316. h[2] = m2 ^ p2
  317. h[3] = m3 ^ p3
  318. h[4] = m4 ^ p4
  319. h[5] = m5 ^ p5
  320. h[6] = m6 ^ p6
  321. h[7] = m7 ^ p7
  322. }
  323. ////////////////
  324. var kInit = [8]uint64{
  325. uint64(0x4903ADFF749C51CE), uint64(0x0D95DE399746DF03),
  326. uint64(0x8FD1934127C79BCE), uint64(0x9A255629FF352CB1),
  327. uint64(0x5DB62599DF6CA7B0), uint64(0xEABE394CA9D5C3F4),
  328. uint64(0x991112C71A75B523), uint64(0xAE18A40B660FCC33),
  329. }