keccak-tiny-unrolled.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /** libkeccak-tiny
  2. *
  3. * A single-file implementation of SHA-3 and SHAKE.
  4. *
  5. * Implementor: David Leon Gil
  6. * License: CC0, attribution kindly requested. Blame taken too,
  7. * but not liability.
  8. */
  9. #include "keccak-tiny.h"
  10. #include <stdint.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. /******** The Keccak-f[1600] permutation ********/
  15. /*** Constants. ***/
  16. static const uint8_t rho[24] = \
  17. { 1, 3, 6, 10, 15, 21,
  18. 28, 36, 45, 55, 2, 14,
  19. 27, 41, 56, 8, 25, 43,
  20. 62, 18, 39, 61, 20, 44};
  21. static const uint8_t pi[24] = \
  22. {10, 7, 11, 17, 18, 3,
  23. 5, 16, 8, 21, 24, 4,
  24. 15, 23, 19, 13, 12, 2,
  25. 20, 14, 22, 9, 6, 1};
  26. static const uint64_t RC[24] = \
  27. {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
  28. 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
  29. 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
  30. 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
  31. 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
  32. 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
  33. /*** Helper macros to unroll the permutation. ***/
  34. #define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
  35. #define REPEAT6(e) e e e e e e
  36. #define REPEAT24(e) REPEAT6(e e e e)
  37. #define REPEAT5(e) e e e e e
  38. #define FOR5(v, s, e) \
  39. v = 0; \
  40. REPEAT5(e; v += s;)
  41. /*** Keccak-f[1600] ***/
  42. static inline void keccakf(void* state) {
  43. uint64_t* a = (uint64_t*)state;
  44. uint64_t b[5] = {0};
  45. uint64_t t = 0;
  46. uint8_t x, y, i = 0;
  47. REPEAT24(
  48. // Theta
  49. FOR5(x, 1,
  50. b[x] = 0;
  51. FOR5(y, 5,
  52. b[x] ^= a[x + y]; ))
  53. FOR5(x, 1,
  54. FOR5(y, 5,
  55. a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
  56. // Rho and pi
  57. t = a[1];
  58. x = 0;
  59. REPEAT24(b[0] = a[pi[x]];
  60. a[pi[x]] = rol(t, rho[x]);
  61. t = b[0];
  62. x++; )
  63. // Chi
  64. FOR5(y,
  65. 5,
  66. FOR5(x, 1,
  67. b[x] = a[y + x];)
  68. FOR5(x, 1,
  69. a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
  70. // Iota
  71. a[0] ^= RC[i];
  72. i++; )
  73. }
  74. /******** The FIPS202-defined functions. ********/
  75. /*** Some helper macros. ***/
  76. #define _(S) do { S } while (0)
  77. #define FOR(i, ST, L, S) \
  78. _(for (size_t i = 0; i < L; i += ST) { S; })
  79. #define mkapply_ds(NAME, S) \
  80. static inline void NAME(uint8_t* dst, \
  81. const uint8_t* src, \
  82. size_t len) { \
  83. FOR(i, 1, len, S); \
  84. }
  85. #define mkapply_sd(NAME, S) \
  86. static inline void NAME(const uint8_t* src, \
  87. uint8_t* dst, \
  88. size_t len) { \
  89. FOR(i, 1, len, S); \
  90. }
  91. mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
  92. mkapply_sd(setout, dst[i] = src[i]) // setout
  93. #define P keccakf
  94. #define Plen KECCAK_MAX_RATE
  95. #define KECCAK_DELIM_DIGEST 0x06
  96. #define KECCAK_DELIM_XOF 0x1f
  97. // Fold P*F over the full blocks of an input.
  98. #define foldP(I, L, F) \
  99. while (L >= s->rate) { \
  100. F(s->a, I, s->rate); \
  101. P(s->a); \
  102. I += s->rate; \
  103. L -= s->rate; \
  104. }
  105. static inline void
  106. keccak_absorb_blocks(keccak_state *s, const uint8_t *buf, size_t nr_blocks)
  107. {
  108. size_t blen = nr_blocks * s->rate;
  109. foldP(buf, blen, xorin);
  110. }
  111. static int
  112. keccak_update(keccak_state *s, const uint8_t *buf, size_t len)
  113. {
  114. if (s->finalized)
  115. return -1;
  116. if ((buf == NULL) && len != 0)
  117. return -1;
  118. size_t remaining = len;
  119. while (remaining > 0) {
  120. if (s->offset == 0) {
  121. const size_t blocks = remaining / s->rate;
  122. size_t direct_bytes = blocks * s->rate;
  123. if (direct_bytes > 0) {
  124. keccak_absorb_blocks(s, buf, blocks);
  125. remaining -= direct_bytes;
  126. buf += direct_bytes;
  127. }
  128. }
  129. const size_t buf_avail = s->rate - s->offset;
  130. const size_t buf_bytes = (buf_avail > remaining) ? remaining : buf_avail;
  131. if (buf_bytes > 0) {
  132. memcpy(&s->block[s->offset], buf, buf_bytes);
  133. s->offset += buf_bytes;
  134. remaining -= buf_bytes;
  135. buf += buf_bytes;
  136. }
  137. if (s->offset == s->rate) {
  138. keccak_absorb_blocks(s, s->block, 1);
  139. s->offset = 0;
  140. }
  141. }
  142. return 0;
  143. }
  144. static void
  145. keccak_finalize(keccak_state *s)
  146. {
  147. // Xor in the DS and pad frame.
  148. s->a[s->offset] ^= s->delim;
  149. s->a[s->rate - 1] ^= 0x80;
  150. // Xor in the last block.
  151. xorin(s->a, s->block, s->offset);
  152. memset_s(s->block, sizeof(s->block), 0, sizeof(s->block));
  153. s->finalized = 1;
  154. s->offset = s->rate;
  155. }
  156. static inline void
  157. keccak_squeeze_blocks(keccak_state *s, uint8_t *out, size_t nr_blocks)
  158. {
  159. for (size_t n = 0; n < nr_blocks; n++) {
  160. keccakf(s->a);
  161. setout(s->a, out, s->rate);
  162. out += s->rate;
  163. }
  164. }
  165. static int
  166. keccak_squeeze(keccak_state *s, uint8_t *out, size_t outlen)
  167. {
  168. if (!s->finalized)
  169. return -1;
  170. size_t remaining = outlen;
  171. while (remaining > 0) {
  172. if (s->offset == s->rate) {
  173. const size_t blocks = remaining / s->rate;
  174. const size_t direct_bytes = blocks * s->rate;
  175. if (blocks > 0) {
  176. keccak_squeeze_blocks(s, out, blocks);
  177. out += direct_bytes;
  178. remaining -= direct_bytes;
  179. }
  180. if (remaining > 0) {
  181. keccak_squeeze_blocks(s, s->block, 1);
  182. s->offset = 0;
  183. }
  184. }
  185. const size_t buf_bytes = s->rate - s->offset;
  186. const size_t indirect_bytes = (buf_bytes > remaining) ? remaining : buf_bytes;
  187. if (indirect_bytes > 0) {
  188. memcpy(out, &s->block[s->offset], indirect_bytes);
  189. out += indirect_bytes;
  190. s->offset += indirect_bytes;
  191. remaining -= indirect_bytes;
  192. }
  193. }
  194. return 0;
  195. }
  196. int
  197. keccak_digest_init(keccak_state *s, size_t bits)
  198. {
  199. if (s == NULL)
  200. return -1;
  201. if (bits != 224 && bits != 256 && bits != 384 && bits != 512)
  202. return -1;
  203. keccak_cleanse(s);
  204. s->rate = KECCAK_RATE(bits);
  205. s->delim = KECCAK_DELIM_DIGEST;
  206. return 0;
  207. }
  208. int
  209. keccak_digest_update(keccak_state *s, const uint8_t *buf, size_t len)
  210. {
  211. if (s == NULL)
  212. return -1;
  213. if (s->delim != KECCAK_DELIM_DIGEST)
  214. return -1;
  215. return keccak_update(s, buf, len);
  216. }
  217. int
  218. keccak_digest_sum(const keccak_state *s, uint8_t *out, size_t outlen)
  219. {
  220. if (s == NULL)
  221. return -1;
  222. if (s->delim != KECCAK_DELIM_DIGEST)
  223. return -1;
  224. if (out == NULL || outlen > 4 * (KECCAK_MAX_RATE - s->rate) / 8)
  225. return -1;
  226. // Work in a copy so that incremental/rolling hashes are easy.
  227. keccak_state s_tmp;
  228. keccak_clone(&s_tmp, s);
  229. keccak_finalize(&s_tmp);
  230. int ret = keccak_squeeze(&s_tmp, out, outlen);
  231. keccak_cleanse(&s_tmp);
  232. return ret;
  233. }
  234. int
  235. keccak_xof_init(keccak_state *s, size_t bits)
  236. {
  237. if (s == NULL)
  238. return -1;
  239. if (bits != 128 && bits != 256)
  240. return -1;
  241. keccak_cleanse(s);
  242. s->rate = KECCAK_RATE(bits);
  243. s->delim = KECCAK_DELIM_XOF;
  244. return 0;
  245. }
  246. int
  247. keccak_xof_absorb(keccak_state *s, const uint8_t *buf, size_t len)
  248. {
  249. if (s == NULL)
  250. return -1;
  251. if (s->delim != KECCAK_DELIM_XOF)
  252. return -1;
  253. return keccak_update(s, buf, len);
  254. }
  255. int
  256. keccak_xof_squeeze(keccak_state *s, uint8_t *out, size_t outlen)
  257. {
  258. if (s == NULL)
  259. return -1;
  260. if (s->delim != KECCAK_DELIM_XOF)
  261. return -1;
  262. if (!s->finalized)
  263. keccak_finalize(s);
  264. return keccak_squeeze(s, out, outlen);
  265. }
  266. void
  267. keccak_clone(keccak_state *out, const keccak_state *in)
  268. {
  269. memcpy(out, in, sizeof(keccak_state));
  270. }
  271. void
  272. keccak_cleanse(keccak_state *s)
  273. {
  274. memset_s(s, sizeof(keccak_state), 0, sizeof(keccak_state));
  275. }
  276. /** The sponge-based hash construction. **/
  277. static inline int hash(uint8_t* out, size_t outlen,
  278. const uint8_t* in, size_t inlen,
  279. size_t bits, uint8_t delim) {
  280. if ((out == NULL) || ((in == NULL) && inlen != 0)) {
  281. return -1;
  282. }
  283. int ret = 0;
  284. keccak_state s;
  285. switch (delim) {
  286. case KECCAK_DELIM_DIGEST:
  287. ret |= keccak_digest_init(&s, bits);
  288. ret |= keccak_digest_update(&s, in, inlen);
  289. // Use the internal API instead of sum to avoid the memcpy.
  290. keccak_finalize(&s);
  291. ret |= keccak_squeeze(&s, out, outlen);
  292. break;
  293. case KECCAK_DELIM_XOF:
  294. ret |= keccak_xof_init(&s, bits);
  295. ret |= keccak_xof_absorb(&s, in, inlen);
  296. ret |= keccak_xof_squeeze(&s, out, outlen);
  297. break;
  298. default:
  299. return -1;
  300. }
  301. keccak_cleanse(&s);
  302. return ret;
  303. }
  304. /*** Helper macros to define SHA3 and SHAKE instances. ***/
  305. #define defshake(bits) \
  306. int shake##bits(uint8_t* out, size_t outlen, \
  307. const uint8_t* in, size_t inlen) { \
  308. return hash(out, outlen, in, inlen, bits, KECCAK_DELIM_XOF); \
  309. }
  310. #define defsha3(bits) \
  311. int sha3_##bits(uint8_t* out, size_t outlen, \
  312. const uint8_t* in, size_t inlen) { \
  313. if (outlen > (bits/8)) { \
  314. return -1; \
  315. } \
  316. return hash(out, outlen, in, inlen, bits, KECCAK_DELIM_DIGEST); \
  317. }
  318. /*** FIPS202 SHAKE VOFs ***/
  319. defshake(128)
  320. defshake(256)
  321. /*** FIPS202 SHA3 FOFs ***/
  322. defsha3(224)
  323. defsha3(256)
  324. defsha3(384)
  325. defsha3(512)