aboutsummaryrefslogtreecommitdiff
path: root/src/impl.c
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2023-12-31 08:49:16 -0300
committerEuAndreh <eu@euandre.org>2025-06-04 20:11:50 -0300
commitbf54d3bc7be151ee3de15e3cc9fabea68369008e (patch)
tree6ee57bf4e6d57f3aaba9155a3088323a446d5df8 /src/impl.c
parentAdd complete "Makefile" for standard packaging (diff)
downloadsiphash-main.tar.gz
siphash-main.tar.xz
Rewrite code, but keeping the exact same semantic and behaviourHEADmain
- assert that the generated `siphash.o` code is identical to the original code, available at `tests/assert-identical.sh`; - remove unneeded `#define`s; - rewrite code with the correct indentation, spacing and formatting; - use C99 constructs over C89 (for loop variable declarations inside the parentheses); - fix the public API.
Diffstat (limited to '')
-rw-r--r--src/impl.c180
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;
+}