summary refs log tree commit diff
path: root/src/c-siphash
diff options
context:
space:
mode:
Diffstat (limited to 'src/c-siphash')
-rw-r--r--src/c-siphash/src/c-siphash.c110
-rw-r--r--src/c-siphash/src/c-siphash.h26
2 files changed, 94 insertions, 42 deletions
diff --git a/src/c-siphash/src/c-siphash.c b/src/c-siphash/src/c-siphash.c
index 720e403a..b92af658 100644
--- a/src/c-siphash/src/c-siphash.c
+++ b/src/c-siphash/src/c-siphash.c
@@ -8,7 +8,7 @@
  *
  * So far, only SipHash24 is implemented, since there was no need for other
  * parameters. However, adjusted c_siphash_append_X() and
- * C_siphash_finalize_Y() can be easily provided, if required.
+ * c_siphash_finalize_Y() can be easily provided, if required.
  */
 
 #include <c-stdaux.h>
@@ -88,23 +88,8 @@ _c_public_ void c_siphash_init(CSipHash *state, const uint8_t seed[16]) {
         };
 }
 
-/**
- * c_siphash_append() - hash stream of data
- * @state:              context object
- * @bytes:              array of input bytes
- * @n_bytes:            number of input bytes
- *
- * This feeds an array of bytes into the SipHash state machine. This is a
- * streaming-capable API. That is, the resulting hash is the same, regardless
- * of the way you chunk the input.
- * This function simply feeds the given bytes into the SipHash state machine.
- * It does not produce a final hash. You can call this function many times to
- * append more data. To retrieve the final hash, call c_siphash_finalize().
- *
- * Note that this implementation works best when used with chunk-sizes of
- * multiples of 64bit (8-bytes). This is not a requirement, though.
- */
-_c_public_ void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n_bytes) {
+
+static inline _c_always_inline_ void c_siphash_append_N(CSipHash *state, const uint8_t *bytes, size_t n_bytes, unsigned N) {
         const uint8_t *end = bytes + n_bytes;
         size_t left = state->n_bytes & 7;
         uint64_t m;
@@ -123,8 +108,8 @@ _c_public_ void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n
                         return;
 
                 state->v3 ^= state->padding;
-                c_siphash_sipround(state);
-                c_siphash_sipround(state);
+                for (unsigned i = 0; i < N; i++)
+                        c_siphash_sipround(state);
                 state->v0 ^= state->padding;
 
                 state->padding = 0;
@@ -141,8 +126,8 @@ _c_public_ void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n
                 m = c_siphash_read_le64(bytes);
 
                 state->v3 ^= m;
-                c_siphash_sipround(state);
-                c_siphash_sipround(state);
+                for (unsigned i = 0; i < N; i++)
+                        c_siphash_sipround(state);
                 state->v0 ^= m;
         }
 
@@ -179,6 +164,50 @@ _c_public_ void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n
         }
 }
 
+static inline _c_always_inline_ uint64_t c_siphash_finalize_NM(CSipHash *state, unsigned N, unsigned M) {
+        uint64_t b;
+
+        b = state->padding | (((uint64_t) state->n_bytes) << 56);
+
+        state->v3 ^= b;
+        for (unsigned i = 0; i < N; i++)
+                c_siphash_sipround(state);
+        state->v0 ^= b;
+
+        state->v2 ^= 0xff;
+
+        for (unsigned i = 0; i < M; i++)
+                c_siphash_sipround(state);
+
+        return state->v0 ^ state->v1 ^ state->v2  ^ state->v3;
+}
+
+/**
+ * c_siphash_append() - hash stream of data
+ * @state:              context object
+ * @bytes:              array of input bytes
+ * @n_bytes:            number of input bytes
+ *
+ * This feeds an array of bytes into the SipHash state machine. This is a
+ * streaming-capable API. That is, the resulting hash is the same, regardless
+ * of the way you chunk the input.
+ * This function simply feeds the given bytes into the SipHash state machine.
+ * It does not produce a final hash. You can call this function many times to
+ * append more data. To retrieve the final hash, call c_siphash_finalize().
+ *
+ * Note that this implementation works best when used with chunk-sizes of
+ * multiples of 64bit (8-bytes). This is not a requirement, though.
+ *
+ * This uses the SipHash-2-4 variant.
+ */
+_c_public_ void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n_bytes) {
+        c_siphash_append_N(state, bytes, n_bytes, 2);
+}
+
+_c_public_ void c_siphash_append_13(CSipHash *state, const uint8_t *bytes, size_t n_bytes) {
+        c_siphash_append_N(state, bytes, n_bytes, 1);
+}
+
 /**
  * c_siphash_finalize() - finalize hash
  * @state:              context object
@@ -192,26 +221,16 @@ _c_public_ void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n
  * the object, anymore, you can release it any time. There is no need to
  * destroy the object explicitly.
  *
+ * This uses the SipHash-2-4 variant.
+ *
  * Return: 64bit hash value
  */
 _c_public_ uint64_t c_siphash_finalize(CSipHash *state) {
-        uint64_t b;
-
-        b = state->padding | (((uint64_t) state->n_bytes) << 56);
-
-        state->v3 ^= b;
-        c_siphash_sipround(state);
-        c_siphash_sipround(state);
-        state->v0 ^= b;
-
-        state->v2 ^= 0xff;
-
-        c_siphash_sipround(state);
-        c_siphash_sipround(state);
-        c_siphash_sipround(state);
-        c_siphash_sipround(state);
+        return c_siphash_finalize_NM(state, 2, 4);
+}
 
-        return state->v0 ^ state->v1 ^ state->v2  ^ state->v3;
+_c_public_ uint64_t c_siphash_finalize_13(CSipHash *state) {
+        return c_siphash_finalize_NM(state, 1, 3);
 }
 
 /**
@@ -233,13 +252,24 @@ _c_public_ uint64_t c_siphash_finalize(CSipHash *state) {
  * Unlike the streaming API, this is a one-shot call suitable for any data that
  * is available in-memory at the same time.
  *
+ * This uses the SipHash-2-4 variant.
+ *
  * Return: 64bit hash value
  */
 _c_public_ uint64_t c_siphash_hash(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes) {
         CSipHash state;
 
         c_siphash_init(&state, seed);
-        c_siphash_append(&state, bytes, n_bytes);
+        c_siphash_append_24(&state, bytes, n_bytes);
+
+        return c_siphash_finalize_24(&state);
+}
+
+_c_public_ uint64_t c_siphash_hash_13(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes) {
+        CSipHash state;
+
+        c_siphash_init(&state, seed);
+        c_siphash_append_13(&state, bytes, n_bytes);
 
-        return c_siphash_finalize(&state);
+        return c_siphash_finalize_13(&state);
 }
diff --git a/src/c-siphash/src/c-siphash.h b/src/c-siphash/src/c-siphash.h
index c0cfc1e0..24fc3f27 100644
--- a/src/c-siphash/src/c-siphash.h
+++ b/src/c-siphash/src/c-siphash.h
@@ -47,14 +47,36 @@ struct CSipHash {
         size_t n_bytes;
 };
 
-#define C_SIPHASH_NULL {}
+#define C_SIPHASH_NULL {0}
 
 void c_siphash_init(CSipHash *state, const uint8_t seed[16]);
+
+/* siphash-2-4 (default for historical reasons) */
+
 void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n_bytes);
 uint64_t c_siphash_finalize(CSipHash *state);
-
 uint64_t c_siphash_hash(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes);
 
+/* siphash-1-3 */
+
+void c_siphash_append_13(CSipHash *state, const uint8_t *bytes, size_t n_bytes);
+uint64_t c_siphash_finalize_13(CSipHash *state);
+uint64_t c_siphash_hash_13(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes);
+
+/* inline helpers */
+
+static inline void c_siphash_append_24(CSipHash *state, const uint8_t *bytes, size_t n_bytes) {
+        c_siphash_append(state, bytes, n_bytes);
+}
+
+static inline uint64_t c_siphash_finalize_24(CSipHash *state) {
+        return c_siphash_finalize(state);
+}
+
+static inline uint64_t c_siphash_hash_24(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes) {
+        return c_siphash_hash(seed, bytes, n_bytes);
+}
+
 #ifdef __cplusplus
 }
 #endif