siphash.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. /* siphash.c
  2. *
  3. * Copyright (C) 2006-2023 wolfSSL Inc.
  4. *
  5. * This file is part of wolfSSL.
  6. *
  7. * wolfSSL is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * wolfSSL is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #include <wolfssl/wolfcrypt/settings.h>
  25. #include <wolfssl/wolfcrypt/types.h>
  26. #include <wolfssl/wolfcrypt/siphash.h>
  27. #include <wolfssl/wolfcrypt/error-crypt.h>
  28. #ifdef NO_INLINE
  29. #include <wolfssl/wolfcrypt/misc.h>
  30. #else
  31. #define WOLFSSL_MISC_INCLUDED
  32. #include <wolfcrypt/src/misc.c>
  33. #endif
  34. /* DESCRIPTION
  35. *
  36. * SipHash is a PseudoRandom Function (PRF) that can be used with small
  37. * messages (less than 256 bytes).
  38. * SipHash can be used for Message Authentication Codes (MACs) and as such must
  39. * be passed a secret key.
  40. * https://eprint.iacr.org/2012/351.pdf
  41. *
  42. * SipHash is commonly used in hash tables.
  43. * Do not use this as a hash not as a general purpose MAC.
  44. *
  45. * WOLFSSL_SIPHASH_CROUNDS and WOLFSSL_SIPHASH_DROUNDS can be defined at build
  46. * time to change the algorithm.
  47. * Default is SipHash-2-4:
  48. * WOLFSSL_SIPHASH_CROUNDS = 2
  49. * WOLFSSL_SIPHASH_DROUNDS = 4
  50. *
  51. * Inline assembly implementations of wc_SipHash() written for:
  52. * - GCC for Intel x86_64
  53. * - GCC for Aarch64.
  54. */
  55. #ifdef WOLFSSL_SIPHASH
  56. #ifdef LITTLE_ENDIAN_ORDER
  57. /**
  58. * Decode little-endian byte array to 64-bit number.
  59. *
  60. * @param [in] a Little-endian byte array.
  61. * @return 64-bit number.
  62. */
  63. #define GET_U64(a) (*(word64*)(a))
  64. /**
  65. * Decode little-endian byte array to 32-bit number.
  66. *
  67. * @param [in] a Little-endian byte array.
  68. * @return 32-bit number.
  69. */
  70. #define GET_U32(a) (*(word32*)(a))
  71. /**
  72. * Decode little-endian byte array to 16-bit number.
  73. *
  74. * @param [in] a Little-endian byte array.
  75. * @return 16-bit number.
  76. */
  77. #define GET_U16(a) (*(word16*)(a))
  78. /**
  79. * Encode 64-bit number to a little-endian byte array.
  80. *
  81. * @param [out] a Byte array to write into.
  82. * @param [in] n Number to encode.
  83. */
  84. #define SET_U64(a, n) ((*(word64*)(a)) = (n))
  85. #else
  86. /**
  87. * Decode little-endian byte array to 64-bit number.
  88. *
  89. * @param [in] a Little-endian byte array.
  90. * @return 64-bit number.
  91. */
  92. #define GET_U64(a) (((word64)((a)[7]) << 56) | \
  93. ((word64)((a)[6]) << 48) | \
  94. ((word64)((a)[5]) << 40) | \
  95. ((word64)((a)[4]) << 32) | \
  96. ((word64)((a)[3]) << 24) | \
  97. ((word64)((a)[2]) << 16) | \
  98. ((word64)((a)[1]) << 8) | \
  99. ((word64)((a)[0]) ))
  100. /**
  101. * Decode little-endian byte array to 32-bit number.
  102. *
  103. * @param [in] a Little-endian byte array.
  104. * @return 32-bit number.
  105. */
  106. #define GET_U32(a) (((word64)((a)[3]) << 24) | \
  107. ((word32)((a)[2]) << 16) | \
  108. ((word32)((a)[1]) << 8) | \
  109. ((word32)((a)[0]) ))
  110. /**
  111. * Decode little-endian byte array to 16-bit number.
  112. *
  113. * @param [in] a Little-endian byte array.
  114. * @return 16-bit number.
  115. */
  116. #define GET_U16(a) (((word16)((a)[1]) << 8) | \
  117. ((word16)((a)[0]) ))
  118. /**
  119. * Encode 64-bit number to a little-endian byte array.
  120. *
  121. * @param [out] a Byte array to write into.
  122. * @param [in] n Number to encode.
  123. */
  124. #define SET_U64(a, n) (a)[0] = (byte)((n) ); \
  125. (a)[1] = (byte)((n) >> 8); \
  126. (a)[2] = (byte)((n) >> 16); \
  127. (a)[3] = (byte)((n) >> 24); \
  128. (a)[4] = (byte)((n) >> 32); \
  129. (a)[5] = (byte)((n) >> 40); \
  130. (a)[6] = (byte)((n) >> 48); \
  131. (a)[7] = (byte)((n) >> 56)
  132. #endif
  133. /**
  134. * Initialize SipHash operation with a key.
  135. *
  136. * @param [out] sipHash SipHash object.
  137. * @param [in] key 16 byte array - little endian.
  138. * @return BAD_FUNC_ARG when sipHash or key is NULL.
  139. * @return BAD_FUNC_ARG when outSz is neither 8 nor 16.
  140. * @return 0 on success.
  141. */
  142. int wc_InitSipHash(SipHash* sipHash, const unsigned char* key,
  143. unsigned char outSz)
  144. {
  145. int ret = 0;
  146. /* Validate parameters. */
  147. if ((sipHash == NULL) || (key == NULL) ||
  148. ((outSz != SIPHASH_MAC_SIZE_8) && (outSz != SIPHASH_MAC_SIZE_16))) {
  149. ret = BAD_FUNC_ARG;
  150. }
  151. if (ret == 0) {
  152. word64 k0 = GET_U64(key + 0);
  153. word64 k1 = GET_U64(key + 8);
  154. /* Initialize state with key. */
  155. sipHash->v[0] = W64LIT(0x736f6d6570736575);
  156. if (outSz == SIPHASH_MAC_SIZE_8) {
  157. sipHash->v[1] = W64LIT(0x646f72616e646f6d);
  158. }
  159. else {
  160. sipHash->v[1] = W64LIT(0x646f72616e646f83);
  161. }
  162. sipHash->v[2] = W64LIT(0x6c7967656e657261);
  163. sipHash->v[3] = W64LIT(0x7465646279746573);
  164. sipHash->v[0] ^= k0;
  165. sipHash->v[1] ^= k1;
  166. sipHash->v[2] ^= k0;
  167. sipHash->v[3] ^= k1;
  168. /* No cached message bytes. */
  169. sipHash->cacheCnt = 0;
  170. /* No message bytes compressed yet. */
  171. sipHash->inCnt = 0;
  172. /* Keep the output size to check against final call. */
  173. sipHash->outSz = outSz;
  174. }
  175. return ret;
  176. }
  177. /**
  178. * One round of SipHash.
  179. *
  180. * @param [in, out] sipHash SipHash object.
  181. */
  182. static WC_INLINE void SipRound(SipHash *sipHash)
  183. {
  184. word64* v = sipHash->v;
  185. v[0] += v[1];
  186. v[2] += v[3];
  187. v[1] = rotlFixed64(v[1], 13);
  188. v[3] = rotlFixed64(v[3], 16);
  189. v[1] ^= v[0];
  190. v[3] ^= v[2];
  191. v[0] = rotlFixed64(v[0], 32);
  192. v[2] += v[1];
  193. v[0] += v[3];
  194. v[1] = rotlFixed64(v[1], 17);
  195. v[3] = rotlFixed64(v[3], 21);
  196. v[1] ^= v[2];
  197. v[3] ^= v[0];
  198. v[2] = rotlFixed64(v[2], 32);
  199. }
  200. /**
  201. * One step of the compression operation.
  202. *
  203. * @param [in, out] sipHash SipHash object.
  204. * @param [in] m Message to compress.
  205. */
  206. static WC_INLINE void SipHashCompress(SipHash* sipHash, const byte* m)
  207. {
  208. int i;
  209. sipHash->v[3] ^= GET_U64(m);
  210. for (i = 0; i < WOLFSSL_SIPHASH_CROUNDS; i++) {
  211. SipRound(sipHash);
  212. }
  213. sipHash->v[0] ^= GET_U64(m);
  214. }
  215. /**
  216. * Update the SipHash operation with more data.
  217. *
  218. * @param [in, out] sipHash SipHash object.
  219. * @param [in] in Input message.
  220. * @param [in] inSz Size of input message.
  221. * @return BAD_FUNC_ARG when sipHash is NULL.
  222. * @return BAD_FUNC_ARG when in is NULL and inSz is not zero.
  223. * @return 0 on success.
  224. */
  225. int wc_SipHashUpdate(SipHash* sipHash, const unsigned char* in, word32 inSz)
  226. {
  227. int ret = 0;
  228. /* Validate parameters. */
  229. if ((sipHash == NULL) || ((in == NULL) && (inSz != 0))) {
  230. ret = BAD_FUNC_ARG;
  231. }
  232. /* Process any message bytes. */
  233. if ((ret == 0) && (inSz > 0)) {
  234. /* Add to cache if already started. */
  235. if (sipHash->cacheCnt > 0) {
  236. byte len = SIPHASH_BLOCK_SIZE - sipHash->cacheCnt;
  237. if (len > inSz) {
  238. len = (byte)inSz;
  239. }
  240. XMEMCPY(sipHash->cache + sipHash->cacheCnt, in, len);
  241. in += len;
  242. inSz -= len;
  243. sipHash->cacheCnt += len;
  244. if (sipHash->cacheCnt == SIPHASH_BLOCK_SIZE) {
  245. /* Compress the block from the cache. */
  246. SipHashCompress(sipHash, sipHash->cache);
  247. sipHash->inCnt += SIPHASH_BLOCK_SIZE;
  248. sipHash->cacheCnt = 0;
  249. }
  250. }
  251. /* Process more blocks from message. */
  252. while (inSz >= SIPHASH_BLOCK_SIZE) {
  253. /* Compress the next block from the message data. */
  254. SipHashCompress(sipHash, in);
  255. in += SIPHASH_BLOCK_SIZE;
  256. inSz -= SIPHASH_BLOCK_SIZE;
  257. sipHash->inCnt += SIPHASH_BLOCK_SIZE;
  258. }
  259. if (inSz > 0) {
  260. /* Cache remaining message bytes less than a block. */
  261. XMEMCPY(sipHash->cache, in, inSz);
  262. sipHash->cacheCnt = (byte)inSz;
  263. }
  264. }
  265. return ret;
  266. }
  267. /**
  268. * Calculate 8-bytes of output.
  269. *
  270. * @param [in, out] sipHash SipHash object.
  271. * @param [out] out Buffer to place 8-bytes of MAC into.
  272. */
  273. static WC_INLINE void SipHashOut(SipHash* sipHash, byte* out)
  274. {
  275. word64 n;
  276. int i;
  277. for (i = 0; i < WOLFSSL_SIPHASH_DROUNDS; i++) {
  278. SipRound(sipHash);
  279. }
  280. n = sipHash->v[0] ^ sipHash->v[1] ^ sipHash->v[2] ^ sipHash->v[3];
  281. SET_U64(out, n);
  282. }
  283. /**
  284. * Finalize SipHash operation.
  285. *
  286. * @param [in, out] sipHash SipHash object.
  287. * @param [out] out Buffer to place MAC into.
  288. * @param [in] outSz Size of output MAC. 8 or 16 only.
  289. * @return BAD_FUNC_ARG when sipHash or out is NULL.
  290. * @return BAD_FUNC_ARG when outSz is not the same as initialized value.
  291. * @return 0 on success.
  292. */
  293. int wc_SipHashFinal(SipHash* sipHash, unsigned char* out, unsigned char outSz)
  294. {
  295. int ret = 0;
  296. /* Validate parameters. */
  297. if ((sipHash == NULL) || (out == NULL) || (outSz != sipHash->outSz)) {
  298. ret = BAD_FUNC_ARG;
  299. }
  300. if (ret == 0) {
  301. /* Put in remaining cached message bytes. */
  302. XMEMSET(sipHash->cache + sipHash->cacheCnt, 0, 7 - sipHash->cacheCnt);
  303. sipHash->cache[7] = (byte)(sipHash->inCnt + sipHash->cacheCnt);
  304. SipHashCompress(sipHash, sipHash->cache);
  305. sipHash->cacheCnt = 0;
  306. /* Output either 8 or 16 bytes. */
  307. if (outSz == SIPHASH_MAC_SIZE_8) {
  308. sipHash->v[2] ^= (word64)0xff;
  309. SipHashOut(sipHash, out);
  310. }
  311. else {
  312. sipHash->v[2] ^= (word64)0xee;
  313. SipHashOut(sipHash, out);
  314. sipHash->v[1] ^= (word64)0xdd;
  315. SipHashOut(sipHash, out + 8);
  316. }
  317. }
  318. return ret;
  319. }
  320. #if !defined(WOLFSSL_NO_ASM) && defined(__GNUC__) && defined(__x86_64__) && \
  321. (WOLFSSL_SIPHASH_CROUNDS == 1 || WOLFSSL_SIPHASH_CROUNDS == 2) && \
  322. (WOLFSSL_SIPHASH_DROUNDS == 2 || WOLFSSL_SIPHASH_DROUNDS == 4)
  323. #define SIPHASH_ROUND(v0, v1, v2, v3) \
  324. "addq " #v1 ", " #v0 "\n\t" \
  325. "addq " #v3 ", " #v2 "\n\t" \
  326. "rolq $13, " #v1 "\n\t" \
  327. "rolq $16, " #v3 "\n\t" \
  328. "xorq " #v0 ", " #v1 "\n\t" \
  329. "xorq " #v2 ", " #v3 "\n\t" \
  330. "rolq $32, " #v0 "\n\t" \
  331. "addq " #v1 ", " #v2 "\n\t" \
  332. "addq " #v3 ", " #v0 "\n\t" \
  333. "rolq $17, " #v1 "\n\t" \
  334. "rolq $21, " #v3 "\n\t" \
  335. "xorq " #v2 ", " #v1 "\n\t" \
  336. "xorq " #v0 ", " #v3 "\n\t" \
  337. "rolq $32, " #v2 "\n\t"
  338. #define SIPHASH_LAST_ROUND(v0, v1, v2, v3) \
  339. "addq " #v1 ", " #v0 "\n\t" \
  340. "addq " #v3 ", " #v2 "\n\t" \
  341. "rolq $13, " #v1 "\n\t" \
  342. "rolq $16, " #v3 "\n\t" \
  343. "xorq " #v0 ", " #v1 "\n\t" \
  344. "xorq " #v2 ", " #v3 "\n\t" \
  345. "addq " #v1 ", " #v2 "\n\t" \
  346. "rolq $17, " #v1 "\n\t" \
  347. "rolq $21, " #v3 "\n\t" \
  348. "xorq " #v2 ", " #v1 "\n\t" \
  349. "rolq $32, " #v2 "\n\t"
  350. /**
  351. * Perform SipHash operation on input with key.
  352. *
  353. * @param [in] key 16 byte array - little endian.
  354. * @param [in] in Input message.
  355. * @param [in] inSz Size of input message.
  356. * @param [out] out Buffer to place MAC into.
  357. * @param [in] outSz Size of output MAC. 8 or 16 only.
  358. * @return BAD_FUNC_ARG when key or out is NULL.
  359. * @return BAD_FUNC_ARG when in is NULL and inSz is not zero.
  360. * @return BAD_FUNC_ARG when outSz is neither 8 nor 16.
  361. * @return 0 on success.
  362. */
  363. int wc_SipHash(const unsigned char* key, const unsigned char* in, word32 inSz,
  364. unsigned char* out, unsigned char outSz)
  365. {
  366. word64 v0 = 0x736f6d6570736575L;
  367. word64 v1 = 0x646f72616e646f6dL;
  368. word64 v2 = 0x6c7967656e657261L;
  369. word64 v3 = 0x7465646279746573L;
  370. word64 k0;
  371. word64 k1;
  372. if ((key == NULL) || ((in == NULL) && (inSz != 0)) || (out == NULL) ||
  373. ((outSz != SIPHASH_MAC_SIZE_8) && (outSz != SIPHASH_MAC_SIZE_16))) {
  374. return BAD_FUNC_ARG;
  375. }
  376. k0 = ((word64*)key)[0];
  377. k1 = ((word64*)key)[1];
  378. __asm__ __volatile__ (
  379. "xorq %[k0], %[v0]\n\t"
  380. "xorq %[k1], %[v1]\n\t"
  381. "xorq %[k0], %[v2]\n\t"
  382. "xorq %[k1], %[v3]\n\t"
  383. "cmp $8, %[outSz]\n\t"
  384. "mov %[inSz], %k[k1]\n\t"
  385. "je L_siphash_8_top\n\t"
  386. "xorq $0xee, %[v1]\n\t"
  387. "L_siphash_8_top:\n\t"
  388. "sub $8, %[inSz]\n\t"
  389. "jb L_siphash_done_input_8\n\t"
  390. "L_siphash_input:\n\t"
  391. "movq (%[in]), %[k0]\n\t"
  392. "addq $8, %[in]\n\t"
  393. "xorq %[k0], %[v3]\n\t"
  394. #if WOLFSSL_SIPHASH_CROUNDS == 1
  395. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  396. #elif WOLFSSL_SIPHASH_CROUNDS == 2
  397. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  398. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  399. #endif
  400. "xorq %[k0], %[v0]\n\t"
  401. "sub $8, %[inSz]\n\t"
  402. "jge L_siphash_input\n\t"
  403. "L_siphash_done_input_8:\n\t"
  404. "add $8, %[inSz]\n\t"
  405. "shlq $56, %[k1]\n\t"
  406. "cmp $0, %[inSz]\n\t"
  407. "je L_siphash_last_done\n\t"
  408. "cmp $4, %[inSz]\n\t"
  409. "jl L_siphash_last_lt4\n\t"
  410. "cmp $7, %[inSz]\n\t"
  411. "jl L_siphash_n7\n\t"
  412. "movzbq 6(%[in]), %[k0]\n\t"
  413. "shlq $48, %[k0]\n\t"
  414. "orq %[k0], %[k1]\n\t"
  415. "L_siphash_n7:\n\t"
  416. "cmp $6, %[inSz]\n\t"
  417. "jl L_siphash_n6\n\t"
  418. "movzbq 5(%[in]), %[k0]\n\t"
  419. "shlq $40, %[k0]\n\t"
  420. "orq %[k0], %[k1]\n\t"
  421. "L_siphash_n6:\n\t"
  422. : [in] "+r" (in), [inSz] "+r" (inSz), [k0] "+r" (k0), [k1] "+r" (k1),
  423. [v0] "+r" (v0), [v1] "+r" (v1), [v2] "+r" (v2), [v3] "+r" (v3)
  424. : [key] "r" (key), [out] "r" (out) , [outSz] "r" (outSz)
  425. : "memory"
  426. );
  427. __asm__ __volatile__ (
  428. "cmp $5, %[inSz]\n\t"
  429. "jl L_siphash_n5\n\t"
  430. "movzbq 4(%[in]), %[k0]\n\t"
  431. "shlq $32, %[k0]\n\t"
  432. "orq %[k0], %[k1]\n\t"
  433. "L_siphash_n5:\n\t"
  434. "mov (%[in]), %k[k0]\n\t"
  435. "orq %[k0], %[k1]\n\t"
  436. "jmp L_siphash_last_done\n\t"
  437. "L_siphash_last_lt4:\n\t"
  438. "cmp $1, %[inSz]\n\t"
  439. "je L_siphash_last_1\n\t"
  440. "cmp $3, %[inSz]\n\t"
  441. "jl L_siphash_n3\n\t"
  442. "movzbq 2(%[in]), %[k0]\n\t"
  443. "shlq $16, %[k0]\n\t"
  444. "orq %[k0], %[k1]\n\t"
  445. "L_siphash_n3:\n\t"
  446. "movw (%[in]), %w[k0]\n\t"
  447. "or %w[k0], %w[k1]\n\t"
  448. "jmp L_siphash_last_done\n\t"
  449. "L_siphash_last_1:\n\t"
  450. "movb (%[in]), %b[k0]\n\t"
  451. "or %b[k0], %b[k1]\n\t"
  452. "L_siphash_last_done:\n\t"
  453. "xorq %[k1], %[v3]\n\t"
  454. #if WOLFSSL_SIPHASH_CROUNDS == 1
  455. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  456. #elif WOLFSSL_SIPHASH_CROUNDS == 2
  457. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  458. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  459. #endif
  460. "xorq %[k1], %[v0]\n\t"
  461. "cmp $8, %[outSz]\n\t"
  462. "je L_siphash_8_end\n\t"
  463. : [in] "+r" (in), [inSz] "+r" (inSz), [k0] "+r" (k0), [k1] "+r" (k1),
  464. [v0] "+r" (v0), [v1] "+r" (v1), [v2] "+r" (v2), [v3] "+r" (v3)
  465. : [key] "r" (key), [out] "r" (out) , [outSz] "r" (outSz)
  466. : "memory"
  467. );
  468. __asm__ __volatile__ (
  469. "xor $0xee, %b[v2]\n\t"
  470. #if WOLFSSL_SIPHASH_DROUNDS == 2
  471. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  472. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  473. #elif WOLFSSL_SIPHASH_DROUNDS == 4
  474. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  475. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  476. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  477. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  478. #endif
  479. "movq %[v0], %[k0]\n\t"
  480. "xorq %[v1], %[k0]\n\t"
  481. "xorq %[v2], %[k0]\n\t"
  482. "xorq %[v3], %[k0]\n\t"
  483. "movq %[k0], (%[out])\n\t"
  484. "xor $0xdd, %b[v1]\n\t"
  485. #if WOLFSSL_SIPHASH_DROUNDS == 2
  486. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  487. SIPHASH_LAST_ROUND(%[v0], %[v1], %[v2], %[v3])
  488. #elif WOLFSSL_SIPHASH_DROUNDS == 4
  489. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  490. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  491. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  492. SIPHASH_LAST_ROUND(%[v0], %[v1], %[v2], %[v3])
  493. #endif
  494. "xorq %[v3], %[v1]\n\t"
  495. "xorq %[v2], %[v1]\n\t"
  496. "movq %[v1], 8(%[out])\n\t"
  497. "jmp L_siphash_done\n\t"
  498. "L_siphash_8_end:\n\t"
  499. "xor $0xff, %b[v2]\n\t"
  500. #if WOLFSSL_SIPHASH_DROUNDS == 2
  501. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  502. SIPHASH_LAST_ROUND(%[v0], %[v1], %[v2], %[v3])
  503. #elif WOLFSSL_SIPHASH_DROUNDS == 4
  504. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  505. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  506. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  507. SIPHASH_LAST_ROUND(%[v0], %[v1], %[v2], %[v3])
  508. #endif
  509. "xorq %[v3], %[v1]\n\t"
  510. "xorq %[v2], %[v1]\n\t"
  511. "movq %[v1], (%[out])\n\t"
  512. "L_siphash_done:\n\t"
  513. : [in] "+r" (in), [inSz] "+r" (inSz), [k0] "+r" (k0), [k1] "+r" (k1),
  514. [v0] "+r" (v0), [v1] "+r" (v1), [v2] "+r" (v2), [v3] "+r" (v3)
  515. : [key] "r" (key), [out] "r" (out) , [outSz] "r" (outSz)
  516. : "memory"
  517. );
  518. return 0;
  519. }
  520. #elif !defined(WOLFSSL_NO_ASM) && defined(__GNUC__) && defined(__aarch64__) && \
  521. (WOLFSSL_SIPHASH_CROUNDS == 1 || WOLFSSL_SIPHASH_CROUNDS == 2) && \
  522. (WOLFSSL_SIPHASH_DROUNDS == 2 || WOLFSSL_SIPHASH_DROUNDS == 4)
  523. #define SIPHASH_ROUND(v0, v1, v2, v3) \
  524. "add " #v0 ", " #v0 ", " #v1 "\n\t" \
  525. "add " #v2 ", " #v2 ", " #v3 "\n\t" \
  526. "ror " #v1 ", " #v1 ", #51\n\t" \
  527. "ror " #v3 ", " #v3 ", #48\n\t" \
  528. "eor " #v1 ", " #v1 ", " #v0 "\n\t" \
  529. "eor " #v3 ", " #v3 ", " #v2 "\n\t" \
  530. "ror " #v0 ", " #v0 ", #32\n\t" \
  531. "add " #v2 ", " #v2 ", " #v1 "\n\t" \
  532. "add " #v0 ", " #v0 ", " #v3 "\n\t" \
  533. "ror " #v1 ", " #v1 ", #47\n\t" \
  534. "ror " #v3 ", " #v3 ", #43\n\t" \
  535. "eor " #v1 ", " #v1 ", " #v2 "\n\t" \
  536. "eor " #v3 ", " #v3 ", " #v0 "\n\t" \
  537. "ror " #v2 ", " #v2 ", #32\n\t"
  538. #define SIPHASH_LAST_ROUND(v0, v1, v2, v3) \
  539. "add " #v0 ", " #v0 ", " #v1 "\n\t" \
  540. "add " #v2 ", " #v2 ", " #v3 "\n\t" \
  541. "ror " #v1 ", " #v1 ", #51\n\t" \
  542. "ror " #v3 ", " #v3 ", #48\n\t" \
  543. "eor " #v1 ", " #v1 ", " #v0 "\n\t" \
  544. "eor " #v3 ", " #v3 ", " #v2 "\n\t" \
  545. "add " #v2 ", " #v2 ", " #v1 "\n\t" \
  546. "ror " #v1 ", " #v1 ", #47\n\t" \
  547. "ror " #v3 ", " #v3 ", #43\n\t" \
  548. "eor " #v1 ", " #v1 ", " #v2 "\n\t" \
  549. "ror " #v2 ", " #v2 ", #32\n\t"
  550. /**
  551. * Perform SipHash operation on input with key.
  552. *
  553. * @param [in] key 16 byte array - little endian.
  554. * @param [in] in Input message.
  555. * @param [in] inSz Size of input message.
  556. * @param [out] out Buffer to place MAC into.
  557. * @param [in] outSz Size of output MAC. 8 or 16 only.
  558. * @return BAD_FUNC_ARG when key or out is NULL.
  559. * @return BAD_FUNC_ARG when in is NULL and inSz is not zero.
  560. * @return BAD_FUNC_ARG when outSz is not 8 nor 16.
  561. * @return 0 on success.
  562. */
  563. int wc_SipHash(const unsigned char* key, const unsigned char* in, word32 inSz,
  564. unsigned char* out, unsigned char outSz)
  565. {
  566. word64 v0 = 0x736f6d6570736575L;
  567. word64 v1 = 0x646f72616e646f6dL;
  568. word64 v2 = 0x6c7967656e657261L;
  569. word64 v3 = 0x7465646279746573L;
  570. word64 k0;
  571. word64 k1;
  572. if ((key == NULL) || ((in == NULL) && (inSz != 0)) || (out == NULL) ||
  573. ((outSz != SIPHASH_MAC_SIZE_8) && (outSz != SIPHASH_MAC_SIZE_16))) {
  574. return BAD_FUNC_ARG;
  575. }
  576. k0 = ((word64*)key)[0];
  577. k1 = ((word64*)key)[1];
  578. __asm__ __volatile__ (
  579. "eor %[v0], %[v0], %[k0]\n\t"
  580. "eor %[v1], %[v1], %[k1]\n\t"
  581. "eor %[v2], %[v2], %[k0]\n\t"
  582. "eor %[v3], %[v3], %[k1]\n\t"
  583. "mov %w[k1], %w[inSz]\n\t"
  584. "cmp %w[outSz], #8\n\t"
  585. "b.eq L_siphash_8_top\n\t"
  586. "mov %w[k0], #0xee\n\t"
  587. "eor %[v1], %[v1], %[k0]\n\t"
  588. "L_siphash_8_top:\n\t"
  589. "subs %w[inSz], %w[inSz], #8\n\t"
  590. "b.mi L_siphash_done_input_8\n\t"
  591. "L_siphash_input:\n\t"
  592. "ldr %[k0], [%[in]], #8\n\t"
  593. "eor %[v3], %[v3], %[k0]\n\t"
  594. #if WOLFSSL_SIPHASH_CROUNDS == 1
  595. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  596. #elif WOLFSSL_SIPHASH_CROUNDS == 2
  597. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  598. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  599. #endif
  600. "eor %[v0], %[v0], %[k0]\n\t"
  601. "subs %w[inSz], %w[inSz], #8\n\t"
  602. "b.ge L_siphash_input\n\t"
  603. "L_siphash_done_input_8:\n\t"
  604. "add %w[inSz], %w[inSz], #8\n\t"
  605. "lsl %[k1], %[k1], #56\n\t"
  606. "cmp %w[inSz], #0\n\t"
  607. "b.eq L_siphash_last_done\n\t"
  608. "cmp %w[inSz], #4\n\t"
  609. "b.lt L_siphash_last_lt4\n\t"
  610. "cmp %w[inSz], #7\n\t"
  611. "b.lt L_siphash_n7\n\t"
  612. "ldrb %w[k0], [%[in], 6]\n\t"
  613. "orr %[k1], %[k1], %[k0], lsl 48\n\t"
  614. "L_siphash_n7:\n\t"
  615. "cmp %w[inSz], #6\n\t"
  616. "b.lt L_siphash_n6\n\t"
  617. "ldrb %w[k0], [%[in], 5]\n\t"
  618. "orr %[k1], %[k1], %[k0], lsl 40\n\t"
  619. "L_siphash_n6:\n\t"
  620. "cmp %w[inSz], #5\n\t"
  621. "b.lt L_siphash_n5\n\t"
  622. "ldrb %w[k0], [%[in], 4]\n\t"
  623. "orr %[k1], %[k1], %[k0], lsl 32\n\t"
  624. "L_siphash_n5:\n\t"
  625. "ldr %w[k0], [%[in]]\n\t"
  626. "orr %[k1], %[k1], %[k0]\n\t"
  627. "b L_siphash_last_done\n\t"
  628. "L_siphash_last_lt4:\n\t"
  629. "cmp %w[inSz], #1\n\t"
  630. "b.eq L_siphash_last_1\n\t"
  631. "cmp %w[inSz], #3\n\t"
  632. "b.lt L_siphash_n3\n\t"
  633. "ldrb %w[k0], [%[in], 2]\n\t"
  634. "orr %[k1], %[k1], %[k0], lsl 16\n\t"
  635. "L_siphash_n3:\n\t"
  636. "ldrh %w[k0], [%[in]]\n\t"
  637. "orr %[k1], %[k1], %[k0]\n\t"
  638. "b L_siphash_last_done\n\t"
  639. "L_siphash_last_1:\n\t"
  640. "ldrb %w[k0], [%[in]]\n\t"
  641. "orr %[k1], %[k1], %[k0]\n\t"
  642. "L_siphash_last_done:\n\t"
  643. "eor %[v3], %[v3], %[k1]\n\t"
  644. #if WOLFSSL_SIPHASH_CROUNDS == 1
  645. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  646. #elif WOLFSSL_SIPHASH_CROUNDS == 2
  647. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  648. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  649. #endif
  650. "eor %[v0], %[v0], %[k1]\n\t"
  651. "cmp %w[outSz], #8\n\t"
  652. "b.eq L_siphash_8_end\n\t"
  653. : [in] "+r" (in), [inSz] "+r" (inSz), [k0] "+r" (k0), [k1] "+r" (k1),
  654. [v0] "+r" (v0), [v1] "+r" (v1), [v2] "+r" (v2), [v3] "+r" (v3)
  655. : [key] "r" (key), [out] "r" (out) , [outSz] "r" (outSz)
  656. : "memory"
  657. );
  658. __asm__ __volatile__ (
  659. "mov %w[k1], #0xee\n\t"
  660. "eor %[v2], %[v2], %[k1]\n\t"
  661. #if WOLFSSL_SIPHASH_DROUNDS == 2
  662. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  663. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  664. #elif WOLFSSL_SIPHASH_DROUNDS == 4
  665. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  666. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  667. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  668. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  669. #endif
  670. "eor %[k0], %[v0], %[v1]\n\t"
  671. "eor %[k1], %[v2], %[v3]\n\t"
  672. "eor %[k0], %[k0], %[k1]\n\t"
  673. "mov %w[k1], #0xdd\n\t"
  674. "eor %[v1], %[v1], %[k1]\n\t"
  675. #if WOLFSSL_SIPHASH_DROUNDS == 2
  676. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  677. SIPHASH_LAST_ROUND(%[v0], %[v1], %[v2], %[v3])
  678. #elif WOLFSSL_SIPHASH_DROUNDS == 4
  679. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  680. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  681. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  682. SIPHASH_LAST_ROUND(%[v0], %[v1], %[v2], %[v3])
  683. #endif
  684. "eor %[k1], %[v3], %[v1]\n\t"
  685. "eor %[k1], %[k1], %[v2]\n\t"
  686. "stp %[k0], %[k1], [%[out]]\n\t"
  687. "b L_siphash_done\n\t"
  688. "L_siphash_8_end:\n\t"
  689. "mov %w[k1], #0xff\n\t"
  690. "eor %[v2], %[v2], %[k1]\n\t"
  691. #if WOLFSSL_SIPHASH_DROUNDS == 2
  692. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  693. SIPHASH_LAST_ROUND(%[v0], %[v1], %[v2], %[v3])
  694. #elif WOLFSSL_SIPHASH_DROUNDS == 4
  695. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  696. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  697. SIPHASH_ROUND(%[v0], %[v1], %[v2], %[v3])
  698. SIPHASH_LAST_ROUND(%[v0], %[v1], %[v2], %[v3])
  699. #endif
  700. "eor %[k1], %[v3], %[v1]\n\t"
  701. "eor %[k1], %[k1], %[v2]\n\t"
  702. "str %[k1], [%[out]]\n\t"
  703. "L_siphash_done:\n\t"
  704. : [in] "+r" (in), [inSz] "+r" (inSz), [k0] "+r" (k0), [k1] "+r" (k1),
  705. [v0] "+r" (v0), [v1] "+r" (v1), [v2] "+r" (v2), [v3] "+r" (v3)
  706. : [key] "r" (key), [out] "r" (out) , [outSz] "r" (outSz)
  707. : "memory"
  708. );
  709. return 0;
  710. }
  711. #else
  712. #define SipRoundV(v0, v1, v2, v3) \
  713. v0 += v1; \
  714. v2 += v3; \
  715. v1 = rotlFixed64(v1, 13); \
  716. v3 = rotlFixed64(v3, 16); \
  717. v1 ^= v0; \
  718. v3 ^= v2; \
  719. v0 = rotlFixed64(v0, 32); \
  720. v2 += v1; \
  721. v0 += v3; \
  722. v1 = rotlFixed64(v1, 17); \
  723. v3 = rotlFixed64(v3, 21); \
  724. v1 ^= v2; \
  725. v3 ^= v0; \
  726. v2 = rotlFixed64(v2, 32);
  727. #define SipHashCompressV(v0, v1, v2, v3, m) \
  728. do { \
  729. int i; \
  730. v3 ^= m; \
  731. for (i = 0; i < WOLFSSL_SIPHASH_CROUNDS; i++) { \
  732. SipRoundV(v0, v1, v2, v3); \
  733. } \
  734. v0 ^= m; \
  735. } \
  736. while (0)
  737. #define SipHashOutV(v0, v1, v2, v3, out) \
  738. do { \
  739. word64 n; \
  740. int i; \
  741. \
  742. for (i = 0; i < WOLFSSL_SIPHASH_DROUNDS; i++) { \
  743. SipRoundV(v0, v1, v2, v3); \
  744. } \
  745. n = v0 ^ v1 ^ v2 ^ v3; \
  746. SET_U64(out, n); \
  747. } \
  748. while (0)
  749. /**
  750. * Perform SipHash operation on input with key.
  751. *
  752. * @param [in] key 16 byte array - little endian.
  753. * @param [in] in Input message.
  754. * @param [in] inSz Size of input message.
  755. * @param [out] out Buffer to place MAC into.
  756. * @param [in] outSz Size of output MAC. 8 or 16 only.
  757. * @return BAD_FUNC_ARG when key or out is NULL.
  758. * @return BAD_FUNC_ARG when in is NULL and inSz is not zero.
  759. * @return BAD_FUNC_ARG when outSz is not 8 nor 16.
  760. * @return 0 on success.
  761. */
  762. int wc_SipHash(const unsigned char* key, const unsigned char* in, word32 inSz,
  763. unsigned char* out, unsigned char outSz)
  764. {
  765. int ret = 0;
  766. if ((key == NULL) || ((in == NULL) && (inSz != 0)) || (out == NULL) ||
  767. ((outSz != SIPHASH_MAC_SIZE_8) && (outSz != SIPHASH_MAC_SIZE_16))) {
  768. ret = BAD_FUNC_ARG;
  769. }
  770. if (ret == 0) {
  771. word64 v0, v1, v2, v3;
  772. word64 k0 = GET_U64(key + 0);
  773. word64 k1 = GET_U64(key + 8);
  774. word64 b = (word64)((word64)inSz << 56);
  775. /* Initialize state with key. */
  776. v0 = 0x736f6d6570736575ULL;
  777. v1 = 0x646f72616e646f6dULL;
  778. v2 = 0x6c7967656e657261ULL;
  779. v3 = 0x7465646279746573ULL;
  780. if (outSz == SIPHASH_MAC_SIZE_16) {
  781. v1 ^= 0xee;
  782. }
  783. v0 ^= k0;
  784. v1 ^= k1;
  785. v2 ^= k0;
  786. v3 ^= k1;
  787. /* Process blocks from message. */
  788. while (inSz >= SIPHASH_BLOCK_SIZE) {
  789. word64 m = GET_U64(in);
  790. /* Compress the next block from the message data. */
  791. SipHashCompressV(v0, v1, v2, v3, m);
  792. in += SIPHASH_BLOCK_SIZE;
  793. inSz -= SIPHASH_BLOCK_SIZE;
  794. }
  795. switch (inSz) {
  796. case 7:
  797. b |= (word64)in[6] << 48;
  798. FALL_THROUGH;
  799. case 6:
  800. b |= (word64)in[5] << 40;
  801. FALL_THROUGH;
  802. case 5:
  803. b |= (word64)in[4] << 32;
  804. FALL_THROUGH;
  805. case 4:
  806. b |= (word64)GET_U32(in);
  807. break;
  808. case 3:
  809. b |= (word64)in[2] << 16;
  810. FALL_THROUGH;
  811. case 2:
  812. b |= (word64)GET_U16(in);
  813. break;
  814. case 1:
  815. b |= (word64)in[0];
  816. break;
  817. case 0:
  818. break;
  819. }
  820. SipHashCompressV(v0, v1, v2, v3, b);
  821. /* Output either 8 or 16 bytes. */
  822. if (outSz == SIPHASH_MAC_SIZE_8) {
  823. v2 ^= (word64)0xff;
  824. SipHashOutV(v0, v1, v2, v3, out);
  825. }
  826. else {
  827. v2 ^= (word64)0xee;
  828. SipHashOutV(v0, v1, v2, v3, out);
  829. v1 ^= (word64)0xdd;
  830. SipHashOutV(v0, v1, v2, v3, out + 8);
  831. }
  832. }
  833. return ret;
  834. }
  835. #endif /* !ASM */
  836. #endif /* WOLFSSL_SIPHASH */