diff --git a/libi2pd/IdentMetrics.cpp b/libi2pd/IdentMetrics.cpp new file mode 100644 index 00000000..19fabda4 --- /dev/null +++ b/libi2pd/IdentMetrics.cpp @@ -0,0 +1,93 @@ +/* +* Copyright (c) 2026, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include "Siphash.h" +#include "util.h" +#include "Timestamp.h" +#include "IdentMetrics.h" + +namespace i2p +{ +namespace data +{ + IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay) + { + uint8_t buf[41]; // ident + yyyymmdd + memcpy (buf, (const uint8_t *)ident, 32); + if (nextDay) + i2p::util::GetNextDayDate ((char *)(buf + 32)); + else + i2p::util::GetCurrentDate ((char *)(buf + 32)); + IdentHash key; + SHA256(buf, 40, key); + return key; + } + + XORMetric operator^(const IdentHash& key1, const IdentHash& key2) + { + XORMetric m; + + const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL (); + m.metric_ll[0] = hash1[0] ^ hash2[0]; + m.metric_ll[1] = hash1[1] ^ hash2[1]; + m.metric_ll[2] = hash1[2] ^ hash2[2]; + m.metric_ll[3] = hash1[3] ^ hash2[3]; + + return m; + } + + PeerOrdering::PeerOrdering () + { + RAND_bytes (m_PeerOrderingKey, 16); + } + + int PeerOrdering::CalculatePeerOrderingGroup (const IdentHash& routerIdent) + { + uint8_t hash[16]; +#if OPENSSL_SIPHASH + EVP_PKEY * sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, m_PeerOrderingKey, 16); + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestSignInit (ctx, nullptr, nullptr, nullptr, sipKey); + size_t l = 16; + EVP_DigestSign (ctx, hash, &l, routerIdent, 32); + EVP_MD_CTX_destroy (ctx); + EVP_PKEY_free (sipKey); +#else + i2p::crypto::Siphash<16> (hash, routerIdent, 32, m_PeerOrderingKey); +#endif + return hash[0] & 0x03; + } + + int PeerOrdering::GetPeerOrderingGroup (const IdentHash& routerIdent) + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + auto it = m_OrderingGroups.find (routerIdent); + if (it != m_OrderingGroups.end ()) + { + it->second.second = ts; + return it->second.first; + } + int group = CalculatePeerOrderingGroup (routerIdent); + m_OrderingGroups.emplace (routerIdent, std::pair{group, ts}); + return group; + } + + void PeerOrdering::CleanUp (uint64_t ts) + { + for (auto it = m_OrderingGroups.begin (); it != m_OrderingGroups.end ();) + { + if (ts > it->second.second + PEER_ORDERING_INACTIVITY_TIMEOUT) + it = m_OrderingGroups.erase (it); + else + it++; + } + } +} +} diff --git a/libi2pd/IdentMetrics.h b/libi2pd/IdentMetrics.h new file mode 100644 index 00000000..464896e8 --- /dev/null +++ b/libi2pd/IdentMetrics.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2026, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#ifndef IDENT_METRICS_H__ +#define IDENT_METRICS_H__ + +#include +#include +#include +#include "Tag.h" +#include "Identity.h" +#include "Crypto.h" + +namespace i2p +{ +namespace data +{ + // kademlia + struct XORMetric + { + union + { + uint8_t metric[32]; + uint64_t metric_ll[4]; + }; + + void SetMin () { memset (metric, 0, 32); }; + void SetMax () { memset (metric, 0xFF, 32); }; + bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; }; + }; + + IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay = false); + XORMetric operator^(const IdentHash& key1, const IdentHash& key2); + + // peer ordering + constexpr uint64_t PEER_ORDERING_INACTIVITY_TIMEOUT = 400; // in seconds + class PeerOrdering + { + public: + + PeerOrdering (); + int GetPeerOrderingGroup (const IdentHash& routerIdent); + void CleanUp (uint64_t ts); + + private: + + int CalculatePeerOrderingGroup (const IdentHash& routerIdent); + + private: + + Tag<16> m_PeerOrderingKey; + std::unordered_map > m_OrderingGroups; // router ident hash -> (group, last request time) + }; +} +} + +#endif diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index a82059a7..57b12e91 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -7,7 +7,6 @@ */ #include "Crypto.h" -#include "Siphash.h" #include "I2PEndian.h" #include "Log.h" #include "Timestamp.h" @@ -864,78 +863,5 @@ namespace data i2p::crypto::CreateDSARandomKeys (keys.signingPrivateKey, keys.signingKey); return keys; } - - IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay) - { - uint8_t buf[41]; // ident + yyyymmdd - memcpy (buf, (const uint8_t *)ident, 32); - if (nextDay) - i2p::util::GetNextDayDate ((char *)(buf + 32)); - else - i2p::util::GetCurrentDate ((char *)(buf + 32)); - IdentHash key; - SHA256(buf, 40, key); - return key; - } - - XORMetric operator^(const IdentHash& key1, const IdentHash& key2) - { - XORMetric m; - - const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL (); - m.metric_ll[0] = hash1[0] ^ hash2[0]; - m.metric_ll[1] = hash1[1] ^ hash2[1]; - m.metric_ll[2] = hash1[2] ^ hash2[2]; - m.metric_ll[3] = hash1[3] ^ hash2[3]; - - return m; - } - - PeerOrdering::PeerOrdering () - { - RAND_bytes (m_PeerOrderingKey, 16); - } - - int PeerOrdering::CalculatePeerOrderingGroup (const IdentHash& routerIdent) - { - uint8_t hash[16]; -#if OPENSSL_SIPHASH - EVP_PKEY * sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, m_PeerOrderingKey, 16); - EVP_MD_CTX * ctx = EVP_MD_CTX_create (); - EVP_DigestSignInit (ctx, nullptr, nullptr, nullptr, sipKey); - size_t l = 16; - EVP_DigestSign (ctx, hash, &l, routerIdent, 32); - EVP_MD_CTX_destroy (ctx); - EVP_PKEY_free (sipKey); -#else - i2p::crypto::Siphash<16> (hash, routerIdent, 32, m_PeerOrderingKey); -#endif - return hash[0] & 0x03; - } - - int PeerOrdering::GetPeerOrderingGroup (const IdentHash& routerIdent) - { - auto ts = i2p::util::GetSecondsSinceEpoch (); - auto it = m_OrderingGroups.find (routerIdent); - if (it != m_OrderingGroups.end ()) - { - it->second.second = ts; - return it->second.first; - } - int group = CalculatePeerOrderingGroup (routerIdent); - m_OrderingGroups.emplace (routerIdent, std::pair{group, ts}); - return group; - } - - void PeerOrdering::CleanUp (uint64_t ts) - { - for (auto it = m_OrderingGroups.begin (); it != m_OrderingGroups.end ();) - { - if (ts > it->second.second + PEER_ORDERING_INACTIVITY_TIMEOUT) - it = m_OrderingGroups.erase (it); - else - it++; - } - } } } diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 87c493d7..f4445807 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -15,7 +15,6 @@ #include #include #include -#include #include "Base.h" #include "Signature.h" #include "Tag.h" @@ -210,43 +209,6 @@ namespace data size_t m_TransientSigningPrivateKeyLen = 0; }; - // kademlia - struct XORMetric - { - union - { - uint8_t metric[32]; - uint64_t metric_ll[4]; - }; - - void SetMin () { memset (metric, 0, 32); }; - void SetMax () { memset (metric, 0xFF, 32); }; - bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; }; - }; - - IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay = false); - XORMetric operator^(const IdentHash& key1, const IdentHash& key2); - - // peer ordering - constexpr uint64_t PEER_ORDERING_INACTIVITY_TIMEOUT = 400; // in seconds - class PeerOrdering - { - public: - - PeerOrdering (); - int GetPeerOrderingGroup (const IdentHash& routerIdent); - void CleanUp (uint64_t ts); - - private: - - int CalculatePeerOrderingGroup (const IdentHash& routerIdent); - - private: - - Tag<16> m_PeerOrderingKey; - std::unordered_map > m_OrderingGroups; // router ident hash -> (group, last request time) - }; - // destination for delivery instructions class RoutingDestination { diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 55639530..f1651be2 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -27,6 +27,7 @@ #include "ECIESX25519AEADRatchetSession.h" #include "Config.h" #include "util.h" +#include "IdentMetrics.h" #include "NetDb.hpp" using namespace i2p::transport; diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 5329d0f4..4069c41d 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -29,6 +29,7 @@ #include "RouterInfo.h" #include "I2NPProtocol.h" #include "Identity.h" +#include "IdentMetrics.h" #include "util.h" namespace i2p diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index 029c2fa5..773ca760 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -17,6 +17,7 @@ #include #include #include "Identity.h" +#include "IdentMetrics.h" #include "LeaseSet.h" #include "RouterInfo.h" #include "I2NPProtocol.h"