diff --git a/include/opendht/default_types.h b/include/opendht/default_types.h
index a3e8ce4cbf13cf0cecf7904a61bf8d162dd1cfcc..ea0f6a155c641218f0167612beab7dd5b3242ff6 100644
--- a/include/opendht/default_types.h
+++ b/include/opendht/default_types.h
@@ -66,7 +66,8 @@ private:
 
 public:
     virtual void unpackValue(const Value& v) override {
-        from = v.owner.getId();
+        if (v.owner)
+            from = v.owner->getId();
         BaseClass::unpackValue(v);
     }
 
diff --git a/include/opendht/value.h b/include/opendht/value.h
index a3f34dc54e5d0d7d35562d4e69b8201781c36015..fa903a05196a284401606637d5927d250808cd49 100644
--- a/include/opendht/value.h
+++ b/include/opendht/value.h
@@ -255,7 +255,7 @@ struct Value
         return not cypher.empty();
     }
     bool isSigned() const {
-        return not signature.empty();
+        return owner and not signature.empty();
     }
 
     Value() {}
@@ -301,7 +301,7 @@ struct Value
     inline bool operator== (const Value& o) {
         return id == o.id &&
         (isEncrypted() ? cypher == o.cypher :
-        (owner == o.owner && type == o.type && data == o.data && user_type == o.user_type && signature == o.signature));
+        ((owner == o.owner || *owner == *o.owner) && type == o.type && data == o.data && user_type == o.user_type && signature == o.signature));
     }
 
     void setRecipient(const InfoHash& r) {
@@ -347,10 +347,11 @@ struct Value
     template <typename Packer>
     void msgpack_pack_to_sign(Packer& pk) const
     {
-        pk.pack_map((user_type.empty()?0:1) + (owner?(recipient == InfoHash() ? 4 : 5):2));
-        if (owner) { // isSigned
+        bool has_owner = owner && *owner;
+        pk.pack_map((user_type.empty()?0:1) + (has_owner?(recipient == InfoHash() ? 4 : 5):2));
+        if (has_owner) { // isSigned
             pk.pack(std::string("seq"));   pk.pack(seq);
-            pk.pack(std::string("owner")); owner.msgpack_pack(pk);
+            pk.pack(std::string("owner")); owner->msgpack_pack(pk);
             if (recipient != InfoHash()) {
                 pk.pack(std::string("to")); pk.pack(recipient);
             }
@@ -395,7 +396,7 @@ struct Value
     /**
      * Public key of the signer.
      */
-    crypto::PublicKey owner {};
+    std::shared_ptr<crypto::PublicKey> owner {};
 
     /**
      * Hash of the recipient (optional).
diff --git a/src/securedht.cpp b/src/securedht.cpp
index 39b343c2369f68c12ccfb5a451c1725f2ed57c72..9ace496b6c2199f19b46cf686c10a3d67b088546 100644
--- a/src/securedht.cpp
+++ b/src/securedht.cpp
@@ -94,7 +94,7 @@ SecureDht::secureType(ValueType&& type)
 {
     type.storePolicy = [this,type](InfoHash id, std::shared_ptr<Value>& v, InfoHash nid, const sockaddr* a, socklen_t al) {
         if (v->isSigned()) {
-            if (!v->owner.checkSignature(v->getToSign(), v->signature)) {
+            if (!v->owner or !v->owner->checkSignature(v->getToSign(), v->signature)) {
                 DHT_LOG.WARN("Signature verification failed");
                 return false;
             }
@@ -110,7 +110,7 @@ SecureDht::secureType(ValueType&& type)
             DHT_LOG.WARN("Edition forbidden: owner changed.");
             return false;
         }
-        if (!o->owner.checkSignature(n->getToSign(), n->signature)) {
+        if (!o->owner or !o->owner->checkSignature(n->getToSign(), n->signature)) {
             DHT_LOG.WARN("Edition forbidden: signature verification failed.");
             return false;
         }
@@ -152,7 +152,7 @@ SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
     }
     InfoHash h = crt->getPublicKey().getId();
     if (node == h) {
-        DHT_LOG.DEBUG("Registering public key for %s", h.toString().c_str());
+        DHT_LOG.DEBUG("Registering certificate for %s", h.toString().c_str());
         auto it = nodesCertificates_.find(h);
         if (it == nodesCertificates_.end())
             std::tie(it, std::ignore) = nodesCertificates_.emplace(h, std::move(crt));
@@ -177,7 +177,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const std::s
 {
     std::shared_ptr<crypto::Certificate> b = getCertificate(node);
     if (b && *b) {
-        DHT_LOG.DEBUG("Using public key from cache for %s", node.toString().c_str());
+        DHT_LOG.DEBUG("Using certificate from cache for %s", node.toString().c_str());
         if (cb)
             cb(b);
         return;
@@ -185,7 +185,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const std::s
     if (localQueryMethod_) {
         auto res = localQueryMethod_(node);
         if (not res.empty()) {
-            DHT_LOG.DEBUG("Registering public key from local store for %s", node.toString().c_str());
+            DHT_LOG.DEBUG("Registering certificate from local store for %s", node.toString().c_str());
             nodesCertificates_.emplace(node, res.front());
             if (cb)
                 cb(res.front());
@@ -200,7 +200,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const std::s
         for (const auto& v : vals) {
             if (auto cert = registerCertificate(node, v->data)) {
                 *found = true;
-                DHT_LOG.DEBUG("Found public key for %s", node.toString().c_str());
+                DHT_LOG.DEBUG("Found certificate for %s", node.toString().c_str());
                 if (cb)
                     cb(cert);
                 return false;
@@ -237,7 +237,7 @@ SecureDht::getCallbackFilter(GetCallback cb, Value::Filter&& filter)
             }
             // Check signed values
             else if (v->isSigned()) {
-                if (v->owner.checkSignature(v->getToSign(), v->signature)) {
+                if (v->owner and v->owner->checkSignature(v->getToSign(), v->signature)) {
                     if (not filter  or filter(*v))
                         tmpvals.push_back(v);
                 }
@@ -290,7 +290,7 @@ SecureDht::putSigned(const InfoHash& hash, std::shared_ptr<Value> val, DoneCallb
             for (const auto& v : vals) {
                 if (!v->isSigned())
                     DHT_LOG.ERROR("Existing non-signed value seems to exists at this location.");
-                else if (v->owner.getId() != getId())
+                else if (not v->owner or v->owner->getId() != getId())
                     DHT_LOG.ERROR("Existing signed value belonging to someone else seems to exists at this location.");
                 else if (val->seq <= v->seq)
                     val->seq = v->seq + 1;
@@ -330,7 +330,7 @@ SecureDht::sign(Value& v) const
 {
     if (v.isEncrypted())
         throw DhtException("Can't sign encrypted data.");
-    v.owner = key_->getPublicKey();
+    v.owner = std::make_shared<crypto::PublicKey>(key_->getPublicKey());
     v.signature = key_->sign(v.getToSign());
 }
 
@@ -360,7 +360,7 @@ SecureDht::decrypt(const Value& v)
 
     if (ret.recipient != getId())
         throw crypto::DecryptError("Recipient mismatch");
-    if (not ret.owner.checkSignature(ret.getToSign(), ret.signature))
+    if (not ret.owner or not ret.owner->checkSignature(ret.getToSign(), ret.signature))
         throw crypto::DecryptError("Signature mismatch");
 
     return ret;
diff --git a/src/value.cpp b/src/value.cpp
index 6431678a06cf90dcde76443090857a43131df249..a2c4d1e6e12c48910b533a2a981d726c6681e972 100644
--- a/src/value.cpp
+++ b/src/value.cpp
@@ -142,7 +142,8 @@ Value::msgpack_unpack_body(const msgpack::object& o)
                 seq = rseq->as<decltype(seq)>();
             else
                 throw msgpack::type_error();
-            owner.msgpack_unpack(*rowner);
+            owner = std::make_shared<crypto::PublicKey>();
+            owner->msgpack_unpack(*rowner);
             if (auto rrecipient = findMapValue(*rbody, "to")) {
                 recipient = rrecipient->as<InfoHash>();
             }