diff options
Diffstat (limited to 'src/impl.c')
-rw-r--r-- | src/impl.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/impl.c b/src/impl.c new file mode 100644 index 0000000..5ba4bde --- /dev/null +++ b/src/impl.c @@ -0,0 +1,180 @@ +#include <s.h> + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> + +#include "impl.h" + + + +static const int cROUNDS = 2; +static const int dROUNDS = 4; + + + +static inline uint64_t +ROTL(uint64_t x, uint64_t b) { + return (x << b) | (x >> (64 - b)); +} + +static inline void +U32TO8_LE(u8 *p, uint32_t v) { + p[0] = (u8)(v >> 0); + p[1] = (u8)(v >> 8); + p[2] = (u8)(v >> 16); + p[3] = (u8)(v >> 24); +} + +static inline void +U64TO8_LE(u8 *p, uint64_t v) { + U32TO8_LE(p + 0, (uint32_t)(v >> 0)); + U32TO8_LE(p + 4, (uint32_t)(v >> 32)); +} + +static inline uint64_t +U8TO64_LE(const u8 *p) { + return + (((uint64_t)p[0]) << 0) | + (((uint64_t)p[1]) << 8) | + (((uint64_t)p[2]) << 16) | + (((uint64_t)p[3]) << 24) | + (((uint64_t)p[4]) << 32) | + (((uint64_t)p[5]) << 40) | + (((uint64_t)p[6]) << 48) | + (((uint64_t)p[7]) << 56); +} + +static inline void +SIPROUND(uint64_t *v0, uint64_t *v1, uint64_t *v2, uint64_t *v3) { + *v0 += *v1; + *v1 = ROTL(*v1, 13); + *v1 ^= *v0; + *v0 = ROTL(*v0, 32); + *v2 += *v3; + *v3 = ROTL(*v3, 16); + *v3 ^= *v2; + *v0 += *v3; + *v3 = ROTL(*v3, 21); + *v3 ^= *v0; + *v2 += *v1; + *v1 = ROTL(*v1, 17); + *v1 ^= *v2; + *v2 = ROTL(*v2, 32); +} + +/** + Computes a SipHash value: + + - *in: pointer to input data (read-only) + - inlen: input data length in bytes (any size_t value) + - *key: pointer to the key data (read-only), must be 16 bytes + - *out: pointer to output data (write-only), outlen bytes must be allocated + - outlen: length of the output in bytes, must be 8 or 16 +*/ +int +siphash_impl( + const void *const restrict in, + const size_t inlen, + const void *const restrict key, + u8 out[16U], + const size_t outlen +) { + const unsigned char *ni = (const unsigned char *)in; + const unsigned char *kk = (const unsigned char *)key; + + #line 95 + assert((outlen == 8) || (outlen == 16)); + #line 89 + uint64_t v0 = UINT64_C(0x736f6d6570736575); + uint64_t v1 = UINT64_C(0x646f72616e646f6d); + uint64_t v2 = UINT64_C(0x6c7967656e657261); + uint64_t v3 = UINT64_C(0x7465646279746573); + const uint64_t k0 = U8TO64_LE(kk); + const uint64_t k1 = U8TO64_LE(kk + 8); + const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t)); + const int left = inlen & 7; + uint64_t b = ((uint64_t)inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + if (outlen == 16) { + v1 ^= 0xee; + } + + while (ni != end) { + uint64_t m = U8TO64_LE(ni); + v3 ^= m; + + for (int i = 0; i < cROUNDS; i++) { + SIPROUND(&v0, &v1, &v2, &v3); + } + + v0 ^= m; + ni += 8; + } + + switch (left) { + case 7: + b |= ((uint64_t)ni[6]) << 48; + // fallthrough + case 6: + b |= ((uint64_t)ni[5]) << 40; + // fallthrough + case 5: + b |= ((uint64_t)ni[4]) << 32; + // fallthrough + case 4: + b |= ((uint64_t)ni[3]) << 24; + // fallthrough + case 3: + b |= ((uint64_t)ni[2]) << 16; + // fallthrough + case 2: + b |= ((uint64_t)ni[1]) << 8; + // fallthrough + case 1: + b |= ((uint64_t)ni[0]); + break; + case 0: + break; + } + + v3 ^= b; + + for (int i = 0; i < cROUNDS; i++) { + SIPROUND(&v0, &v1, &v2, &v3); + } + + v0 ^= b; + + if (outlen == 16) { + v2 ^= 0xee; + } else { + v2 ^= 0xff; + } + + for (int i = 0; i < dROUNDS; i++) { + SIPROUND(&v0, &v1, &v2, &v3); + } + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b); + + if (outlen == 8) { + return 0; + } + + v1 ^= 0xdd; + + for (int i = 0; i < dROUNDS; i++) { + SIPROUND(&v0, &v1, &v2, &v3); + } + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out + 8, b); + + return 0; +} |