/* spritz.c */ /* (C)2015 Marc Alexander Lehmann, all rights reserved */ #include "spritz.h" #include void spritz_init (spritz_state *s) { s->a = s->i = s->j = s->k = s->z = 0; s->w = 1; uint_fast8_t v = spritz_N - 1; do s->S[v] = v; while (v--); } void spritz_update (spritz_state *s) { s->i += s->w; s->j = s->k + s->S[s->j + s->S[s->i]]; s->k = s->k + s->i + s->S[s->j]; SPRITZ_SWAP (s->S[s->i], s->S[s->j]); } void spritz_whip (spritz_state *s, uint_fast16_t r) { while (r--) spritz_update (s); s->w += 2; } #define SPRITZ_SWAP(a,b) { uint8_t ss_c = (a); (a) = (b); (b) = ss_c; } void spritz_crush (spritz_state *s) { uint_fast16_t v; for (v = 0; v < (spritz_N >> 1); ++v) if (s->S[v] > s->S[spritz_N - 1 - v]) SPRITZ_SWAP (s->S[v], s->S[spritz_N - 1 - v]); } void spritz_shuffle (spritz_state *s) { spritz_whip (s, 2 * spritz_N); spritz_crush (s); spritz_whip (s, 2 * spritz_N); spritz_crush (s); spritz_whip (s, 2 * spritz_N); s->a = 0; } static void spritz_shuffle_absorb (spritz_state *s) { if (s->a == (spritz_N >> 1)) spritz_shuffle (s); } void spritz_absorb_nibble (spritz_state *s, uint8_t x) { spritz_shuffle_absorb (s); SPRITZ_SWAP (s->S[s->a], s->S[(spritz_N >> 1) + x]); ++s->a; } static void spritz_absorb_byte (spritz_state *s, uint8_t b) { spritz_absorb_nibble (s, b & 15); spritz_absorb_nibble (s, b >> 4); } void spritz_absorb (spritz_state *s, const void *I, size_t I_len) { uint8_t *i = (uint8_t *)I; while (I_len--) spritz_absorb_byte (s, *i++); } void spritz_absorb_stop (spritz_state *s) { spritz_shuffle_absorb (s); ++s->a; } // commonly used helper function void spritz_absorb_and_stop (spritz_state *s, const void *I, size_t I_len) { spritz_absorb (s, I, I_len); spritz_absorb_stop (s); } static void spritz_shuffle_squeeze (spritz_state *s) { if (s->a) spritz_shuffle (s); } uint8_t spritz_output (spritz_state *s) { return s->S[s->j + s->S[s->i + s->S[s->z + s->k]]]; } // slightly faster internal helper, drip without squeeze preparation static uint8_t spritz_drip_nosqueeze (spritz_state *s) { spritz_update (s); return spritz_output (s); } void spritz_squeeze (spritz_state *s, void *P, size_t P_len) { spritz_shuffle_squeeze (s); uint8_t *p = (uint8_t *)P; while (P_len--) *p++ = spritz_drip_nosqueeze (s); } uint8_t spritz_drip (spritz_state *s) { spritz_shuffle_squeeze (s); return spritz_drip_nosqueeze (s); } void spritz_xor_init (spritz_state *s, const void *K, size_t K_len, const void *IV, size_t IV_len) { spritz_init (s); spritz_absorb (s, K, K_len); if (IV) { spritz_absorb_stop (s); spritz_absorb (s, IV, IV_len); } spritz_shuffle_squeeze (s); } void spritz_xor_crypt (spritz_state *s, const void *I, void *O, size_t len) { const uint8_t *i = (const uint8_t *)I; uint8_t *o = ( uint8_t *)O; while (len--) *o++ = *i++ ^ spritz_drip_nosqueeze (s); } void spritz_hash_finish (spritz_state *s, void *H, size_t H_len) { spritz_absorb_stop (s); assert (H_len <= 0xff); spritz_absorb_byte (s, H_len); spritz_squeeze (s, H, H_len); } void spritz_mac_init (spritz_state *s, const void *K, size_t K_len) { spritz_init (s); spritz_absorb_and_stop (s, K, K_len); } void spritz_aead_init (spritz_state *s, const void *K, size_t K_len) { spritz_mac_init (s, K, K_len); } void spritz_aead_crypt (spritz_state *s, const void *I, void *O, size_t len) { const uint8_t *i = (const uint8_t *)I; uint8_t *o = ( uint8_t *)O; uint8_t x[spritz_N >> 2]; while (len) { uint_fast8_t j; uint8_t l = len > sizeof (x) ? sizeof (x) : len; len -= l; spritz_squeeze (s, x, l); for (j = 0; j < l; ++j) spritz_absorb_byte (s, *o++ = *i++ ^ x[j]); } } void spritz_prng_init (spritz_state *s, const void *S, size_t S_len) { spritz_init (s); spritz_absorb (s, S, S_len); }