/* $Id: hamsi.c 251 2010-10-19 14:31:51Z tp $ */ /* * Hamsi implementation. * * ==========================(LICENSE BEGIN)============================ * * Copyright (c) 2007-2010 Projet RNRT SAPHIR * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * ===========================(LICENSE END)============================= * * @author Thomas Pornin */ #include #include #include "sph_hamsi.h" #ifdef __cplusplus extern "C"{ #endif #if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_HAMSI #define SPH_SMALL_FOOTPRINT_HAMSI 1 #endif /* * The SPH_HAMSI_EXPAND_* define how many input bits we handle in one * table lookup during message expansion (1 to 8, inclusive). If we note * w the number of bits per message word (w=32 for Hamsi-224/256, w=64 * for Hamsi-384/512), r the size of a "row" in 32-bit words (r=8 for * Hamsi-224/256, r=16 for Hamsi-384/512), and n the expansion level, * then we will get t tables (where t=ceil(w/n)) of individual size * 2^n*r*4 (in bytes). The last table may be shorter (e.g. with w=32 and * n=5, there are 7 tables, but the last one uses only two bits on * input, not five). * * Also, we read t rows of r words from RAM. Words in a given row are * concatenated in RAM in that order, so most of the cost is about * reading the first row word; comparatively, cache misses are thus * less expensive with Hamsi-512 (r=16) than with Hamsi-256 (r=8). * * When n=1, tables are "special" in that we omit the first entry of * each table (which always contains 0), so that total table size is * halved. * * We thus have the following (size1 is the cumulative table size of * Hamsi-224/256; size2 is for Hamsi-384/512; similarly, t1 and t2 * are for Hamsi-224/256 and Hamsi-384/512, respectively). * * n size1 size2 t1 t2 * --------------------------------------- * 1 1024 4096 32 64 * 2 2048 8192 16 32 * 3 2688 10880 11 22 * 4 4096 16384 8 16 * 5 6272 25600 7 13 * 6 10368 41984 6 11 * 7 16896 73856 5 10 * 8 32768 131072 4 8 * * So there is a trade-off: a lower n makes the tables fit better in * L1 cache, but increases the number of memory accesses. The optimal * value depends on the amount of available L1 cache and the relative * impact of a cache miss. * * Experimentally, in ideal benchmark conditions (which are not necessarily * realistic with regards to L1 cache contention), it seems that n=8 is * the best value on "big" architectures (those with 32 kB or more of L1 * cache), while n=4 is better on "small" architectures. This was tested * on an Intel Core2 Q6600 (both 32-bit and 64-bit mode), a PowerPC G3 * (32 kB L1 cache, hence "big"), and a MIPS-compatible Broadcom BCM3302 * (8 kB L1 cache). * * Note: with n=1, the 32 tables (actually implemented as one big table) * are read entirely and sequentially, regardless of the input data, * thus avoiding any data-dependent table access pattern. */ #if !defined SPH_HAMSI_EXPAND_SMALL #if SPH_SMALL_FOOTPRINT_HAMSI #define SPH_HAMSI_EXPAND_SMALL 4 #else #define SPH_HAMSI_EXPAND_SMALL 8 #endif #endif #if !defined SPH_HAMSI_EXPAND_BIG #define SPH_HAMSI_EXPAND_BIG 8 #endif #ifdef _MSC_VER #pragma warning (disable: 4146) #endif #include "hamsi_helper.c" static const sph_u32 IV224[] = { SPH_C32(0xc3967a67), SPH_C32(0xc3bc6c20), SPH_C32(0x4bc3bcc3), SPH_C32(0xa7c3bc6b), SPH_C32(0x2c204b61), SPH_C32(0x74686f6c), SPH_C32(0x69656b65), SPH_C32(0x20556e69) }; /* * This version is the one used in the Hamsi submission package for * round 2 of the SHA-3 competition; the UTF-8 encoding is wrong and * shall soon be corrected in the official Hamsi specification. * static const sph_u32 IV224[] = { SPH_C32(0x3c967a67), SPH_C32(0x3cbc6c20), SPH_C32(0xb4c343c3), SPH_C32(0xa73cbc6b), SPH_C32(0x2c204b61), SPH_C32(0x74686f6c), SPH_C32(0x69656b65), SPH_C32(0x20556e69) }; */ static const sph_u32 IV256[] = { SPH_C32(0x76657273), SPH_C32(0x69746569), SPH_C32(0x74204c65), SPH_C32(0x7576656e), SPH_C32(0x2c204465), SPH_C32(0x70617274), SPH_C32(0x656d656e), SPH_C32(0x7420456c) }; static const sph_u32 IV384[] = { SPH_C32(0x656b7472), SPH_C32(0x6f746563), SPH_C32(0x686e6965), SPH_C32(0x6b2c2043), SPH_C32(0x6f6d7075), SPH_C32(0x74657220), SPH_C32(0x53656375), SPH_C32(0x72697479), SPH_C32(0x20616e64), SPH_C32(0x20496e64), SPH_C32(0x75737472), SPH_C32(0x69616c20), SPH_C32(0x43727970), SPH_C32(0x746f6772), SPH_C32(0x61706879), SPH_C32(0x2c204b61) }; static const sph_u32 IV512[] = { SPH_C32(0x73746565), SPH_C32(0x6c706172), SPH_C32(0x6b204172), SPH_C32(0x656e6265), SPH_C32(0x72672031), SPH_C32(0x302c2062), SPH_C32(0x75732032), SPH_C32(0x3434362c), SPH_C32(0x20422d33), SPH_C32(0x30303120), SPH_C32(0x4c657576), SPH_C32(0x656e2d48), SPH_C32(0x65766572), SPH_C32(0x6c65652c), SPH_C32(0x2042656c), SPH_C32(0x6769756d) }; static const sph_u32 alpha_n[] = { SPH_C32(0xff00f0f0), SPH_C32(0xccccaaaa), SPH_C32(0xf0f0cccc), SPH_C32(0xff00aaaa), SPH_C32(0xccccaaaa), SPH_C32(0xf0f0ff00), SPH_C32(0xaaaacccc), SPH_C32(0xf0f0ff00), SPH_C32(0xf0f0cccc), SPH_C32(0xaaaaff00), SPH_C32(0xccccff00), SPH_C32(0xaaaaf0f0), SPH_C32(0xaaaaf0f0), SPH_C32(0xff00cccc), SPH_C32(0xccccf0f0), SPH_C32(0xff00aaaa), SPH_C32(0xccccaaaa), SPH_C32(0xff00f0f0), SPH_C32(0xff00aaaa), SPH_C32(0xf0f0cccc), SPH_C32(0xf0f0ff00), SPH_C32(0xccccaaaa), SPH_C32(0xf0f0ff00), SPH_C32(0xaaaacccc), SPH_C32(0xaaaaff00), SPH_C32(0xf0f0cccc), SPH_C32(0xaaaaf0f0), SPH_C32(0xccccff00), SPH_C32(0xff00cccc), SPH_C32(0xaaaaf0f0), SPH_C32(0xff00aaaa), SPH_C32(0xccccf0f0) }; static const sph_u32 alpha_f[] = { SPH_C32(0xcaf9639c), SPH_C32(0x0ff0f9c0), SPH_C32(0x639c0ff0), SPH_C32(0xcaf9f9c0), SPH_C32(0x0ff0f9c0), SPH_C32(0x639ccaf9), SPH_C32(0xf9c00ff0), SPH_C32(0x639ccaf9), SPH_C32(0x639c0ff0), SPH_C32(0xf9c0caf9), SPH_C32(0x0ff0caf9), SPH_C32(0xf9c0639c), SPH_C32(0xf9c0639c), SPH_C32(0xcaf90ff0), SPH_C32(0x0ff0639c), SPH_C32(0xcaf9f9c0), SPH_C32(0x0ff0f9c0), SPH_C32(0xcaf9639c), SPH_C32(0xcaf9f9c0), SPH_C32(0x639c0ff0), SPH_C32(0x639ccaf9), SPH_C32(0x0ff0f9c0), SPH_C32(0x639ccaf9), SPH_C32(0xf9c00ff0), SPH_C32(0xf9c0caf9), SPH_C32(0x639c0ff0), SPH_C32(0xf9c0639c), SPH_C32(0x0ff0caf9), SPH_C32(0xcaf90ff0), SPH_C32(0xf9c0639c), SPH_C32(0xcaf9f9c0), SPH_C32(0x0ff0639c) }; #define DECL_STATE_SMALL \ sph_u32 c0, c1, c2, c3, c4, c5, c6, c7; #define READ_STATE_SMALL(sc) do { \ c0 = sc->h[0x0]; \ c1 = sc->h[0x1]; \ c2 = sc->h[0x2]; \ c3 = sc->h[0x3]; \ c4 = sc->h[0x4]; \ c5 = sc->h[0x5]; \ c6 = sc->h[0x6]; \ c7 = sc->h[0x7]; \ } while (0) #define WRITE_STATE_SMALL(sc) do { \ sc->h[0x0] = c0; \ sc->h[0x1] = c1; \ sc->h[0x2] = c2; \ sc->h[0x3] = c3; \ sc->h[0x4] = c4; \ sc->h[0x5] = c5; \ sc->h[0x6] = c6; \ sc->h[0x7] = c7; \ } while (0) #define s0 m0 #define s1 m1 #define s2 c0 #define s3 c1 #define s4 c2 #define s5 c3 #define s6 m2 #define s7 m3 #define s8 m4 #define s9 m5 #define sA c4 #define sB c5 #define sC c6 #define sD c7 #define sE m6 #define sF m7 #define SBOX(a, b, c, d) do { \ sph_u32 t; \ t = (a); \ (a) &= (c); \ (a) ^= (d); \ (c) ^= (b); \ (c) ^= (a); \ (d) |= t; \ (d) ^= (b); \ t ^= (c); \ (b) = (d); \ (d) |= t; \ (d) ^= (a); \ (a) &= (b); \ t ^= (a); \ (b) ^= (d); \ (b) ^= t; \ (a) = (c); \ (c) = (b); \ (b) = (d); \ (d) = SPH_T32(~t); \ } while (0) #define L(a, b, c, d) do { \ (a) = SPH_ROTL32(a, 13); \ (c) = SPH_ROTL32(c, 3); \ (b) ^= (a) ^ (c); \ (d) ^= (c) ^ SPH_T32((a) << 3); \ (b) = SPH_ROTL32(b, 1); \ (d) = SPH_ROTL32(d, 7); \ (a) ^= (b) ^ (d); \ (c) ^= (d) ^ SPH_T32((b) << 7); \ (a) = SPH_ROTL32(a, 5); \ (c) = SPH_ROTL32(c, 22); \ } while (0) #define ROUND_SMALL(rc, alpha) do { \ s0 ^= alpha[0x00]; \ s1 ^= alpha[0x01] ^ (sph_u32)(rc); \ s2 ^= alpha[0x02]; \ s3 ^= alpha[0x03]; \ s4 ^= alpha[0x08]; \ s5 ^= alpha[0x09]; \ s6 ^= alpha[0x0A]; \ s7 ^= alpha[0x0B]; \ s8 ^= alpha[0x10]; \ s9 ^= alpha[0x11]; \ sA ^= alpha[0x12]; \ sB ^= alpha[0x13]; \ sC ^= alpha[0x18]; \ sD ^= alpha[0x19]; \ sE ^= alpha[0x1A]; \ sF ^= alpha[0x1B]; \ SBOX(s0, s4, s8, sC); \ SBOX(s1, s5, s9, sD); \ SBOX(s2, s6, sA, sE); \ SBOX(s3, s7, sB, sF); \ L(s0, s5, sA, sF); \ L(s1, s6, sB, sC); \ L(s2, s7, s8, sD); \ L(s3, s4, s9, sE); \ } while (0) #define P_SMALL do { \ ROUND_SMALL(0, alpha_n); \ ROUND_SMALL(1, alpha_n); \ ROUND_SMALL(2, alpha_n); \ } while (0) #define PF_SMALL do { \ ROUND_SMALL(0, alpha_f); \ ROUND_SMALL(1, alpha_f); \ ROUND_SMALL(2, alpha_f); \ ROUND_SMALL(3, alpha_f); \ ROUND_SMALL(4, alpha_f); \ ROUND_SMALL(5, alpha_f); \ } while (0) #define T_SMALL do { \ /* order is important */ \ c7 = (sc->h[7] ^= sB); \ c6 = (sc->h[6] ^= sA); \ c5 = (sc->h[5] ^= s9); \ c4 = (sc->h[4] ^= s8); \ c3 = (sc->h[3] ^= s3); \ c2 = (sc->h[2] ^= s2); \ c1 = (sc->h[1] ^= s1); \ c0 = (sc->h[0] ^= s0); \ } while (0) static void hamsi_small(sph_hamsi_small_context *sc, const unsigned char *buf, size_t num) { DECL_STATE_SMALL #if !SPH_64 sph_u32 tmp; #endif #if SPH_64 sc->count += (sph_u64)num << 5; #else tmp = SPH_T32((sph_u32)num << 5); sc->count_low = SPH_T32(sc->count_low + tmp); sc->count_high += (sph_u32)((num >> 13) >> 14); if (sc->count_low < tmp) sc->count_high ++; #endif READ_STATE_SMALL(sc); while (num -- > 0) { sph_u32 m0, m1, m2, m3, m4, m5, m6, m7; INPUT_SMALL; P_SMALL; T_SMALL; buf += 4; } WRITE_STATE_SMALL(sc); } static void hamsi_small_final(sph_hamsi_small_context *sc, const unsigned char *buf) { sph_u32 m0, m1, m2, m3, m4, m5, m6, m7; DECL_STATE_SMALL READ_STATE_SMALL(sc); INPUT_SMALL; PF_SMALL; T_SMALL; WRITE_STATE_SMALL(sc); } static void hamsi_small_init(sph_hamsi_small_context *sc, const sph_u32 *iv) { sc->partial_len = 0; memcpy(sc->h, iv, sizeof sc->h); #if SPH_64 sc->count = 0; #else sc->count_high = sc->count_low = 0; #endif } static void hamsi_small_core(sph_hamsi_small_context *sc, const void *data, size_t len) { if (sc->partial_len != 0) { size_t mlen; mlen = 4 - sc->partial_len; if (len < mlen) { memcpy(sc->partial + sc->partial_len, data, len); sc->partial_len += len; return; } else { memcpy(sc->partial + sc->partial_len, data, mlen); len -= mlen; data = (const unsigned char *)data + mlen; hamsi_small(sc, sc->partial, 1); sc->partial_len = 0; } } hamsi_small(sc, data, (len >> 2)); data = (const unsigned char *)data + (len & ~(size_t)3); len &= (size_t)3; memcpy(sc->partial, data, len); sc->partial_len = len; } static void hamsi_small_close(sph_hamsi_small_context *sc, unsigned ub, unsigned n, void *dst, size_t out_size_w32) { unsigned char pad[12]; size_t ptr, u; unsigned z; unsigned char *out; ptr = sc->partial_len; memcpy(pad, sc->partial, ptr); #if SPH_64 sph_enc64be(pad + 4, sc->count + (ptr << 3) + n); #else sph_enc32be(pad + 4, sc->count_high); sph_enc32be(pad + 8, sc->count_low + (ptr << 3) + n); #endif z = 0x80 >> n; pad[ptr ++] = ((ub & -z) | z) & 0xFF; while (ptr < 4) pad[ptr ++] = 0; hamsi_small(sc, pad, 2); hamsi_small_final(sc, pad + 8); out = dst; for (u = 0; u < out_size_w32; u ++) sph_enc32be(out + (u << 2), sc->h[u]); } #define DECL_STATE_BIG \ sph_u32 c0, c1, c2, c3, c4, c5, c6, c7; \ sph_u32 c8, c9, cA, cB, cC, cD, cE, cF; #define READ_STATE_BIG(sc) do { \ c0 = sc->h[0x0]; \ c1 = sc->h[0x1]; \ c2 = sc->h[0x2]; \ c3 = sc->h[0x3]; \ c4 = sc->h[0x4]; \ c5 = sc->h[0x5]; \ c6 = sc->h[0x6]; \ c7 = sc->h[0x7]; \ c8 = sc->h[0x8]; \ c9 = sc->h[0x9]; \ cA = sc->h[0xA]; \ cB = sc->h[0xB]; \ cC = sc->h[0xC]; \ cD = sc->h[0xD]; \ cE = sc->h[0xE]; \ cF = sc->h[0xF]; \ } while (0) #define WRITE_STATE_BIG(sc) do { \ sc->h[0x0] = c0; \ sc->h[0x1] = c1; \ sc->h[0x2] = c2; \ sc->h[0x3] = c3; \ sc->h[0x4] = c4; \ sc->h[0x5] = c5; \ sc->h[0x6] = c6; \ sc->h[0x7] = c7; \ sc->h[0x8] = c8; \ sc->h[0x9] = c9; \ sc->h[0xA] = cA; \ sc->h[0xB] = cB; \ sc->h[0xC] = cC; \ sc->h[0xD] = cD; \ sc->h[0xE] = cE; \ sc->h[0xF] = cF; \ } while (0) #define s00 m0 #define s01 m1 #define s02 c0 #define s03 c1 #define s04 m2 #define s05 m3 #define s06 c2 #define s07 c3 #define s08 c4 #define s09 c5 #define s0A m4 #define s0B m5 #define s0C c6 #define s0D c7 #define s0E m6 #define s0F m7 #define s10 m8 #define s11 m9 #define s12 c8 #define s13 c9 #define s14 mA #define s15 mB #define s16 cA #define s17 cB #define s18 cC #define s19 cD #define s1A mC #define s1B mD #define s1C cE #define s1D cF #define s1E mE #define s1F mF #define ROUND_BIG(rc, alpha) do { \ s00 ^= alpha[0x00]; \ s01 ^= alpha[0x01] ^ (sph_u32)(rc); \ s02 ^= alpha[0x02]; \ s03 ^= alpha[0x03]; \ s04 ^= alpha[0x04]; \ s05 ^= alpha[0x05]; \ s06 ^= alpha[0x06]; \ s07 ^= alpha[0x07]; \ s08 ^= alpha[0x08]; \ s09 ^= alpha[0x09]; \ s0A ^= alpha[0x0A]; \ s0B ^= alpha[0x0B]; \ s0C ^= alpha[0x0C]; \ s0D ^= alpha[0x0D]; \ s0E ^= alpha[0x0E]; \ s0F ^= alpha[0x0F]; \ s10 ^= alpha[0x10]; \ s11 ^= alpha[0x11]; \ s12 ^= alpha[0x12]; \ s13 ^= alpha[0x13]; \ s14 ^= alpha[0x14]; \ s15 ^= alpha[0x15]; \ s16 ^= alpha[0x16]; \ s17 ^= alpha[0x17]; \ s18 ^= alpha[0x18]; \ s19 ^= alpha[0x19]; \ s1A ^= alpha[0x1A]; \ s1B ^= alpha[0x1B]; \ s1C ^= alpha[0x1C]; \ s1D ^= alpha[0x1D]; \ s1E ^= alpha[0x1E]; \ s1F ^= alpha[0x1F]; \ SBOX(s00, s08, s10, s18); \ SBOX(s01, s09, s11, s19); \ SBOX(s02, s0A, s12, s1A); \ SBOX(s03, s0B, s13, s1B); \ SBOX(s04, s0C, s14, s1C); \ SBOX(s05, s0D, s15, s1D); \ SBOX(s06, s0E, s16, s1E); \ SBOX(s07, s0F, s17, s1F); \ L(s00, s09, s12, s1B); \ L(s01, s0A, s13, s1C); \ L(s02, s0B, s14, s1D); \ L(s03, s0C, s15, s1E); \ L(s04, s0D, s16, s1F); \ L(s05, s0E, s17, s18); \ L(s06, s0F, s10, s19); \ L(s07, s08, s11, s1A); \ L(s00, s02, s05, s07); \ L(s10, s13, s15, s16); \ L(s09, s0B, s0C, s0E); \ L(s19, s1A, s1C, s1F); \ } while (0) #if SPH_SMALL_FOOTPRINT_HAMSI #define P_BIG do { \ unsigned r; \ for (r = 0; r < 6; r ++) \ ROUND_BIG(r, alpha_n); \ } while (0) #define PF_BIG do { \ unsigned r; \ for (r = 0; r < 12; r ++) \ ROUND_BIG(r, alpha_f); \ } while (0) #else #define P_BIG do { \ ROUND_BIG(0, alpha_n); \ ROUND_BIG(1, alpha_n); \ ROUND_BIG(2, alpha_n); \ ROUND_BIG(3, alpha_n); \ ROUND_BIG(4, alpha_n); \ ROUND_BIG(5, alpha_n); \ } while (0) #define PF_BIG do { \ ROUND_BIG(0, alpha_f); \ ROUND_BIG(1, alpha_f); \ ROUND_BIG(2, alpha_f); \ ROUND_BIG(3, alpha_f); \ ROUND_BIG(4, alpha_f); \ ROUND_BIG(5, alpha_f); \ ROUND_BIG(6, alpha_f); \ ROUND_BIG(7, alpha_f); \ ROUND_BIG(8, alpha_f); \ ROUND_BIG(9, alpha_f); \ ROUND_BIG(10, alpha_f); \ ROUND_BIG(11, alpha_f); \ } while (0) #endif #define T_BIG do { \ /* order is important */ \ cF = (sc->h[0xF] ^= s17); \ cE = (sc->h[0xE] ^= s16); \ cD = (sc->h[0xD] ^= s15); \ cC = (sc->h[0xC] ^= s14); \ cB = (sc->h[0xB] ^= s13); \ cA = (sc->h[0xA] ^= s12); \ c9 = (sc->h[0x9] ^= s11); \ c8 = (sc->h[0x8] ^= s10); \ c7 = (sc->h[0x7] ^= s07); \ c6 = (sc->h[0x6] ^= s06); \ c5 = (sc->h[0x5] ^= s05); \ c4 = (sc->h[0x4] ^= s04); \ c3 = (sc->h[0x3] ^= s03); \ c2 = (sc->h[0x2] ^= s02); \ c1 = (sc->h[0x1] ^= s01); \ c0 = (sc->h[0x0] ^= s00); \ } while (0) static void hamsi_big(sph_hamsi_big_context *sc, const unsigned char *buf, size_t num) { DECL_STATE_BIG #if !SPH_64 sph_u32 tmp; #endif #if SPH_64 sc->count += (sph_u64)num << 6; #else tmp = SPH_T32((sph_u32)num << 6); sc->count_low = SPH_T32(sc->count_low + tmp); sc->count_high += (sph_u32)((num >> 13) >> 13); if (sc->count_low < tmp) sc->count_high ++; #endif READ_STATE_BIG(sc); while (num -- > 0) { sph_u32 m0, m1, m2, m3, m4, m5, m6, m7; sph_u32 m8, m9, mA, mB, mC, mD, mE, mF; INPUT_BIG; P_BIG; T_BIG; buf += 8; } WRITE_STATE_BIG(sc); } static void hamsi_big_final(sph_hamsi_big_context *sc, const unsigned char *buf) { sph_u32 m0, m1, m2, m3, m4, m5, m6, m7; sph_u32 m8, m9, mA, mB, mC, mD, mE, mF; DECL_STATE_BIG READ_STATE_BIG(sc); INPUT_BIG; PF_BIG; T_BIG; WRITE_STATE_BIG(sc); } static void hamsi_big_init(sph_hamsi_big_context *sc, const sph_u32 *iv) { sc->partial_len = 0; memcpy(sc->h, iv, sizeof sc->h); #if SPH_64 sc->count = 0; #else sc->count_high = sc->count_low = 0; #endif } static void hamsi_big_core(sph_hamsi_big_context *sc, const void *data, size_t len) { if (sc->partial_len != 0) { size_t mlen; mlen = 8 - sc->partial_len; if (len < mlen) { memcpy(sc->partial + sc->partial_len, data, len); sc->partial_len += len; return; } else { memcpy(sc->partial + sc->partial_len, data, mlen); len -= mlen; data = (const unsigned char *)data + mlen; hamsi_big(sc, sc->partial, 1); sc->partial_len = 0; } } hamsi_big(sc, data, (len >> 3)); data = (const unsigned char *)data + (len & ~(size_t)7); len &= (size_t)7; memcpy(sc->partial, data, len); sc->partial_len = len; } static void hamsi_big_close(sph_hamsi_big_context *sc, unsigned ub, unsigned n, void *dst, size_t out_size_w32) { unsigned char pad[8]; size_t ptr, u; unsigned z; unsigned char *out; ptr = sc->partial_len; #if SPH_64 sph_enc64be(pad, sc->count + (ptr << 3) + n); #else sph_enc32be(pad, sc->count_high); sph_enc32be(pad + 4, sc->count_low + (ptr << 3) + n); #endif z = 0x80 >> n; sc->partial[ptr ++] = ((ub & -z) | z) & 0xFF; while (ptr < 8) sc->partial[ptr ++] = 0; hamsi_big(sc, sc->partial, 1); hamsi_big_final(sc, pad); out = dst; if (out_size_w32 == 12) { sph_enc32be(out + 0, sc->h[ 0]); sph_enc32be(out + 4, sc->h[ 1]); sph_enc32be(out + 8, sc->h[ 3]); sph_enc32be(out + 12, sc->h[ 4]); sph_enc32be(out + 16, sc->h[ 5]); sph_enc32be(out + 20, sc->h[ 6]); sph_enc32be(out + 24, sc->h[ 8]); sph_enc32be(out + 28, sc->h[ 9]); sph_enc32be(out + 32, sc->h[10]); sph_enc32be(out + 36, sc->h[12]); sph_enc32be(out + 40, sc->h[13]); sph_enc32be(out + 44, sc->h[15]); } else { for (u = 0; u < 16; u ++) sph_enc32be(out + (u << 2), sc->h[u]); } } /* see sph_hamsi.h */ void sph_hamsi224_init(void *cc) { hamsi_small_init(cc, IV224); } /* see sph_hamsi.h */ void sph_hamsi224(void *cc, const void *data, size_t len) { hamsi_small_core(cc, data, len); } /* see sph_hamsi.h */ void sph_hamsi224_close(void *cc, void *dst) { hamsi_small_close(cc, 0, 0, dst, 7); hamsi_small_init(cc, IV224); } /* see sph_hamsi.h */ void sph_hamsi224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) { hamsi_small_close(cc, ub, n, dst, 7); hamsi_small_init(cc, IV224); } /* see sph_hamsi.h */ void sph_hamsi256_init(void *cc) { hamsi_small_init(cc, IV256); } /* see sph_hamsi.h */ void sph_hamsi256(void *cc, const void *data, size_t len) { hamsi_small_core(cc, data, len); } /* see sph_hamsi.h */ void sph_hamsi256_close(void *cc, void *dst) { hamsi_small_close(cc, 0, 0, dst, 8); hamsi_small_init(cc, IV256); } /* see sph_hamsi.h */ void sph_hamsi256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) { hamsi_small_close(cc, ub, n, dst, 8); hamsi_small_init(cc, IV256); } /* see sph_hamsi.h */ void sph_hamsi384_init(void *cc) { hamsi_big_init(cc, IV384); } /* see sph_hamsi.h */ void sph_hamsi384(void *cc, const void *data, size_t len) { hamsi_big_core(cc, data, len); } /* see sph_hamsi.h */ void sph_hamsi384_close(void *cc, void *dst) { hamsi_big_close(cc, 0, 0, dst, 12); hamsi_big_init(cc, IV384); } /* see sph_hamsi.h */ void sph_hamsi384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) { hamsi_big_close(cc, ub, n, dst, 12); hamsi_big_init(cc, IV384); } /* see sph_hamsi.h */ void sph_hamsi512_init(void *cc) { hamsi_big_init(cc, IV512); } /* see sph_hamsi.h */ void sph_hamsi512(void *cc, const void *data, size_t len) { hamsi_big_core(cc, data, len); } /* see sph_hamsi.h */ void sph_hamsi512_close(void *cc, void *dst) { hamsi_big_close(cc, 0, 0, dst, 16); hamsi_big_init(cc, IV512); } /* see sph_hamsi.h */ void sph_hamsi512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) { hamsi_big_close(cc, ub, n, dst, 16); hamsi_big_init(cc, IV512); } #ifdef __cplusplus } #endif