diff --git a/include/opendht/value.h b/include/opendht/value.h
index 63795caf702033cccfd3a10c991fcc18cdb5ecb1..a4a3348a1c0b019bcccecb465e5295f5c2c55280 100644
--- a/include/opendht/value.h
+++ b/include/opendht/value.h
@@ -122,6 +122,8 @@ private:
     std::map<ValueType::Id, ValueType> types {};
 };
 
+struct CryptoValueCache;
+
 /**
  * A "value" is data potentially stored on the Dht, with some metadata.
  *
@@ -588,6 +590,14 @@ struct OPENDHT_PUBLIC Value
      * Hold encrypted version of the data.
      */
     Blob cypher {};
+
+private:
+    friend class SecureDht;
+    /* Cache for crypto ops */
+    bool signatureChecked {false};
+    bool signatureValid {false};
+    bool decrypted {false};
+    Sp<Value> decryptedValue {};
 };
 
 using ValuesExport = std::pair<InfoHash, Blob>;
diff --git a/src/securedht.cpp b/src/securedht.cpp
index 4d173170e4e84b9c90817a894f0574fc64e7410f..a0d5a5a25da90e404eb1ac2ea1ac240dfbc36871 100644
--- a/src/securedht.cpp
+++ b/src/securedht.cpp
@@ -235,12 +235,17 @@ SecureDht::checkValue(const Sp<Value>& v)
 #endif
             return {};
         }
+        if (v->decrypted) {
+            return v->decryptedValue;
+        }
+        v->decrypted = true;
         try {
             Value decrypted_val (decrypt(*v));
             if (decrypted_val.recipient == getId()) {
                 if (decrypted_val.owner)
                     nodesPubKeys_[decrypted_val.owner->getId()] = decrypted_val.owner;
-                return std::make_shared<Value>(std::move(decrypted_val));
+                v->decryptedValue = std::make_shared<Value>(std::move(decrypted_val));
+                return v->decryptedValue;
             }
             // Ignore values belonging to other people
         } catch (const std::exception& e) {
@@ -249,7 +254,12 @@ SecureDht::checkValue(const Sp<Value>& v)
     }
     // Check signed values
     else if (v->isSigned()) {
+        if (v->signatureChecked) {
+            return v->signatureValid ? v : Sp<Value>{};
+        }
+        v->signatureChecked = true;
         if (v->owner and v->owner->checkSignature(v->getToSign(), v->signature)) {
+            v->signatureValid = true;
             nodesPubKeys_[v->owner->getId()] = v->owner;
             return v;
         }
@@ -355,7 +365,7 @@ SecureDht::putSigned(const InfoHash& hash, Sp<Value> val, DoneCallback callback,
 void
 SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val, DoneCallback callback, bool permanent)
 {
-    findPublicKey(to, [=](const Sp<const crypto::PublicKey> pk) {
+    findPublicKey(to, [=](const Sp<const crypto::PublicKey>& pk) {
         if(!pk || !*pk) {
             if (callback)
                 callback(false, {});