diff --git a/src/private_message.rs b/src/private_message.rs
index 1655c7aaa07fc95f06938cc1be0fb11ca0e05829..6161df9429a8937a4677697d8385c1268c5d5a75 100644
--- a/src/private_message.rs
+++ b/src/private_message.rs
@@ -83,7 +83,7 @@
 //!
 //! ```
 //! use dup_crypto::keys::{KeyPair, ed25519::KeyPairFromSeed32Generator};
-//! use dup_crypto::private_message::{Aad, Algorithm};
+//! use dup_crypto::private_message::{Aad, Algorithm, DecryptedMessage};
 //! use dup_crypto::seeds::Seed32;
 //!
 //! let receiver_key_pair = KeyPairFromSeed32Generator::generate(
@@ -103,17 +103,22 @@
 //! # 247, 151, 148, 197, 162, 88, 254, 185, 149, 108, 2, 137, 139, 66, 82, 168, 213, 118, 218, 188, 238,
 //! # 147, 89, 156];
 //!
-//! let (message, signature_opt) = dup_crypto::private_message::decrypt_private_message(
-//!     Aad::from(b"service name - currency name"),
-//!     Algorithm::Chacha20Poly1305,
-//!     &mut encrypted_message,
-//!     &receiver_key_pair,
+//! let DecryptedMessage { message, sender_public_key, signature_opt } =
+//!     dup_crypto::private_message::decrypt_private_message(
+//!         Aad::from(b"service name - currency name"),
+//!         Algorithm::Chacha20Poly1305,
+//!         &mut encrypted_message,
+//!         &receiver_key_pair,
 //! )?;
 //!
 //! assert_eq!(
 //!     message,
 //!     &b"This is a secret message, which can only be read by the recipient."[..],
 //! );
+//! assert_eq!{
+//!     "4HbjoXtWu9C2Q5LMu1RcWHS66k4dnvHspBxKWagFG5rJ",
+//!     &sender_public_key.to_string(),
+//! }
 //! assert_eq!(
 //!     signature_opt,
 //!     None
@@ -289,6 +294,16 @@ where
     Ok(())
 }
 
+/// Decrypted message
+pub struct DecryptedMessage<'m> {
+    /// decrypted message content
+    pub message: &'m [u8],
+    /// Sender public key
+    pub sender_public_key: Ed25519PublicKey,
+    /// Optional signature
+    pub signature_opt: Option<Signature>,
+}
+
 /// Decrypt private message.
 /// Return a reference to decrypted bytes and an optional signature.
 /// If the authentication method chosen by the sender is `Signature`,
@@ -299,7 +314,7 @@ pub fn decrypt_private_message<'m, A: AsRef<[u8]>>(
     algorithm: Algorithm,
     encrypted_message: &'m mut [u8],
     receiver_key_pair: &Ed25519KeyPair,
-) -> Result<(&'m [u8], Option<Signature>), PrivateMessageError> {
+) -> Result<DecryptedMessage<'m>, PrivateMessageError> {
     // Get ephemeral public key
     let len = encrypted_message.len();
     let ephemeral_public_key = &encrypted_message[(len - EPHEMERAL_PUBLIC_KEY_LEN)..];
@@ -326,13 +341,17 @@ pub fn decrypt_private_message<'m, A: AsRef<[u8]>>(
     let tag_len = algorithm.to_ring_algo().tag_len();
     let authent_end = len - EPHEMERAL_PUBLIC_KEY_LEN - tag_len;
     let authent_begin = authent_end - AUTHENTICATION_DATAS_LEN;
-    let sig_opt = verify_authentication_proof(
+    let (sender_public_key, sig_opt) = verify_authentication_proof(
         receiver_key_pair,
         &encrypted_message[..authent_begin],
         &encrypted_message[authent_begin..authent_end],
     )?;
 
-    Ok((&encrypted_message[..authent_begin], sig_opt))
+    Ok(DecryptedMessage {
+        message: &encrypted_message[..authent_begin],
+        sender_public_key,
+        signature_opt: sig_opt,
+    })
 }
 
 fn generate_symmetric_key_and_nonce(
@@ -483,7 +502,11 @@ mod tests {
 
         println!("encrypted message={:?}", encrypted_message);
 
-        let (decrypted_message, sig_opt) = decrypt_private_message(
+        let DecryptedMessage {
+            message: decrypted_message,
+            sender_public_key,
+            signature_opt,
+        } = decrypt_private_message(
             Aad::from(AAD),
             Algorithm::Chacha20Poly1305,
             &mut encrypted_message,
@@ -493,7 +516,8 @@ mod tests {
         println!("decrypted message={:?}", decrypted_message);
 
         assert_eq!(decrypted_message, message);
-        assert_eq!(sig_opt, None);
+        assert_eq!(sender_public_key, sender_key_pair.public_key());
+        assert_eq!(signature_opt, None);
 
         Ok(())
     }
diff --git a/src/private_message/authentication.rs b/src/private_message/authentication.rs
index 52f626f3554a71adc4e3e3787b4e8582c2e15b24..32714ea242e876cb5b68ec8311e0e26220e62d64 100644
--- a/src/private_message/authentication.rs
+++ b/src/private_message/authentication.rs
@@ -114,7 +114,7 @@ pub(crate) fn verify_authentication_proof(
     receiver_key_pair: &Ed25519KeyPair,
     message: &[u8],
     authentication_datas: &[u8],
-) -> Result<Option<Signature>, PrivateMessageError> {
+) -> Result<(Ed25519PublicKey, Option<Signature>), PrivateMessageError> {
     let sender_public_key =
         Ed25519PublicKey::try_from(&authentication_datas[..SENDER_PUBLIC_KEY_LEN])
             .map_err(PrivateMessageError::InvalidSenderPubkey)?;
@@ -151,7 +151,7 @@ pub(crate) fn verify_authentication_proof(
                 .map_err(|_| PrivateMessageError::InvalidAuthenticationProof)?;
         }
     }
-    Ok(signature_opt)
+    Ok((sender_public_key, signature_opt))
 }
 
 #[cfg(test)]