Use static array instead of unordered_map to keep memory contiguous

This commit is contained in:
Jason B. Cox 2025-05-13 10:39:49 -07:00
parent 657eb93c44
commit 66560fbcfa
3 changed files with 47 additions and 43 deletions

View File

@ -263,31 +263,30 @@ bool CryptoEngine::setCryptoSharedSecret(meshtastic_UserLite_public_key_t pubkey
uint32_t lookupKey; uint32_t lookupKey;
memcpy(&lookupKey, pubkey.bytes, sizeof(lookupKey)); memcpy(&lookupKey, pubkey.bytes, sizeof(lookupKey));
// See if we cached the secret already uint16_t oldestDelta = 0;
auto iter = sharedSecretCache.find(lookupKey); CachedSharedSecret &oldestEntry = sharedSecretCache[0];
if (iter != sharedSecretCache.end()) { for (size_t i = 0; i < MAX_CACHED_SHARED_SECRETS; i++) {
CachedSharedSecret &entry = sharedSecretCache[i];
if (entry.lookup_key == lookupKey) {
// Cache hit! Copy it into shared_key. // Cache hit! Copy it into shared_key.
CachedSharedSecret &entry = iter->second;
memcpy(shared_key, entry.shared_secret, 32); memcpy(shared_key, entry.shared_secret, 32);
// Update the last used timestamp // Update the last used timestamp
entry.last_used = now; entry.last_used = now;
return true; return true;
} }
// Cache miss. Generate the shared secret. if (oldestEntry.lookup_key == 0) {
if (!setDHPublicKey(pubkey.bytes)) { // We already have a valid slot to insert into. Keep looking for a cache hit.
return false; continue;
} }
hash(shared_key, 32);
// If the cache will grow too large, remove the oldest entry first if (entry.lookup_key == 0) {
if (sharedSecretCache.size() >= MAX_CACHED_SHARED_SECRETS) { // This entry is empty. We can insert into it later, if needed.
uint16_t oldestDelta = 0; oldestEntry = entry;
uint32_t oldestKey = sharedSecretCache.begin()->first; continue;
for (const auto &p : sharedSecretCache) { }
const uint32_t key = p.first;
const CachedSharedSecret &entry = p.second;
// Track the oldest entry in case the cache is full.
uint16_t delta = 0; uint16_t delta = 0;
if (now >= entry.last_used) { if (now >= entry.last_used) {
delta = now - entry.last_used; delta = now - entry.last_used;
@ -296,18 +295,21 @@ bool CryptoEngine::setCryptoSharedSecret(meshtastic_UserLite_public_key_t pubkey
delta = uint16_t(0x100) + now - entry.last_used; delta = uint16_t(0x100) + now - entry.last_used;
} }
if (delta > oldestDelta) { if (delta > oldestDelta) {
oldestKey = key; oldestEntry = entry;
oldestDelta = delta; oldestDelta = delta;
} }
} }
sharedSecretCache.erase(oldestKey);
}
// Now insert the calculated shared secret // Cache miss. Generate the shared secret.
CachedSharedSecret entry; if (!setDHPublicKey(pubkey.bytes)) {
entry.last_used = now; return false;
memcpy(entry.shared_secret, shared_key, 32); }
sharedSecretCache.insert({lookupKey, entry}); hash(shared_key, 32);
// Insert the calculated shared secret into the cache, overwriting an old entry if needed.
oldestEntry.lookup_key = lookupKey;
oldestEntry.last_used = now;
memcpy(oldestEntry.shared_secret, shared_key, 32);
return true; return true;
} }

View File

@ -17,6 +17,7 @@ struct CryptoKey {
}; };
struct CachedSharedSecret { struct CachedSharedSecret {
uint32_t lookup_key;
uint8_t shared_secret[32]; uint8_t shared_secret[32];
uint8_t last_used; uint8_t last_used;
}; };
@ -114,7 +115,7 @@ class CryptoEngine
/** /**
* Cache mapping peers' public keys -> {shared_secret, last_used} * Cache mapping peers' public keys -> {shared_secret, last_used}
*/ */
std::unordered_map<uint32_t, CachedSharedSecret> sharedSecretCache; CachedSharedSecret sharedSecretCache[MAX_CACHED_SHARED_SECRETS] = {0};
/** /**
* Set cryptographic (hashed) shared_key calculated from the given pubkey * Set cryptographic (hashed) shared_key calculated from the given pubkey

View File

@ -7,13 +7,14 @@
struct TestCryptoEngine { struct TestCryptoEngine {
static bool getCachedSecret(uint32_t lookupKey, CachedSharedSecret &entry) static bool getCachedSecret(uint32_t lookupKey, CachedSharedSecret &entry)
{ {
auto iter = crypto->sharedSecretCache.find(lookupKey); for (size_t i = 0; i < MAX_CACHED_SHARED_SECRETS; i++) {
if (iter == crypto->sharedSecretCache.end()) { entry = crypto->sharedSecretCache[i];
return false; if (entry.lookup_key == lookupKey) {
}
entry = iter->second;
return true; return true;
} }
}
return false;
}
}; };
void HexToBytes(uint8_t *result, const std::string hex, size_t len = 0) void HexToBytes(uint8_t *result, const std::string hex, size_t len = 0)