diff --git a/c/opendht.cpp b/c/opendht.cpp
index 7ba15ea9c310953e9aa2b8ce41f40730d26a6628..d1fe081176b397011cb28476a9d984c340421550 100644
--- a/c/opendht.cpp
+++ b/c/opendht.cpp
@@ -261,7 +261,7 @@ dht_pkid dht_certificate_get_long_id(const dht_certificate* c) {
 
 dht_publickey* dht_certificate_get_publickey(const dht_certificate* c) {
     const auto& cert = *reinterpret_cast<const CertSp*>(c);
-    return reinterpret_cast<dht_publickey*>(new PubkeySp(std::make_shared<dht::crypto::PublicKey>(cert->getPublicKey())));
+    return reinterpret_cast<dht_publickey*>(new PubkeySp(cert->getSharedPublicKey()));
 }
 
 // dht::crypto::Identity
diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h
index f26a65f2af8271c356e46041181937db2233e2af..84d5df0e9f62ff5c9f4247470d9c532923041b75 100644
--- a/include/opendht/crypto.h
+++ b/include/opendht/crypto.h
@@ -390,7 +390,11 @@ struct OPENDHT_PUBLIC Certificate {
      */
     Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
 
-    Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
+    Certificate(Certificate&& o) noexcept
+        : cert(o.cert)
+        , issuer(std::move(o.issuer))
+        , publicKey_(std::move(o.publicKey_))
+        { o.cert = nullptr; };
 
     /**
      * Import certificate (PEM or DER) or certificate chain (PEM),
@@ -498,7 +502,8 @@ struct OPENDHT_PUBLIC Certificate {
     void msgpack_unpack(const msgpack::object& o);
 
     explicit operator bool() const { return cert; }
-    PublicKey getPublicKey() const;
+    const PublicKey& getPublicKey() const;
+    const std::shared_ptr<PublicKey>& getSharedPublicKey() const;
 
     /** Same as getPublicKey().getId() */
     const InfoHash& getId() const;
@@ -631,6 +636,9 @@ private:
     };
 
     std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists;
+
+    mutable std::mutex publicKeyMutex_ {};
+    mutable std::shared_ptr<PublicKey> publicKey_ {};
 };
 
 struct OPENDHT_PUBLIC TrustList
diff --git a/src/crypto.cpp b/src/crypto.cpp
index dba347320eb7fe16f0a19a0151913bfadf82693d..ff997d64688fa3b6d2fa8be91801c3bfe4f370b3 100644
--- a/src/crypto.cpp
+++ b/src/crypto.cpp
@@ -366,7 +366,7 @@ PrivateKey::getSharedPublicKey() const
         auto pk = std::make_shared<PublicKey>();
         if (auto err = gnutls_pubkey_import_privkey(pk->pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
             throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
-        publicKey_ = pk;
+        publicKey_ = std::move(pk);
     }
     return publicKey_;
 }
@@ -824,13 +824,23 @@ Certificate::~Certificate()
     }
 }
 
-PublicKey
+const PublicKey&
 Certificate::getPublicKey() const
 {
-    PublicKey pk_ret;
-    if (auto err = gnutls_pubkey_import_x509(pk_ret.pk, cert, 0))
-        throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
-    return pk_ret;
+    return *getSharedPublicKey();
+}
+
+const std::shared_ptr<PublicKey>&
+Certificate::getSharedPublicKey() const
+{
+    std::lock_guard<std::mutex> lock(publicKeyMutex_);
+    if (not publicKey_) {
+        auto pk = std::make_shared<PublicKey>();
+        if (auto err = gnutls_pubkey_import_x509(pk->pk, cert, 0))
+            throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
+        publicKey_ = std::move(pk);
+    }
+    return publicKey_;
 }
 
 const InfoHash&
diff --git a/src/securedht.cpp b/src/securedht.cpp
index 55a7bd8a0aeabd3202e4c12164f3b4c97e2794c7..ae1dc0f517e2a1dcc8b4bfeeb3198887395f541a 100644
--- a/src/securedht.cpp
+++ b/src/securedht.cpp
@@ -121,7 +121,7 @@ Sp<crypto::PublicKey>
 SecureDht::getPublicKey(const InfoHash& node) const
 {
     if (node == getId())
-        return std::make_shared<crypto::PublicKey>(certificate_->getPublicKey());
+        return certificate_->getSharedPublicKey();
     auto it = nodesPubKeys_.find(node);
     if (it == nodesPubKeys_.end())
         return nullptr;
@@ -217,7 +217,7 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
     }
     findCertificate(node, [=](const Sp<crypto::Certificate>& crt) {
         if (crt && *crt) {
-            auto pk = std::make_shared<crypto::PublicKey>(crt->getPublicKey());
+            auto pk = crt->getSharedPublicKey();
             if (*pk) {
                 nodesPubKeys_[pk->getId()] = pk;
                 if (cb) cb(pk);