/* spritz.c, spritz C implementation * * Copyright (c) 2015 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License ("GPL") version 2 or any later version, * in which case the provisions of the GPL are applicable instead of * the above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the BSD license, indicate your decision * by deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file under * either the BSD or the GPL. */ #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); }