siphash.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Written in 2012-2014 by Dmitry Chestnykh.
  2. //
  3. // To the extent possible under law, the author have dedicated all copyright
  4. // and related and neighboring rights to this software to the public domain
  5. // worldwide. This software is distributed without any warranty.
  6. // http://creativecommons.org/publicdomain/zero/1.0/
  7. // Package siphash implements SipHash-2-4, a fast short-input PRF
  8. // created by Jean-Philippe Aumasson and Daniel J. Bernstein.
  9. package siphash
  10. import "hash"
  11. const (
  12. // BlockSize is the block size of hash algorithm in bytes.
  13. BlockSize = 8
  14. // Size is the size of hash output in bytes.
  15. Size = 8
  16. // Size128 is the size of 128-bit hash output in bytes.
  17. Size128 = 16
  18. )
  19. type digest struct {
  20. v0, v1, v2, v3 uint64 // state
  21. k0, k1 uint64 // two parts of key
  22. x [8]byte // buffer for unprocessed bytes
  23. nx int // number of bytes in buffer x
  24. size int // output size in bytes (8 or 16)
  25. t uint8 // message bytes counter (mod 256)
  26. }
  27. // newDigest returns a new digest with the given output size in bytes (must be 8 or 16).
  28. func newDigest(size int, key []byte) *digest {
  29. if size != Size && size != Size128 {
  30. panic("size must be 8 or 16")
  31. }
  32. d := new(digest)
  33. d.k0 = uint64(key[0]) | uint64(key[1])<<8 | uint64(key[2])<<16 | uint64(key[3])<<24 |
  34. uint64(key[4])<<32 | uint64(key[5])<<40 | uint64(key[6])<<48 | uint64(key[7])<<56
  35. d.k1 = uint64(key[8]) | uint64(key[9])<<8 | uint64(key[10])<<16 | uint64(key[11])<<24 |
  36. uint64(key[12])<<32 | uint64(key[13])<<40 | uint64(key[14])<<48 | uint64(key[15])<<56
  37. d.size = size
  38. d.Reset()
  39. return d
  40. }
  41. // New returns a new hash.Hash64 computing SipHash-2-4 with 16-byte key and 8-byte output.
  42. func New(key []byte) hash.Hash64 {
  43. return newDigest(Size, key)
  44. }
  45. // New128 returns a new hash.Hash computing SipHash-2-4 with 16-byte key and 16-byte output.
  46. //
  47. // Note that 16-byte output is considered experimental by SipHash authors at this time.
  48. func New128(key []byte) hash.Hash {
  49. return newDigest(Size128, key)
  50. }
  51. func (d *digest) Reset() {
  52. d.v0 = d.k0 ^ 0x736f6d6570736575
  53. d.v1 = d.k1 ^ 0x646f72616e646f6d
  54. d.v2 = d.k0 ^ 0x6c7967656e657261
  55. d.v3 = d.k1 ^ 0x7465646279746573
  56. d.t = 0
  57. d.nx = 0
  58. if d.size == Size128 {
  59. d.v1 ^= 0xee
  60. }
  61. }
  62. func (d *digest) Size() int { return d.size }
  63. func (d *digest) BlockSize() int { return BlockSize }
  64. func (d *digest) Write(p []byte) (nn int, err error) {
  65. nn = len(p)
  66. d.t += uint8(nn)
  67. if d.nx > 0 {
  68. n := len(p)
  69. if n > BlockSize-d.nx {
  70. n = BlockSize - d.nx
  71. }
  72. d.nx += copy(d.x[d.nx:], p)
  73. if d.nx == BlockSize {
  74. once(d)
  75. d.nx = 0
  76. }
  77. p = p[n:]
  78. }
  79. if len(p) >= BlockSize {
  80. n := len(p) &^ (BlockSize - 1)
  81. blocks(d, p[:n])
  82. p = p[n:]
  83. }
  84. if len(p) > 0 {
  85. d.nx = copy(d.x[:], p)
  86. }
  87. return
  88. }
  89. func (d *digest) Sum64() uint64 {
  90. for i := d.nx; i < BlockSize-1; i++ {
  91. d.x[i] = 0
  92. }
  93. d.x[7] = d.t
  94. return finalize(d)
  95. }
  96. func (d0 *digest) sum128() (r0, r1 uint64) {
  97. // Make a copy of d0 so that caller can keep writing and summing.
  98. d := *d0
  99. for i := d.nx; i < BlockSize-1; i++ {
  100. d.x[i] = 0
  101. }
  102. d.x[7] = d.t
  103. blocks(&d, d.x[:])
  104. v0, v1, v2, v3 := d.v0, d.v1, d.v2, d.v3
  105. v2 ^= 0xee
  106. // Round 1.
  107. v0 += v1
  108. v1 = v1<<13 | v1>>(64-13)
  109. v1 ^= v0
  110. v0 = v0<<32 | v0>>(64-32)
  111. v2 += v3
  112. v3 = v3<<16 | v3>>(64-16)
  113. v3 ^= v2
  114. v0 += v3
  115. v3 = v3<<21 | v3>>(64-21)
  116. v3 ^= v0
  117. v2 += v1
  118. v1 = v1<<17 | v1>>(64-17)
  119. v1 ^= v2
  120. v2 = v2<<32 | v2>>(64-32)
  121. // Round 2.
  122. v0 += v1
  123. v1 = v1<<13 | v1>>(64-13)
  124. v1 ^= v0
  125. v0 = v0<<32 | v0>>(64-32)
  126. v2 += v3
  127. v3 = v3<<16 | v3>>(64-16)
  128. v3 ^= v2
  129. v0 += v3
  130. v3 = v3<<21 | v3>>(64-21)
  131. v3 ^= v0
  132. v2 += v1
  133. v1 = v1<<17 | v1>>(64-17)
  134. v1 ^= v2
  135. v2 = v2<<32 | v2>>(64-32)
  136. // Round 3.
  137. v0 += v1
  138. v1 = v1<<13 | v1>>(64-13)
  139. v1 ^= v0
  140. v0 = v0<<32 | v0>>(64-32)
  141. v2 += v3
  142. v3 = v3<<16 | v3>>(64-16)
  143. v3 ^= v2
  144. v0 += v3
  145. v3 = v3<<21 | v3>>(64-21)
  146. v3 ^= v0
  147. v2 += v1
  148. v1 = v1<<17 | v1>>(64-17)
  149. v1 ^= v2
  150. v2 = v2<<32 | v2>>(64-32)
  151. // Round 4.
  152. v0 += v1
  153. v1 = v1<<13 | v1>>(64-13)
  154. v1 ^= v0
  155. v0 = v0<<32 | v0>>(64-32)
  156. v2 += v3
  157. v3 = v3<<16 | v3>>(64-16)
  158. v3 ^= v2
  159. v0 += v3
  160. v3 = v3<<21 | v3>>(64-21)
  161. v3 ^= v0
  162. v2 += v1
  163. v1 = v1<<17 | v1>>(64-17)
  164. v1 ^= v2
  165. v2 = v2<<32 | v2>>(64-32)
  166. r0 = v0 ^ v1 ^ v2 ^ v3
  167. v1 ^= 0xdd
  168. // Round 1.
  169. v0 += v1
  170. v1 = v1<<13 | v1>>(64-13)
  171. v1 ^= v0
  172. v0 = v0<<32 | v0>>(64-32)
  173. v2 += v3
  174. v3 = v3<<16 | v3>>(64-16)
  175. v3 ^= v2
  176. v0 += v3
  177. v3 = v3<<21 | v3>>(64-21)
  178. v3 ^= v0
  179. v2 += v1
  180. v1 = v1<<17 | v1>>(64-17)
  181. v1 ^= v2
  182. v2 = v2<<32 | v2>>(64-32)
  183. // Round 2.
  184. v0 += v1
  185. v1 = v1<<13 | v1>>(64-13)
  186. v1 ^= v0
  187. v0 = v0<<32 | v0>>(64-32)
  188. v2 += v3
  189. v3 = v3<<16 | v3>>(64-16)
  190. v3 ^= v2
  191. v0 += v3
  192. v3 = v3<<21 | v3>>(64-21)
  193. v3 ^= v0
  194. v2 += v1
  195. v1 = v1<<17 | v1>>(64-17)
  196. v1 ^= v2
  197. v2 = v2<<32 | v2>>(64-32)
  198. // Round 3.
  199. v0 += v1
  200. v1 = v1<<13 | v1>>(64-13)
  201. v1 ^= v0
  202. v0 = v0<<32 | v0>>(64-32)
  203. v2 += v3
  204. v3 = v3<<16 | v3>>(64-16)
  205. v3 ^= v2
  206. v0 += v3
  207. v3 = v3<<21 | v3>>(64-21)
  208. v3 ^= v0
  209. v2 += v1
  210. v1 = v1<<17 | v1>>(64-17)
  211. v1 ^= v2
  212. v2 = v2<<32 | v2>>(64-32)
  213. // Round 4.
  214. v0 += v1
  215. v1 = v1<<13 | v1>>(64-13)
  216. v1 ^= v0
  217. v0 = v0<<32 | v0>>(64-32)
  218. v2 += v3
  219. v3 = v3<<16 | v3>>(64-16)
  220. v3 ^= v2
  221. v0 += v3
  222. v3 = v3<<21 | v3>>(64-21)
  223. v3 ^= v0
  224. v2 += v1
  225. v1 = v1<<17 | v1>>(64-17)
  226. v1 ^= v2
  227. v2 = v2<<32 | v2>>(64-32)
  228. r1 = v0 ^ v1 ^ v2 ^ v3
  229. return r0, r1
  230. }
  231. func (d *digest) Sum(in []byte) []byte {
  232. if d.size == Size {
  233. r := d.Sum64()
  234. in = append(in,
  235. byte(r),
  236. byte(r>>8),
  237. byte(r>>16),
  238. byte(r>>24),
  239. byte(r>>32),
  240. byte(r>>40),
  241. byte(r>>48),
  242. byte(r>>56))
  243. } else {
  244. r0, r1 := d.sum128()
  245. in = append(in,
  246. byte(r0),
  247. byte(r0>>8),
  248. byte(r0>>16),
  249. byte(r0>>24),
  250. byte(r0>>32),
  251. byte(r0>>40),
  252. byte(r0>>48),
  253. byte(r0>>56),
  254. byte(r1),
  255. byte(r1>>8),
  256. byte(r1>>16),
  257. byte(r1>>24),
  258. byte(r1>>32),
  259. byte(r1>>40),
  260. byte(r1>>48),
  261. byte(r1>>56))
  262. }
  263. return in
  264. }