Files
NetworkManager/shared/nm-utils/siphash24.c
Thomas Haller ee76b0979f all: use siphash24 for hashing
siphash24() is wildly used by projects nowadays.

It's certainly slower then our djb hashing that we used before.
But quite likely it's fast enough for us, given how wildly it is
used. I think it would be hard to profile NetworkManager to show
that the performance of hash tables is the issue, be it with
djb or siphash24.

Certainly with siphash24() it's much harder to exploit the hashing
algorithm to cause worst case hash operations (provided that the
seed is kept private). Does this better resistance against a denial
of service matter for us? Probably not, but let's better be safe then
sorry.

Note that systemd's implementation uses a different seed for each hash
table (at least, after the hash table grows to a certain size).
We don't do that and use only one global seed.
2017-10-18 13:27:02 +02:00

204 lines
7.2 KiB
C

/*
SipHash reference C implementation
Written in 2012 by
Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
Daniel J. Bernstein <djb@cr.yp.to>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
(Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd)
(Refactored by Tom Gundersen to split up in several functions and follow systemd
coding style)
*/
#include "nm-default.h"
#define assert(cond) nm_assert (cond)
#include <stdio.h>
#include "siphash24.h"
#include "unaligned.h"
static inline uint64_t rotate_left(uint64_t x, uint8_t b) {
assert(b < 64);
return (x << b) | (x >> (64 - b));
}
static inline void sipround(struct siphash *state) {
assert(state);
state->v0 += state->v1;
state->v1 = rotate_left(state->v1, 13);
state->v1 ^= state->v0;
state->v0 = rotate_left(state->v0, 32);
state->v2 += state->v3;
state->v3 = rotate_left(state->v3, 16);
state->v3 ^= state->v2;
state->v0 += state->v3;
state->v3 = rotate_left(state->v3, 21);
state->v3 ^= state->v0;
state->v2 += state->v1;
state->v1 = rotate_left(state->v1, 17);
state->v1 ^= state->v2;
state->v2 = rotate_left(state->v2, 32);
}
void siphash24_init(struct siphash *state, const uint8_t k[16]) {
uint64_t k0, k1;
assert(state);
assert(k);
k0 = unaligned_read_le64(k);
k1 = unaligned_read_le64(k + 8);
*state = (struct siphash) {
/* "somepseudorandomlygeneratedbytes" */
.v0 = 0x736f6d6570736575ULL ^ k0,
.v1 = 0x646f72616e646f6dULL ^ k1,
.v2 = 0x6c7967656e657261ULL ^ k0,
.v3 = 0x7465646279746573ULL ^ k1,
.padding = 0,
.inlen = 0,
};
}
void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
const uint8_t *in = _in;
const uint8_t *end = in + inlen;
size_t left = state->inlen & 7;
uint64_t m;
assert(in);
assert(state);
/* Update total length */
state->inlen += inlen;
/* If padding exists, fill it out */
if (left > 0) {
for ( ; in < end && left < 8; in ++, left ++)
state->padding |= ((uint64_t) *in) << (left * 8);
if (in == end && left < 8)
/* We did not have enough input to fill out the padding completely */
return;
#ifdef DEBUG
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
#endif
state->v3 ^= state->padding;
sipround(state);
sipround(state);
state->v0 ^= state->padding;
state->padding = 0;
}
end -= (state->inlen % sizeof(uint64_t));
for ( ; in < end; in += 8) {
m = unaligned_read_le64(in);
#ifdef DEBUG
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m);
#endif
state->v3 ^= m;
sipround(state);
sipround(state);
state->v0 ^= m;
}
left = state->inlen & 7;
switch (left) {
case 7:
state->padding |= ((uint64_t) in[6]) << 48;
/* fall through */
case 6:
state->padding |= ((uint64_t) in[5]) << 40;
/* fall through */
case 5:
state->padding |= ((uint64_t) in[4]) << 32;
/* fall through */
case 4:
state->padding |= ((uint64_t) in[3]) << 24;
/* fall through */
case 3:
state->padding |= ((uint64_t) in[2]) << 16;
/* fall through */
case 2:
state->padding |= ((uint64_t) in[1]) << 8;
/* fall through */
case 1:
state->padding |= ((uint64_t) in[0]);
/* fall through */
case 0:
break;
}
}
uint64_t siphash24_finalize(struct siphash *state) {
uint64_t b;
assert(state);
b = state->padding | (((uint64_t) state->inlen) << 56);
#ifdef DEBUG
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
#endif
state->v3 ^= b;
sipround(state);
sipround(state);
state->v0 ^= b;
#ifdef DEBUG
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
#endif
state->v2 ^= 0xff;
sipround(state);
sipround(state);
sipround(state);
sipround(state);
return state->v0 ^ state->v1 ^ state->v2 ^ state->v3;
}
uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]) {
struct siphash state;
assert(in);
assert(k);
siphash24_init(&state, k);
siphash24_compress(in, inlen, &state);
return siphash24_finalize(&state);
}