Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_library(siphash_hpp INTERFACE)
target_include_directories(siphash_hpp INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/siphash-hpp>
$<INSTALL_INTERFACE:include/siphash-hpp>)
target_compile_features(siphash_hpp INTERFACE cxx_std_11)

include(CMakePackageConfigHelpers)

Expand Down
168 changes: 150 additions & 18 deletions include/siphash-hpp/siphash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <array>
#include <cassert>
#include <cstdint>
#include <cstddef>
#include <string>
#include <tuple>
#include <type_traits>
Expand Down Expand Up @@ -54,14 +55,28 @@ namespace siphash_hpp {

template<typename T>
struct runtime_size_checker<T, true> {
static void check(const T &key) {
static void check(const T &key, size_t = 0) {
assert(key.size() >= 16 && "SipHash key must be at least 16 bytes");
}
};

template<typename T>
struct runtime_size_checker<T, false> {
static void check(const T &) {}
static void check(const T &, size_t = 0) {}
};

template<>
struct runtime_size_checker<const uint8_t*, false> {
static void check(const uint8_t *, size_t length) {
assert(length >= 16 && "SipHash key must be at least 16 bytes");
}
};

template<>
struct runtime_size_checker<const char*, false> {
static void check(const char *, size_t length) {
assert(length >= 16 && "SipHash key must be at least 16 bytes");
}
};

class SipHash {
Expand Down Expand Up @@ -126,11 +141,27 @@ namespace siphash_hpp {
* \param c Number of rounds per message block
* \param d Number of finalization rounds
*/
template<class T>
template<class T, typename std::enable_if<!std::is_pointer<T>::value, int>::type = 0>
SipHash(const T &key, const size_t c = 2, const size_t d = 4) {
init(key, c, d);
};

SipHash(const char *key, size_t length) {
init(key, length, 2, 4);
};

SipHash(const char *key, size_t length, const size_t c, const size_t d) {
init(key, length, c, d);
};

SipHash(const uint8_t *key, size_t length) {
init(key, length, 2, 4);
};

SipHash(const uint8_t *key, size_t length, const size_t c, const size_t d) {
init(key, length, c, d);
};

~SipHash() {};

/** \brief Initialize SipHash
Expand All @@ -141,7 +172,7 @@ namespace siphash_hpp {
* \param c Number of rounds per message block
* \param d Number of finalization rounds
*/
template<class T>
template<class T, typename std::enable_if<!std::is_pointer<T>::value, int>::type = 0>
inline void init(
const T &key,
const size_t c = 2,
Expand All @@ -153,7 +184,7 @@ namespace siphash_hpp {
"SipHash key must be at least 16 bytes");

static_size_checker<T>::check();
runtime_size_checker<T>::check(key);
runtime_size_checker<T>::check(key, 0);

const uint64_t k0 = read8(key);
const uint64_t k1 = read8(key, 8);
Expand All @@ -168,6 +199,49 @@ namespace siphash_hpp {
m = 0;
}

inline void init(
const char *key,
size_t length,
const size_t c,
const size_t d) noexcept {
this->c = c;
this->d = d;

runtime_size_checker<const char*>::check(key, length);

const uint64_t k0 = read8(key);
const uint64_t k1 = read8(key, 8);

v0 = (0x736f6d6570736575 ^ k0);
v1 = (0x646f72616e646f6d ^ k1);
v2 = (0x6c7967656e657261 ^ k0);
v3 = (0x7465646279746573 ^ k1);

index = 0;
input_len = 0;
m = 0;
}

inline void init(
const char *key,
size_t length) noexcept {
init(key, length, 2, 4);
}

inline void init(
const uint8_t *key,
size_t length,
const size_t c,
const size_t d) noexcept {
init(reinterpret_cast<const char*>(key), length, c, d);
}

inline void init(
const uint8_t *key,
size_t length) noexcept {
init(reinterpret_cast<const char*>(key), length, 2, 4);
}

SipHash& update(const char byte) noexcept {
++input_len;
m |= (((uint64_t) byte & 0xff) << (index++ * 8));
Expand Down Expand Up @@ -231,7 +305,7 @@ namespace siphash_hpp {
}
}; // SipHash

template<class T>
template<class T, typename std::enable_if<!std::is_pointer<T>::value, int>::type = 0>
const uint64_t siphash(
const std::string &data,
const T &key,
Expand All @@ -242,31 +316,89 @@ namespace siphash_hpp {
return h.digest();
}

template<class T>
const uint64_t siphash_2_4(
inline const uint64_t siphash(
const std::string &data,
const T &key) noexcept {
SipHash h(key, 2, 4);
const char *key,
size_t length,
const size_t c,
const size_t d) noexcept {
SipHash h(key, length, c, d);
h.update(data);
return h.digest();
}

template<class T>
const uint64_t siphash_4_8(
inline const uint64_t siphash(
const std::string &data,
const T &key) noexcept {
SipHash h(key, 4, 8);
const uint8_t *key,
size_t length,
const size_t c,
const size_t d) noexcept {
SipHash h(key, length, c, d);
h.update(data);
return h.digest();
}

template<class T>
template<class T, typename std::enable_if<!std::is_pointer<T>::value, int>::type = 0>
const uint64_t siphash_2_4(
const std::string &data,
const T &key) noexcept {
return siphash(data, key, 2, 4);
}

inline const uint64_t siphash_2_4(
const std::string &data,
const char *key,
size_t length) noexcept {
return siphash(data, key, length, 2, 4);
}

inline const uint64_t siphash_2_4(
const std::string &data,
const uint8_t *key,
size_t length) noexcept {
return siphash(data, key, length, 2, 4);
}

template<class T, typename std::enable_if<!std::is_pointer<T>::value, int>::type = 0>
const uint64_t siphash_4_8(
const std::string &data,
const T &key) noexcept {
return siphash(data, key, 4, 8);
}

inline const uint64_t siphash_4_8(
const std::string &data,
const char *key,
size_t length) noexcept {
return siphash(data, key, length, 4, 8);
}

inline const uint64_t siphash_4_8(
const std::string &data,
const uint8_t *key,
size_t length) noexcept {
return siphash(data, key, length, 4, 8);
}

template<class T, typename std::enable_if<!std::is_pointer<T>::value, int>::type = 0>
const uint64_t siphash_1_3(
const std::string &data,
const T &key) noexcept {
SipHash h(key, 1, 3);
h.update(data);
return h.digest();
return siphash(data, key, 1, 3);
}

inline const uint64_t siphash_1_3(
const std::string &data,
const char *key,
size_t length) noexcept {
return siphash(data, key, length, 1, 3);
}

inline const uint64_t siphash_1_3(
const std::string &data,
const uint8_t *key,
size_t length) noexcept {
return siphash(data, key, length, 1, 3);
}
};

Expand Down
18 changes: 18 additions & 0 deletions tests/siphash_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ TEST(SipHash, KnownValues) {
EXPECT_EQ(14986662229302055855ULL, siphash_hpp::siphash_4_8(data, key));
}

TEST(SipHash, PointerKey) {
const uint8_t key[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
std::string data = "hello";

siphash_hpp::SipHash h;
h.init(key, sizeof(key));
h.update(data);
EXPECT_EQ(4402678656023170274ULL, h.digest());
}

TEST(SipHash, EmptyMessageArrayKey) {
const char key[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
std::string data = "";

EXPECT_EQ(3627314469837380007ULL,
siphash_hpp::siphash_2_4(data, key, sizeof(key)));
}

TEST(SipHash, EmptyMessageArrayKey) {
char key[16];
for (int i = 0; i < 16; ++i) key[i] = static_cast<char>(i);
Expand Down
Loading