mirror of https://github.com/PurpleI2P/i2pd.git
I2P: End-to-End encrypted and anonymous Internet
https://i2pd.website/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
3.9 KiB
152 lines
3.9 KiB
/** |
|
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 <cstdint> |
|
|
|
namespace i2p |
|
{ |
|
namespace crypto |
|
{ |
|
namespace siphash |
|
{ |
|
constexpr int crounds = 2; |
|
constexpr int drounds = 4; |
|
|
|
uint64_t rotl(const uint64_t & x, int b) |
|
{ |
|
uint64_t ret = x << b; |
|
ret |= x >> (64 - b); |
|
return ret; |
|
} |
|
|
|
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); |
|
} |
|
|
|
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; |
|
} |
|
|
|
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; |
|
} |
|
|
|
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<std::size_t hashsz> |
|
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 |