28#include <netinet/in.h>
31typedef uint16_t in_port_t;
36typedef uint16_t sa_family_t;
37typedef uint16_t in_port_t;
57 OPENDHT_PUBLIC
void hash(
const uint8_t* data,
size_t data_length, uint8_t*
hash,
size_t hash_length);
66class OPENDHT_PUBLIC Hash {
68 using T = std::array<uint8_t, N>;
69 typedef typename T::iterator iterator;
70 typedef typename T::const_iterator const_iterator;
75 Hash(
const uint8_t* h,
size_t data_len) {
79 std::copy_n(h, N, data_.begin());
86 explicit Hash(std::string_view hex) {
90 fromString(hex.data());
93 Hash(
const msgpack::object& o) {
97 static constexpr size_t size() noexcept {
return N; }
98 const uint8_t* data()
const {
return data_.data(); }
99 uint8_t* data() {
return data_.data(); }
100 iterator begin() {
return data_.begin(); }
101 const_iterator cbegin()
const {
return data_.cbegin(); }
102 iterator end() {
return data_.end(); }
103 const_iterator cend()
const {
return data_.cend(); }
105 static constexpr inline Hash zero() noexcept {
return Hash{}; }
107 bool operator==(
const Hash& h)
const {
108 return data_ == h.data_;
110 bool operator!=(
const Hash& h)
const {
return !(*
this == h); }
112 bool operator<(
const Hash& o)
const {
113 for(
unsigned i = 0; i < N; i++) {
114 if(data_[i] != o.data_[i])
115 return data_[i] < o.data_[i];
120 Hash operator^(
const Hash& o)
const {
122 for(
auto i = 0u; i < N; i++) {
123 result[i] = data_[i] ^ o.data_[i];
128 explicit operator bool()
const {
129 auto a =
reinterpret_cast<const uint32_t*
>(data_.data());
130 auto b =
reinterpret_cast<const uint32_t*
>(data_.data() + N);
131 for (; a != b; a++) {
138 uint8_t& operator[](
size_t index) {
return data_[index]; }
139 const uint8_t& operator[](
size_t index)
const {
return data_[index]; }
147 for(i = N-1; i >= 0; i--)
152 for(j = 7; j >= 0; j--)
153 if((data_[i] & (0x80 >> j)) != 0)
158 static inline int cmp(
const Hash& id1,
const Hash& id2) {
159 return std::memcmp(id1.data_.data(), id2.data_.data(), N);
163 static inline unsigned
168 for(i = 0; i < N; i++) {
169 if(id1.data_[i] != id2.data_[i])
176 x = id1.data_[i] ^ id2.data_[i];
179 while((x & 0x80) == 0) {
189 xorCmp(
const Hash& id1,
const Hash& id2)
const
191 for (
unsigned i = 0; i < N; i++) {
192 if(id1.data_[i] == id2.data_[i])
194 uint8_t xor1 = id1.data_[i] ^ data_[i];
195 uint8_t xor2 = id2.data_[i] ^ data_[i];
196 return (xor1 < xor2) ? -1 : 1;
202 getBit(
unsigned nbit)
const
204 auto& num = *(data_.cbegin()+(nbit/8));
205 unsigned bit = 7 - (nbit % 8);
206 return (num >> bit) & 1;
210 setBit(
unsigned nbit,
bool b)
212 auto& num = data_[nbit/8];
213 unsigned bit = 7 - (nbit % 8);
214 num ^= (-b ^ num) & (1 << bit);
217 double toFloat()
const {
220 for (
size_t i = 0; i < std::min<size_t>(N,
sizeof(D)-1); i++)
221 v += *(data_.cbegin()+i) / (double)((D)1 << 8*(i+1));
225 static inline Hash get(std::string_view data) {
226 return get((
const uint8_t*)data.data(), data.size());
229 static inline Hash get(
const std::vector<uint8_t>& data) {
230 return get(data.data(), data.size());
234 static Hash get(
const Hash<H>& o) {
235 return get(o.data(), o.size());
241 static Hash
get(
const uint8_t* data,
size_t data_len)
248 static Hash getRandom();
250 template <
typename Rd>
251 static Hash getRandom(Rd&);
254 OPENDHT_PUBLIC
friend std::ostream& operator<< (std::ostream& s,
const Hash<M>& h);
257 OPENDHT_PUBLIC
friend std::istream& operator>> (std::istream& s,
Hash<M>& h);
260 std::string_view
to_view()
const {
return std::string_view(to_c_str(), N*2); }
261 const char* to_c_str()
const;
263 std::string toString()
const;
265 template <
typename Packer>
266 void msgpack_pack(Packer& pk)
const
269 pk.pack_bin_body((
char*)data_.data(), N);
272 void msgpack_unpack(msgpack::object o) {
273 if (o.type != msgpack::type::BIN or o.via.bin.size != N)
274 throw msgpack::type_error();
275 std::copy_n(o.via.bin.ptr, N, data_.data());
279 void fromString(
const char*);
288std::ostream& operator<< (std::ostream& s,
const Hash<N>& h)
290 s.write(h.to_c_str(), N*2);
295std::istream& operator>> (std::istream& s,
Hash<N>& h)
297 std::array<char, h.size()*2> dat;
298 s.exceptions(std::istream::eofbit | std::istream::failbit);
299 s.read(&(*dat.begin()), dat.size());
300 fromString(dat.data());
306Hash<N>::fromString(
const char* in) {
307 auto hex2bin = [](
char c) -> uint8_t {
308 if (c >=
'a' and c <=
'f')
return 10 + c -
'a';
309 else if (c >=
'A' and c <=
'F')
return 10 + c -
'A';
310 else if (c >=
'0' and c <=
'9')
return c -
'0';
311 else throw std::domain_error(
"not an hex character");
314 for (
size_t i=0; i<N; i++)
315 data_[i] = (hex2bin(in[2*i]) << 4) | hex2bin(in[2*i+1]);
316 }
catch (
const std::domain_error&) {
326 std::random_device rdev;
327 std::uniform_int_distribution<uint32_t> rand_int;
328 auto a =
reinterpret_cast<uint32_t*
>(h.data());
329 auto b =
reinterpret_cast<uint32_t*
>(h.data() + h.size());
330 std::generate(a, b, std::bind(rand_int, std::ref(rdev)));
335template <
typename Rd>
337Hash<N>::getRandom(Rd& rdev)
340 std::uniform_int_distribution<uint32_t> rand_int;
341 auto a =
reinterpret_cast<uint32_t*
>(h.data());
342 auto b =
reinterpret_cast<uint32_t*
>(h.data() + h.size());
343 std::generate(a, b, std::bind(rand_int, std::ref(rdev)));
347struct alignas(std::max_align_t) HexMap :
public std::array<std::array<char, 2>, 256> {
349 for (
size_t i=0; i<size(); i++) {
350 auto& e = (*this)[i];
351 e[0] = hex_digits[(i >> 4) & 0x0F];
352 e[1] = hex_digits[i & 0x0F];
356 static constexpr const char* hex_digits =
"0123456789abcdef";
359OPENDHT_PUBLIC
extern const HexMap hex_map;
362toHex(
const uint8_t* data,
size_t size) {
363 std::string ret(size * 2,
'\0');
364 for (
size_t i=0; i<size; i++) {
365 auto b = ret.data()+i*2;
366 const auto& m = hex_map[data[i]];
367 *((uint16_t*)b) = *((uint16_t*)&m);
373toHex(
const std::vector<uint8_t>& data) {
374 return toHex(data.data(), data.size());
379Hash<N>::to_c_str()
const
381 alignas(std::max_align_t)
thread_local std::array<char, N*2+1> buf;
382 for (
size_t i=0; i<N; i++) {
383 auto b = buf.data()+i*2;
384 const auto& m = hex_map[data_[i]];
385 *((uint16_t*)b) = *((uint16_t*)&m);
392Hash<N>::toString()
const
394 return std::string(to_c_str(), N*2);
400struct fmt::formatter<
dht::Hash<N>>: formatter<string_view> {
401 constexpr auto format(
const dht::Hash<N>& c, format_context& ctx)
const {
402 return formatter<string_view>::format(c.
to_view(), ctx);
static unsigned commonBits(const Hash &id1, const Hash &id2)
Hash(std::string_view hex)
static Hash get(const uint8_t *data, size_t data_len)
std::string_view to_view() const
int xorCmp(const Hash &id1, const Hash &id2) const
OPENDHT_PUBLIC Blob hash(const Blob &data, size_t hash_length=512/8)