|
|
749169 |
From 4250a33a40c14325fb6076cded8e88b5a717ed13 Mon Sep 17 00:00:00 2001
|
|
|
d7027e |
From: Greg Hudson <ghudson@mit.edu>
|
|
|
d7027e |
Date: Sat, 4 Aug 2018 20:11:09 -0400
|
|
|
d7027e |
Subject: [PATCH] Add a hash table implementation to libkrb5support
|
|
|
d7027e |
|
|
|
d7027e |
(cherry picked from commit 09e814fe47f5ceeb35bee15ced6e346db8a5e81d)
|
|
|
d7027e |
[rharwood@redhat.com: gitignore, no utf16]
|
|
|
d7027e |
---
|
|
|
d7027e |
src/include/k5-hashtab.h | 79 ++++++
|
|
|
d7027e |
src/util/support/Makefile.in | 15 +-
|
|
|
d7027e |
src/util/support/deps | 11 +
|
|
|
d7027e |
src/util/support/hashtab.c | 243 ++++++++++++++++++
|
|
|
d7027e |
src/util/support/libkrb5support-fixed.exports | 5 +
|
|
|
d7027e |
src/util/support/t_hashtab.c | 176 +++++++++++++
|
|
|
d7027e |
6 files changed, 526 insertions(+), 3 deletions(-)
|
|
|
d7027e |
create mode 100644 src/include/k5-hashtab.h
|
|
|
d7027e |
create mode 100644 src/util/support/hashtab.c
|
|
|
d7027e |
create mode 100644 src/util/support/t_hashtab.c
|
|
|
d7027e |
|
|
|
d7027e |
diff --git a/src/include/k5-hashtab.h b/src/include/k5-hashtab.h
|
|
|
d7027e |
new file mode 100644
|
|
|
d7027e |
index 000000000..dc0ef3613
|
|
|
d7027e |
--- /dev/null
|
|
|
d7027e |
+++ b/src/include/k5-hashtab.h
|
|
|
d7027e |
@@ -0,0 +1,79 @@
|
|
|
d7027e |
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
d7027e |
+/* include/k5-hash.h - hash table interface definitions */
|
|
|
d7027e |
+/*
|
|
|
d7027e |
+ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
|
|
|
d7027e |
+ * All rights reserved.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * Redistribution and use in source and binary forms, with or without
|
|
|
d7027e |
+ * modification, are permitted provided that the following conditions
|
|
|
d7027e |
+ * are met:
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * * Redistributions of source code must retain the above copyright
|
|
|
d7027e |
+ * notice, this list of conditions and the following disclaimer.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * * Redistributions in binary form must reproduce the above copyright
|
|
|
d7027e |
+ * notice, this list of conditions and the following disclaimer in
|
|
|
d7027e |
+ * the documentation and/or other materials provided with the
|
|
|
d7027e |
+ * distribution.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
d7027e |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
d7027e |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
d7027e |
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
d7027e |
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
|
d7027e |
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
d7027e |
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
d7027e |
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
d7027e |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
d7027e |
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
d7027e |
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
d7027e |
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
d7027e |
+ */
|
|
|
d7027e |
+
|
|
|
d7027e |
+/*
|
|
|
d7027e |
+ * This file contains declarations for a simple hash table using siphash. Some
|
|
|
d7027e |
+ * limitations which might need to be addressed in the future:
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * - The table does not manage caller memory. This limitation could be
|
|
|
d7027e |
+ * addressed by adding an optional free callback to k5_hashtab_create(), to
|
|
|
d7027e |
+ * be called by k5_hashtab_free() and k5_hashtab_remove().
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * - There is no way to iterate over a hash table.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * - k5_hashtab_add() does not check for duplicate entries.
|
|
|
d7027e |
+ */
|
|
|
d7027e |
+
|
|
|
d7027e |
+#ifndef K5_HASH_H
|
|
|
d7027e |
+#define K5_HASH_H
|
|
|
d7027e |
+
|
|
|
d7027e |
+#define K5_HASH_SEED_LEN 16
|
|
|
d7027e |
+
|
|
|
d7027e |
+struct k5_hashtab;
|
|
|
d7027e |
+
|
|
|
d7027e |
+/*
|
|
|
d7027e |
+ * Create a new hash table in *ht_out. seed must point to random bytes if keys
|
|
|
d7027e |
+ * might be under the control of an attacker; otherwise it may be NULL.
|
|
|
d7027e |
+ * initial_buckets controls the initial allocation of hash buckets; pass zero
|
|
|
d7027e |
+ * to use a default value. The number of hash buckets will be doubled as the
|
|
|
d7027e |
+ * number of entries increases. Return 0 on success, ENOMEM on failure.
|
|
|
d7027e |
+ */
|
|
|
d7027e |
+int k5_hashtab_create(const uint8_t seed[K5_HASH_SEED_LEN],
|
|
|
d7027e |
+ size_t initial_buckets, struct k5_hashtab **ht_out);
|
|
|
d7027e |
+
|
|
|
d7027e |
+/* Release the memory used by a hash table. Keys and values are the caller's
|
|
|
d7027e |
+ * responsibility. */
|
|
|
d7027e |
+void k5_hashtab_free(struct k5_hashtab *ht);
|
|
|
d7027e |
+
|
|
|
d7027e |
+/* Add an entry to a hash table. key and val must remain valid until the entry
|
|
|
d7027e |
+ * is removed or the hash table is freed. The caller must avoid duplicates. */
|
|
|
d7027e |
+int k5_hashtab_add(struct k5_hashtab *ht, const void *key, size_t klen,
|
|
|
d7027e |
+ void *val);
|
|
|
d7027e |
+
|
|
|
d7027e |
+/* Remove an entry from a hash table by key. Does not free key or the
|
|
|
d7027e |
+ * associated value. Return 1 if the key was found and removed, 0 if not. */
|
|
|
d7027e |
+int k5_hashtab_remove(struct k5_hashtab *ht, const void *key, size_t klen);
|
|
|
d7027e |
+
|
|
|
d7027e |
+/* Retrieve a value from a hash table by key. */
|
|
|
d7027e |
+void *k5_hashtab_get(struct k5_hashtab *ht, const void *key, size_t klen);
|
|
|
d7027e |
+
|
|
|
d7027e |
+#endif /* K5_HASH_H */
|
|
|
d7027e |
diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
|
|
|
d7027e |
index b3576f0b7..12797068f 100644
|
|
|
d7027e |
--- a/src/util/support/Makefile.in
|
|
|
d7027e |
+++ b/src/util/support/Makefile.in
|
|
|
d7027e |
@@ -83,6 +83,7 @@ STLIBOBJS= \
|
|
|
d7027e |
base64.o \
|
|
|
d7027e |
json.o \
|
|
|
d7027e |
hex.o \
|
|
|
d7027e |
+ hashtab.o \
|
|
|
d7027e |
bcmp.o \
|
|
|
d7027e |
strerror_r.o \
|
|
|
d7027e |
dir_filenames.o \
|
|
|
d7027e |
@@ -110,6 +111,7 @@ LIBOBJS= \
|
|
|
d7027e |
$(OUTPRE)base64.$(OBJEXT) \
|
|
|
d7027e |
$(OUTPRE)json.$(OBJEXT) \
|
|
|
d7027e |
$(OUTPRE)hex.$(OBJEXT) \
|
|
|
d7027e |
+ $(OUTPRE)hashtab.$(OBJEXT) \
|
|
|
d7027e |
$(OUTPRE)bcmp.$(OBJEXT) \
|
|
|
d7027e |
$(OUTPRE)strerror_r.$(OBJEXT) \
|
|
|
d7027e |
$(OUTPRE)dir_filenames.$(OBJEXT) \
|
|
|
d7027e |
@@ -142,11 +144,13 @@ SRCS=\
|
|
|
d7027e |
$(srcdir)/t_path.c \
|
|
|
d7027e |
$(srcdir)/t_json.c \
|
|
|
d7027e |
$(srcdir)/t_hex.c \
|
|
|
d7027e |
+ $(srcdir)/t_hashtab.c \
|
|
|
d7027e |
$(srcdir)/zap.c \
|
|
|
d7027e |
$(srcdir)/path.c \
|
|
|
d7027e |
$(srcdir)/base64.c \
|
|
|
d7027e |
$(srcdir)/json.c \
|
|
|
d7027e |
$(srcdir)/hex.c \
|
|
|
d7027e |
+ $(srcdir)/hashtab.c \
|
|
|
d7027e |
$(srcdir)/bcmp.c \
|
|
|
d7027e |
$(srcdir)/strerror_r.c \
|
|
|
d7027e |
$(srcdir)/dir_filenames.c \
|
|
|
d7027e |
@@ -225,13 +229,17 @@ t_json: $(T_JSON_OBJS)
|
|
|
d7027e |
t_hex: t_hex.o hex.o
|
|
|
d7027e |
$(CC_LINK) -o $@ t_hex.o hex.o
|
|
|
d7027e |
|
|
|
d7027e |
+t_hashtab: t_hashtab.o
|
|
|
d7027e |
+ $(CC_LINK) -o $@ t_hashtab.o
|
|
|
d7027e |
+
|
|
|
d7027e |
t_unal: t_unal.o
|
|
|
d7027e |
$(CC_LINK) -o t_unal t_unal.o
|
|
|
d7027e |
|
|
|
d7027e |
t_utf8: t_utf8.o utf8.o
|
|
|
d7027e |
$(CC_LINK) -o t_utf8 t_utf8.o utf8.o
|
|
|
d7027e |
|
|
|
d7027e |
-TEST_PROGS= t_k5buf t_path t_path_win t_base64 t_json t_hex t_unal t_utf8
|
|
|
d7027e |
+TEST_PROGS= t_k5buf t_path t_path_win t_base64 t_json t_hex t_hashtab t_unal \
|
|
|
d7027e |
+ t_utf8
|
|
|
d7027e |
|
|
|
d7027e |
check-unix: $(TEST_PROGS)
|
|
|
d7027e |
./t_k5buf
|
|
|
d7027e |
@@ -240,14 +248,15 @@ check-unix: $(TEST_PROGS)
|
|
|
d7027e |
./t_base64
|
|
|
d7027e |
./t_json
|
|
|
d7027e |
./t_hex
|
|
|
d7027e |
+ ./t_hashtab
|
|
|
d7027e |
./t_unal
|
|
|
d7027e |
./t_utf8
|
|
|
d7027e |
|
|
|
d7027e |
clean:
|
|
|
d7027e |
$(RM) t_k5buf.o t_k5buf t_unal.o t_unal path_win.o path_win
|
|
|
d7027e |
$(RM) t_path_win.o t_path_win t_path.o t_path t_base64.o t_base64
|
|
|
d7027e |
- $(RM) t_json.o t_json t_hex.o t_hex libkrb5support.exports
|
|
|
d7027e |
- $(RM) t_utf8.o t_utf8
|
|
|
d7027e |
+ $(RM) t_json.o t_json t_hex.o t_hex t_hashtab.o t_hashtab
|
|
|
d7027e |
+ $(RM) t_utf8.o t_utf8 libkrb5support.exports
|
|
|
d7027e |
|
|
|
d7027e |
@lib_frag@
|
|
|
d7027e |
@libobj_frag@
|
|
|
d7027e |
diff --git a/src/util/support/deps b/src/util/support/deps
|
|
|
d7027e |
index 551843357..d43baea13 100644
|
|
|
d7027e |
--- a/src/util/support/deps
|
|
|
d7027e |
+++ b/src/util/support/deps
|
|
|
d7027e |
@@ -65,6 +65,10 @@ t_json.so t_json.po $(OUTPRE)t_json.$(OBJEXT): $(top_srcdir)/include/k5-json.h \
|
|
|
d7027e |
t_hex.so t_hex.po $(OUTPRE)t_hex.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-hex.h $(top_srcdir)/include/k5-platform.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-thread.h t_hex.c
|
|
|
d7027e |
+t_hashtab.so t_hashtab.po $(OUTPRE)t_hashtab.$(OBJEXT): \
|
|
|
d7027e |
+ $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-hashtab.h \
|
|
|
d7027e |
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-queue.h \
|
|
|
d7027e |
+ $(top_srcdir)/include/k5-thread.h hashtab.c t_hashtab.c
|
|
|
d7027e |
zap.so zap.po $(OUTPRE)zap.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
|
|
|
d7027e |
zap.c
|
|
|
d7027e |
@@ -81,12 +85,19 @@ json.so json.po $(OUTPRE)json.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
|
|
d7027e |
hex.so hex.po $(OUTPRE)hex.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-hex.h $(top_srcdir)/include/k5-platform.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-thread.h hex.c
|
|
|
d7027e |
+hashtab.so hashtab.po $(OUTPRE)hashtab.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
|
|
d7027e |
+ $(top_srcdir)/include/k5-hashtab.h $(top_srcdir)/include/k5-platform.h \
|
|
|
d7027e |
+ $(top_srcdir)/include/k5-queue.h $(top_srcdir)/include/k5-thread.h \
|
|
|
d7027e |
+ hashtab.c
|
|
|
d7027e |
bcmp.so bcmp.po $(OUTPRE)bcmp.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
|
|
|
d7027e |
bcmp.c
|
|
|
d7027e |
strerror_r.so strerror_r.po $(OUTPRE)strerror_r.$(OBJEXT): \
|
|
|
d7027e |
$(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-platform.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-thread.h strerror_r.c
|
|
|
d7027e |
+dir_filenames.so dir_filenames.po $(OUTPRE)dir_filenames.$(OBJEXT): \
|
|
|
d7027e |
+ $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-platform.h \
|
|
|
d7027e |
+ $(top_srcdir)/include/k5-thread.h dir_filenames.c
|
|
|
d7027e |
t_utf8.so t_utf8.po $(OUTPRE)t_utf8.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
|
|
|
d7027e |
$(top_srcdir)/include/k5-utf8.h t_utf8.c
|
|
|
d7027e |
diff --git a/src/util/support/hashtab.c b/src/util/support/hashtab.c
|
|
|
d7027e |
new file mode 100644
|
|
|
d7027e |
index 000000000..e04e491b2
|
|
|
d7027e |
--- /dev/null
|
|
|
d7027e |
+++ b/src/util/support/hashtab.c
|
|
|
d7027e |
@@ -0,0 +1,243 @@
|
|
|
d7027e |
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
d7027e |
+/* util/support/hash.c - hash table implementation */
|
|
|
d7027e |
+/*
|
|
|
d7027e |
+ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
|
|
|
d7027e |
+ * All rights reserved.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * Redistribution and use in source and binary forms, with or without
|
|
|
d7027e |
+ * modification, are permitted provided that the following conditions
|
|
|
d7027e |
+ * are met:
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * * Redistributions of source code must retain the above copyright
|
|
|
d7027e |
+ * notice, this list of conditions and the following disclaimer.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * * Redistributions in binary form must reproduce the above copyright
|
|
|
d7027e |
+ * notice, this list of conditions and the following disclaimer in
|
|
|
d7027e |
+ * the documentation and/or other materials provided with the
|
|
|
d7027e |
+ * distribution.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
d7027e |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
d7027e |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
d7027e |
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
d7027e |
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
|
d7027e |
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
d7027e |
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
d7027e |
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
d7027e |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
d7027e |
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
d7027e |
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
d7027e |
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
d7027e |
+ */
|
|
|
d7027e |
+
|
|
|
d7027e |
+#include "k5-platform.h"
|
|
|
d7027e |
+#include "k5-hashtab.h"
|
|
|
d7027e |
+#include "k5-queue.h"
|
|
|
d7027e |
+
|
|
|
d7027e |
+struct entry {
|
|
|
d7027e |
+ const void *key;
|
|
|
d7027e |
+ size_t klen;
|
|
|
d7027e |
+ void *val;
|
|
|
d7027e |
+ K5_SLIST_ENTRY(entry) next;
|
|
|
d7027e |
+};
|
|
|
d7027e |
+
|
|
|
d7027e |
+struct k5_hashtab {
|
|
|
d7027e |
+ uint64_t k0;
|
|
|
d7027e |
+ uint64_t k1;
|
|
|
d7027e |
+ size_t nbuckets;
|
|
|
d7027e |
+ size_t nentries;
|
|
|
d7027e |
+ K5_SLIST_HEAD(bucket_list, entry) *buckets;
|
|
|
d7027e |
+};
|
|
|
d7027e |
+
|
|
|
d7027e |
+/* Return x rotated to the left by r bits. */
|
|
|
d7027e |
+static inline uint64_t
|
|
|
d7027e |
+rotl64(uint64_t x, int r)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ return (x << r) | (x >> (64 - r));
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+static inline void
|
|
|
d7027e |
+sipround(uint64_t *v0, uint64_t *v1, uint64_t *v2, uint64_t *v3)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ *v0 += *v1;
|
|
|
d7027e |
+ *v2 += *v3;
|
|
|
d7027e |
+ *v1 = rotl64(*v1, 13) ^ *v0;
|
|
|
d7027e |
+ *v3 = rotl64(*v3, 16) ^ *v2;
|
|
|
d7027e |
+ *v0 = rotl64(*v0, 32);
|
|
|
d7027e |
+ *v2 += *v1;
|
|
|
d7027e |
+ *v0 += *v3;
|
|
|
d7027e |
+ *v1 = rotl64(*v1, 17) ^ *v2;
|
|
|
d7027e |
+ *v3 = rotl64(*v3, 21) ^ *v0;
|
|
|
d7027e |
+ *v2 = rotl64(*v2, 32);
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+/* SipHash-2-4 from https://131002.net/siphash/siphash.pdf (Jean-Philippe
|
|
|
d7027e |
+ * Aumasson and Daniel J. Bernstein) */
|
|
|
d7027e |
+static uint64_t
|
|
|
d7027e |
+siphash24(const uint8_t *data, size_t len, uint64_t k0, uint64_t k1)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ uint64_t v0 = k0 ^ 0x736F6D6570736575;
|
|
|
d7027e |
+ uint64_t v1 = k1 ^ 0x646F72616E646F6D;
|
|
|
d7027e |
+ uint64_t v2 = k0 ^ 0x6C7967656E657261;
|
|
|
d7027e |
+ uint64_t v3 = k1 ^ 0x7465646279746573;
|
|
|
d7027e |
+ uint64_t mi;
|
|
|
d7027e |
+ const uint8_t *p, *end = data + (len - len % 8);
|
|
|
d7027e |
+ uint8_t last[8] = { 0 };
|
|
|
d7027e |
+
|
|
|
d7027e |
+ /* Process each full 8-byte chunk of data. */
|
|
|
d7027e |
+ for (p = data; p < end; p += 8) {
|
|
|
d7027e |
+ mi = load_64_le(p);
|
|
|
d7027e |
+ v3 ^= mi;
|
|
|
d7027e |
+ sipround(&v0, &v1, &v2, &v3;;
|
|
|
d7027e |
+ sipround(&v0, &v1, &v2, &v3;;
|
|
|
d7027e |
+ v0 ^= mi;
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+
|
|
|
d7027e |
+ /* Process the last 0-7 bytes followed by the length mod 256. */
|
|
|
d7027e |
+ memcpy(last, end, len % 8);
|
|
|
d7027e |
+ last[7] = len & 0xFF;
|
|
|
d7027e |
+ mi = load_64_le(last);
|
|
|
d7027e |
+ v3 ^= mi;
|
|
|
d7027e |
+ sipround(&v0, &v1, &v2, &v3;;
|
|
|
d7027e |
+ sipround(&v0, &v1, &v2, &v3;;
|
|
|
d7027e |
+ v0 ^= mi;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ /* Finalize. */
|
|
|
d7027e |
+ v2 ^= 0xFF;
|
|
|
d7027e |
+ sipround(&v0, &v1, &v2, &v3;;
|
|
|
d7027e |
+ sipround(&v0, &v1, &v2, &v3;;
|
|
|
d7027e |
+ sipround(&v0, &v1, &v2, &v3;;
|
|
|
d7027e |
+ sipround(&v0, &v1, &v2, &v3;;
|
|
|
d7027e |
+ return v0 ^ v1 ^ v2 ^ v3;
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+int
|
|
|
d7027e |
+k5_hashtab_create(const uint8_t seed[K5_HASH_SEED_LEN], size_t initial_buckets,
|
|
|
d7027e |
+ struct k5_hashtab **ht_out)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ struct k5_hashtab *ht;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ *ht_out = NULL;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ ht = malloc(sizeof(*ht));
|
|
|
d7027e |
+ if (ht == NULL)
|
|
|
d7027e |
+ return ENOMEM;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ if (seed != NULL) {
|
|
|
d7027e |
+ ht->k0 = load_64_le(seed);
|
|
|
d7027e |
+ ht->k1 = load_64_le(seed + 8);
|
|
|
d7027e |
+ } else {
|
|
|
d7027e |
+ ht->k0 = ht->k1 = 0;
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+ ht->nbuckets = (initial_buckets > 0) ? initial_buckets : 64;
|
|
|
d7027e |
+ ht->nentries = 0;
|
|
|
d7027e |
+ ht->buckets = calloc(ht->nbuckets, sizeof(*ht->buckets));
|
|
|
d7027e |
+ if (ht->buckets == NULL) {
|
|
|
d7027e |
+ free(ht);
|
|
|
d7027e |
+ return ENOMEM;
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+
|
|
|
d7027e |
+ *ht_out = ht;
|
|
|
d7027e |
+ return 0;
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+void
|
|
|
d7027e |
+k5_hashtab_free(struct k5_hashtab *ht)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ size_t i;
|
|
|
d7027e |
+ struct entry *ent;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ for (i = 0; i < ht->nbuckets; i++) {
|
|
|
d7027e |
+ while (!K5_SLIST_EMPTY(&ht->buckets[i])) {
|
|
|
d7027e |
+ ent = K5_SLIST_FIRST(&ht->buckets[i]);
|
|
|
d7027e |
+ K5_SLIST_REMOVE_HEAD(&ht->buckets[i], next);
|
|
|
d7027e |
+ free(ent);
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+ free(ht->buckets);
|
|
|
d7027e |
+ free(ht);
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+static int
|
|
|
d7027e |
+resize_table(struct k5_hashtab *ht)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ size_t i, j, newsize = ht->nbuckets * 2;
|
|
|
d7027e |
+ struct bucket_list *newbuckets;
|
|
|
d7027e |
+ struct entry *ent;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ newbuckets = calloc(newsize, sizeof(*newbuckets));
|
|
|
d7027e |
+ if (newbuckets == NULL)
|
|
|
d7027e |
+ return ENOMEM;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ /* Rehash all the entries into the new buckets. */
|
|
|
d7027e |
+ for (i = 0; i < ht->nbuckets; i++) {
|
|
|
d7027e |
+ while (!K5_SLIST_EMPTY(&ht->buckets[i])) {
|
|
|
d7027e |
+ ent = K5_SLIST_FIRST(&ht->buckets[i]);
|
|
|
d7027e |
+ j = siphash24(ent->key, ent->klen, ht->k0, ht->k1) % newsize;
|
|
|
d7027e |
+ K5_SLIST_REMOVE_HEAD(&ht->buckets[i], next);
|
|
|
d7027e |
+ K5_SLIST_INSERT_HEAD(&newbuckets[j], ent, next);
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+
|
|
|
d7027e |
+ free(ht->buckets);
|
|
|
d7027e |
+ ht->buckets = newbuckets;
|
|
|
d7027e |
+ ht->nbuckets = newsize;
|
|
|
d7027e |
+ return 0;
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+int
|
|
|
d7027e |
+k5_hashtab_add(struct k5_hashtab *ht, const void *key, size_t klen, void *val)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ size_t i;
|
|
|
d7027e |
+ struct entry *ent;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ if (ht->nentries == ht->nbuckets) {
|
|
|
d7027e |
+ if (resize_table(ht) != 0)
|
|
|
d7027e |
+ return ENOMEM;
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+
|
|
|
d7027e |
+ ent = malloc(sizeof(*ent));
|
|
|
d7027e |
+ if (ent == NULL)
|
|
|
d7027e |
+ return ENOMEM;
|
|
|
d7027e |
+ ent->key = key;
|
|
|
d7027e |
+ ent->klen = klen;
|
|
|
d7027e |
+ ent->val = val;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ i = siphash24(key, klen, ht->k0, ht->k1) % ht->nbuckets;
|
|
|
d7027e |
+ K5_SLIST_INSERT_HEAD(&ht->buckets[i], ent, next);
|
|
|
d7027e |
+
|
|
|
d7027e |
+ ht->nentries++;
|
|
|
d7027e |
+ return 0;
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+int
|
|
|
d7027e |
+k5_hashtab_remove(struct k5_hashtab *ht, const void *key, size_t klen)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ size_t i;
|
|
|
d7027e |
+ struct entry *ent;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ i = siphash24(key, klen, ht->k0, ht->k1) % ht->nbuckets;
|
|
|
d7027e |
+ K5_SLIST_FOREACH(ent, &ht->buckets[i], next) {
|
|
|
d7027e |
+ if (ent->klen == klen && memcmp(ent->key, key, klen) == 0) {
|
|
|
d7027e |
+ K5_SLIST_REMOVE(&ht->buckets[i], ent, entry, next);
|
|
|
d7027e |
+ free(ent);
|
|
|
d7027e |
+ ht->nentries--;
|
|
|
d7027e |
+ return 1;
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+ return 0;
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+void *
|
|
|
d7027e |
+k5_hashtab_get(struct k5_hashtab *ht, const void *key, size_t klen)
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ size_t i;
|
|
|
d7027e |
+ struct entry *ent;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ i = siphash24(key, klen, ht->k0, ht->k1) % ht->nbuckets;
|
|
|
d7027e |
+ K5_SLIST_FOREACH(ent, &ht->buckets[i], next) {
|
|
|
d7027e |
+ if (ent->klen == klen && memcmp(ent->key, key, klen) == 0)
|
|
|
d7027e |
+ return ent->val;
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+ return NULL;
|
|
|
d7027e |
+}
|
|
|
d7027e |
diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
|
|
|
d7027e |
index 6193d7331..c63c5fbc3 100644
|
|
|
d7027e |
--- a/src/util/support/libkrb5support-fixed.exports
|
|
|
d7027e |
+++ b/src/util/support/libkrb5support-fixed.exports
|
|
|
d7027e |
@@ -16,6 +16,11 @@ k5_get_error
|
|
|
d7027e |
k5_free_error
|
|
|
d7027e |
k5_clear_error
|
|
|
d7027e |
k5_set_error_info_callout_fn
|
|
|
d7027e |
+k5_hashtab_add
|
|
|
d7027e |
+k5_hashtab_create
|
|
|
d7027e |
+k5_hashtab_free
|
|
|
d7027e |
+k5_hashtab_get
|
|
|
d7027e |
+k5_hashtab_remove
|
|
|
d7027e |
k5_hex_decode
|
|
|
d7027e |
k5_hex_encode
|
|
|
d7027e |
k5_json_array_add
|
|
|
d7027e |
diff --git a/src/util/support/t_hashtab.c b/src/util/support/t_hashtab.c
|
|
|
d7027e |
new file mode 100644
|
|
|
d7027e |
index 000000000..f51abc4f1
|
|
|
d7027e |
--- /dev/null
|
|
|
d7027e |
+++ b/src/util/support/t_hashtab.c
|
|
|
d7027e |
@@ -0,0 +1,176 @@
|
|
|
d7027e |
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
d7027e |
+/* util/support/t_hash.c - tests for hash table code */
|
|
|
d7027e |
+/*
|
|
|
d7027e |
+ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
|
|
|
d7027e |
+ * All rights reserved.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * Redistribution and use in source and binary forms, with or without
|
|
|
d7027e |
+ * modification, are permitted provided that the following conditions
|
|
|
d7027e |
+ * are met:
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * * Redistributions of source code must retain the above copyright
|
|
|
d7027e |
+ * notice, this list of conditions and the following disclaimer.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * * Redistributions in binary form must reproduce the above copyright
|
|
|
d7027e |
+ * notice, this list of conditions and the following disclaimer in
|
|
|
d7027e |
+ * the documentation and/or other materials provided with the
|
|
|
d7027e |
+ * distribution.
|
|
|
d7027e |
+ *
|
|
|
d7027e |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
d7027e |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
d7027e |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
d7027e |
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
d7027e |
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
|
d7027e |
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
d7027e |
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
d7027e |
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
d7027e |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
d7027e |
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
d7027e |
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
d7027e |
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
d7027e |
+ */
|
|
|
d7027e |
+
|
|
|
d7027e |
+/* hash.c has no linker dependencies, so we can simply include its source code
|
|
|
d7027e |
+ * to test its static functions and look inside its structures. */
|
|
|
d7027e |
+#include "hashtab.c"
|
|
|
d7027e |
+
|
|
|
d7027e |
+/* These match the sip64 test vectors in the reference C implementation of
|
|
|
d7027e |
+ * siphash at https://github.com/veorq/SipHash */
|
|
|
d7027e |
+const uint64_t vectors[64] = {
|
|
|
d7027e |
+ 0x726FDB47DD0E0E31,
|
|
|
d7027e |
+ 0x74F839C593DC67FD,
|
|
|
d7027e |
+ 0x0D6C8009D9A94F5A,
|
|
|
d7027e |
+ 0x85676696D7FB7E2D,
|
|
|
d7027e |
+ 0xCF2794E0277187B7,
|
|
|
d7027e |
+ 0x18765564CD99A68D,
|
|
|
d7027e |
+ 0xCBC9466E58FEE3CE,
|
|
|
d7027e |
+ 0xAB0200F58B01D137,
|
|
|
d7027e |
+ 0x93F5F5799A932462,
|
|
|
d7027e |
+ 0x9E0082DF0BA9E4B0,
|
|
|
d7027e |
+ 0x7A5DBBC594DDB9F3,
|
|
|
d7027e |
+ 0xF4B32F46226BADA7,
|
|
|
d7027e |
+ 0x751E8FBC860EE5FB,
|
|
|
d7027e |
+ 0x14EA5627C0843D90,
|
|
|
d7027e |
+ 0xF723CA908E7AF2EE,
|
|
|
d7027e |
+ 0xA129CA6149BE45E5,
|
|
|
d7027e |
+ 0x3F2ACC7F57C29BDB,
|
|
|
d7027e |
+ 0x699AE9F52CBE4794,
|
|
|
d7027e |
+ 0x4BC1B3F0968DD39C,
|
|
|
d7027e |
+ 0xBB6DC91DA77961BD,
|
|
|
d7027e |
+ 0xBED65CF21AA2EE98,
|
|
|
d7027e |
+ 0xD0F2CBB02E3B67C7,
|
|
|
d7027e |
+ 0x93536795E3A33E88,
|
|
|
d7027e |
+ 0xA80C038CCD5CCEC8,
|
|
|
d7027e |
+ 0xB8AD50C6F649AF94,
|
|
|
d7027e |
+ 0xBCE192DE8A85B8EA,
|
|
|
d7027e |
+ 0x17D835B85BBB15F3,
|
|
|
d7027e |
+ 0x2F2E6163076BCFAD,
|
|
|
d7027e |
+ 0xDE4DAAACA71DC9A5,
|
|
|
d7027e |
+ 0xA6A2506687956571,
|
|
|
d7027e |
+ 0xAD87A3535C49EF28,
|
|
|
d7027e |
+ 0x32D892FAD841C342,
|
|
|
d7027e |
+ 0x7127512F72F27CCE,
|
|
|
d7027e |
+ 0xA7F32346F95978E3,
|
|
|
d7027e |
+ 0x12E0B01ABB051238,
|
|
|
d7027e |
+ 0x15E034D40FA197AE,
|
|
|
d7027e |
+ 0x314DFFBE0815A3B4,
|
|
|
d7027e |
+ 0x027990F029623981,
|
|
|
d7027e |
+ 0xCADCD4E59EF40C4D,
|
|
|
d7027e |
+ 0x9ABFD8766A33735C,
|
|
|
d7027e |
+ 0x0E3EA96B5304A7D0,
|
|
|
d7027e |
+ 0xAD0C42D6FC585992,
|
|
|
d7027e |
+ 0x187306C89BC215A9,
|
|
|
d7027e |
+ 0xD4A60ABCF3792B95,
|
|
|
d7027e |
+ 0xF935451DE4F21DF2,
|
|
|
d7027e |
+ 0xA9538F0419755787,
|
|
|
d7027e |
+ 0xDB9ACDDFF56CA510,
|
|
|
d7027e |
+ 0xD06C98CD5C0975EB,
|
|
|
d7027e |
+ 0xE612A3CB9ECBA951,
|
|
|
d7027e |
+ 0xC766E62CFCADAF96,
|
|
|
d7027e |
+ 0xEE64435A9752FE72,
|
|
|
d7027e |
+ 0xA192D576B245165A,
|
|
|
d7027e |
+ 0x0A8787BF8ECB74B2,
|
|
|
d7027e |
+ 0x81B3E73D20B49B6F,
|
|
|
d7027e |
+ 0x7FA8220BA3B2ECEA,
|
|
|
d7027e |
+ 0x245731C13CA42499,
|
|
|
d7027e |
+ 0xB78DBFAF3A8D83BD,
|
|
|
d7027e |
+ 0xEA1AD565322A1A0B,
|
|
|
d7027e |
+ 0x60E61C23A3795013,
|
|
|
d7027e |
+ 0x6606D7E446282B93,
|
|
|
d7027e |
+ 0x6CA4ECB15C5F91E1,
|
|
|
d7027e |
+ 0x9F626DA15C9625F3,
|
|
|
d7027e |
+ 0xE51B38608EF25F57,
|
|
|
d7027e |
+ 0x958A324CEB064572
|
|
|
d7027e |
+};
|
|
|
d7027e |
+
|
|
|
d7027e |
+static void
|
|
|
d7027e |
+test_siphash()
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ uint8_t seq[64];
|
|
|
d7027e |
+ uint64_t k0, k1, hval;
|
|
|
d7027e |
+ size_t i;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ for (i = 0; i < sizeof(seq); i++)
|
|
|
d7027e |
+ seq[i] = i;
|
|
|
d7027e |
+ k0 = load_64_le(seq);
|
|
|
d7027e |
+ k1 = load_64_le(seq + 8);
|
|
|
d7027e |
+
|
|
|
d7027e |
+ for (i = 0; i < sizeof(seq); i++) {
|
|
|
d7027e |
+ hval = siphash24(seq, i, k0, k1);
|
|
|
d7027e |
+ assert(hval == vectors[i]);
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+static void
|
|
|
d7027e |
+test_hashtab()
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ int st;
|
|
|
d7027e |
+ struct k5_hashtab *ht;
|
|
|
d7027e |
+ size_t i;
|
|
|
d7027e |
+ char zeros[100] = { 0 };
|
|
|
d7027e |
+
|
|
|
d7027e |
+ st = k5_hashtab_create(NULL, 4, &ht;;
|
|
|
d7027e |
+ assert(st == 0 && ht != NULL && ht->nentries == 0);
|
|
|
d7027e |
+
|
|
|
d7027e |
+ st = k5_hashtab_add(ht, "abc", 3, &st);
|
|
|
d7027e |
+ assert(st == 0 && ht->nentries == 1);
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, "abc", 3) == &st);
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, "bcde", 4) == NULL);
|
|
|
d7027e |
+
|
|
|
d7027e |
+ st = k5_hashtab_add(ht, "bcde", 4, &ht;;
|
|
|
d7027e |
+ assert(st == 0 && ht->nentries == 2);
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, "abc", 3) == &st);
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, "bcde", 4) == &ht;;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ k5_hashtab_remove(ht, "abc", 3);
|
|
|
d7027e |
+ assert(ht->nentries == 1);
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, "abc", 3) == NULL);
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, "bcde", 4) == &ht;;
|
|
|
d7027e |
+
|
|
|
d7027e |
+ k5_hashtab_remove(ht, "bcde", 4);
|
|
|
d7027e |
+ assert(ht->nentries == 0);
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, "abc", 3) == NULL);
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, "bcde", 4) == NULL);
|
|
|
d7027e |
+
|
|
|
d7027e |
+ for (i = 0; i < sizeof(zeros); i++) {
|
|
|
d7027e |
+ st = k5_hashtab_add(ht, zeros, i, zeros + i);
|
|
|
d7027e |
+ assert(st == 0 && ht->nentries == i + 1 && ht->nbuckets >= i + 1);
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+ for (i = 0; i < sizeof(zeros); i++) {
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, zeros, i) == zeros + i);
|
|
|
d7027e |
+ k5_hashtab_remove(ht, zeros, i);
|
|
|
d7027e |
+ assert(ht->nentries == sizeof(zeros) - i - 1);
|
|
|
d7027e |
+ if (i > 0)
|
|
|
d7027e |
+ assert(k5_hashtab_get(ht, zeros, i - 1) == NULL);
|
|
|
d7027e |
+ }
|
|
|
d7027e |
+
|
|
|
d7027e |
+ k5_hashtab_free(ht);
|
|
|
d7027e |
+}
|
|
|
d7027e |
+
|
|
|
d7027e |
+int
|
|
|
d7027e |
+main()
|
|
|
d7027e |
+{
|
|
|
d7027e |
+ test_siphash();
|
|
|
d7027e |
+ test_hashtab();
|
|
|
d7027e |
+ return 0;
|
|
|
d7027e |
+}
|