diff options
Diffstat (limited to '')
-rw-r--r-- | src/impl.c | 180 | ||||
-rw-r--r-- | src/impl.h | 8 | ||||
-rw-r--r-- | src/lib.c | 78 | ||||
-rw-r--r-- | src/lib.h | 15 | ||||
-rw-r--r-- | src/main.c | 12 | ||||
-rw-r--r-- | src/meta.h.in | 3 | ||||
l--------- | src/siphash.h | 1 |
7 files changed, 297 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; +} diff --git a/src/impl.h b/src/impl.h new file mode 100644 index 0000000..166ccae --- /dev/null +++ b/src/impl.h @@ -0,0 +1,8 @@ +int +siphash_impl( + const void *const restrict in, + const size_t inlen, + const void *const restrict key, + u8 out[16U], + const size_t outlen +); diff --git a/src/lib.c b/src/lib.c new file mode 100644 index 0000000..935ee26 --- /dev/null +++ b/src/lib.c @@ -0,0 +1,78 @@ +#include <s.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "impl.h" + +#include "lib.h" + + + +static int +usage(FILE *restrict stream, const char *const argv0) { + return fprintf(stream, "Usage: %s KEY DATA\n", argv0) < 0; +} + +void +siphash( + const u8 key[SIPHASH_KEY_LENGTH], + const size_t inlen, + const void *const restrict in, + u8 out[SIPHASH_OUTPUT_LENGTH] +) { + siphash_impl(in, inlen, key, out, SIPHASH_OUTPUT_LENGTH); +} + +int +siphash_main(int argc, char *argv[]) { + int rc = EXIT_USAGE; + + if (argc != 3) { + if (usage(stderr, argv[0])) { + rc = EXIT_FAILURE; + perror("usage()"); + goto out; + } + goto out; + } + + const char *const key = argv[1]; + const char *const data = argv[2]; + const size_t keylen = strlen(key); + const size_t datalen = strlen(data); + if (keylen < SIPHASH_KEY_LENGTH) { + if (fprintf( + stderr, + "KEY (%lu) is smaller than SIPHASH_KEY_LENGTH (%d).\n", + keylen, + SIPHASH_KEY_LENGTH + ) < 0) { + rc = EXIT_FAILURE; + perror("fprintf()"); + goto out; + } + goto out; + } + + u8 out[SIPHASH_OUTPUT_LENGTH]; + siphash((u8 *)key, datalen, data, out); + for (int i = 0; i < SIPHASH_OUTPUT_LENGTH; i++) { + const u8 c = out[i]; + if (printf("%x", c) < 0) { + rc = EXIT_FAILURE; + perror("printf()"); + goto out; + } + } + if (printf("\n") < 0) { + rc = EXIT_FAILURE; + perror("printf()"); + goto out; + } + + rc = EXIT_SUCCESS; +out: + return rc; +} diff --git a/src/lib.h b/src/lib.h new file mode 100644 index 0000000..ae16870 --- /dev/null +++ b/src/lib.h @@ -0,0 +1,15 @@ +enum { + SIPHASH_KEY_LENGTH = 16U, + SIPHASH_OUTPUT_LENGTH = 16U, +}; + +void +siphash( + const u8 key[SIPHASH_KEY_LENGTH], + const size_t inlen, + const void *const restrict in, + u8 out[SIPHASH_OUTPUT_LENGTH] +); + +int +siphash_main(int argc, char *argv[]); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..c218d8f --- /dev/null +++ b/src/main.c @@ -0,0 +1,12 @@ +#include <s.h> + +#include <stddef.h> + +#include "siphash.h" + + + +int +main(int argc, char *argv[]) { + return siphash_main(argc, argv); +} diff --git a/src/meta.h.in b/src/meta.h.in new file mode 100644 index 0000000..9bd8c08 --- /dev/null +++ b/src/meta.h.in @@ -0,0 +1,3 @@ +#define VERSION "@VERSION@" +#define DATE "@DATE@" +#define NAME "@NAME@" diff --git a/src/siphash.h b/src/siphash.h new file mode 120000 index 0000000..a564cc1 --- /dev/null +++ b/src/siphash.h @@ -0,0 +1 @@ +lib.h
\ No newline at end of file |