/** * This code is licensed under the MCGSI Public License * Copyright 2018 Jeff Becker * * Kovri go write your own code * */ #ifndef SIPHASH_H #define SIPHASH_H #include #include "Crypto.h" #if !OPENSSL_SIPHASH namespace i2p { namespace crypto { namespace siphash { constexpr int crounds = 2; constexpr int drounds = 4; inline uint64_t rotl(const uint64_t & x, int b) { uint64_t ret = x << b; ret |= x >> (64 - b); return ret; } inline void u32to8le(const uint32_t & v, uint8_t * p) { p[0] = (uint8_t) v; p[1] = (uint8_t) (v >> 8); p[2] = (uint8_t) (v >> 16); p[3] = (uint8_t) (v >> 24); } inline void u64to8le(const uint64_t & v, uint8_t * p) { p[0] = v & 0xff; p[1] = (v >> 8) & 0xff; p[2] = (v >> 16) & 0xff; p[3] = (v >> 24) & 0xff; p[4] = (v >> 32) & 0xff; p[5] = (v >> 40) & 0xff; p[6] = (v >> 48) & 0xff; p[7] = (v >> 56) & 0xff; } inline uint64_t u8to64le(const uint8_t * p) { uint64_t i = 0; int idx = 0; while(idx < 8) { i |= ((uint64_t) p[idx]) << (idx * 8); ++idx; } return i; } inline void round(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); } } /** hashsz must be 8 or 16 */ template inline void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key) { uint64_t v0 = 0x736f6d6570736575ULL; uint64_t v1 = 0x646f72616e646f6dULL; uint64_t v2 = 0x6c7967656e657261ULL; uint64_t v3 = 0x7465646279746573ULL; const uint64_t k0 = siphash::u8to64le(key); const uint64_t k1 = siphash::u8to64le(key + 8); uint64_t msg; int i; const uint8_t * end = buf + bufsz - (bufsz % sizeof(uint64_t)); auto left = bufsz & 7; uint64_t b = ((uint64_t)bufsz) << 56; v3 ^= k1; v2 ^= k0; v1 ^= k1; v0 ^= k0; if(hashsz == 16) v1 ^= 0xee; while(buf != end) { msg = siphash::u8to64le(buf); v3 ^= msg; for(i = 0; i < siphash::crounds; ++i) siphash::round(v0, v1, v2, v3); v0 ^= msg; buf += 8; } while(left) { --left; b |= ((uint64_t)(buf[left])) << (left * 8); } v3 ^= b; for(i = 0; i < siphash::crounds; ++i) siphash::round(v0, v1, v2, v3); v0 ^= b; if(hashsz == 16) v2 ^= 0xee; else v2 ^= 0xff; for(i = 0; i < siphash::drounds; ++i) siphash::round(v0, v1, v2, v3); b = v0 ^ v1 ^ v2 ^ v3; siphash::u64to8le(b, h); if(hashsz == 8) return; v1 ^= 0xdd; for (i = 0; i < siphash::drounds; ++i) siphash::round(v0, v1, v2, v3); b = v0 ^ v1 ^ v2 ^ v3; siphash::u64to8le(b, h + 8); } } } #endif #endif