//! Verified payloads — witnesses of successful signature verification. //! //! [`Verified`] is a witness type that proves a signature has been //! successfully verified. It is the _only_ way to access the payload of a //! [`Signed`](crate::signed::Signed). //! //! # Construction //! //! `Verified` can only be constructed via [`Signed::try_verify`](crate::signed::Signed::try_verify). //! This ensures that you cannot accidentally use unverified data. //! //! For testing or trusted contexts, the [`VerifiedUnchecked`] extension trait //! provides an escape hatch, but it must be explicitly imported. //! //! # Example //! //! ``` //! # #[cfg(feature = "ed25519")] //! # { //! use evidence::{codec::Identity, signature::{ed25519::Ed25519, Signer}, signed::Signed, verified::Verified}; //! //! let signing_key = ed25519_dalek::SigningKey::from_bytes(&[1u8; 32]); //! let data = b"hello world"; //! //! let signed: Signed<[u8; 11], Ed25519, Identity> = Signed::seal(&signing_key, data); //! let verified: Verified<[u8; 11], Ed25519, Identity> = signed.try_verify().unwrap(); //! //! // Now we have proven access to the payload //! assert_eq!(verified.payload(), data); //! assert_eq!(verified.issuer(), &signing_key.verifying_key()); //! //! // The original Signed envelope is retained //! assert_eq!(verified.signed(), &signed); //! # } //! ``` use crate::{signature::SignaturePrimitive, signed::Signed}; /// A verified payload — proof that signature verification succeeded. /// /// This type is only constructible via: /// - [`Signed::try_verify`](crate::signed::Signed::try_verify) — verify an existing `Signed` (cloning) /// - [`Signed::into_verified`](crate::signed::Signed::into_verified) — verify an existing `Signed` (consuming) /// - [`Signed::seal_verified`](crate::signed::Signed::seal_verified) — sign and return `Verified` directly /// - [`Signed::seal_verified_async`](crate::signed::Signed::seal_verified_async) — async variant /// /// This ensures that you cannot accidentally use unverified data. /// /// The original [`Signed`] envelope is retained, so you can recover the /// encoded payload bytes, signature, and issuer key without re-signing. /// /// # Security Note /// /// `Verified` should generally _not_ be serialized and sent over the wire. /// Always transmit [`Signed`](crate::signed::Signed) and have the recipient /// verify it themselves. pub struct Verified { signed: Signed, payload: T, } impl Clone for Verified where S::VerifyingKey: Clone, S::Signature: Clone, { fn clone(&self) -> Self { Self { signed: self.signed.clone(), payload: self.payload.clone(), } } } impl PartialEq for Verified where S::VerifyingKey: PartialEq, S::Signature: PartialEq, { fn eq(&self, other: &Self) -> bool { self.signed == other.signed && self.payload == other.payload } } impl Eq for Verified where S::VerifyingKey: Eq, S::Signature: Eq, { } impl core::hash::Hash for Verified where S::VerifyingKey: core::hash::Hash, S::Signature: core::hash::Hash, { fn hash(&self, state: &mut H) { self.signed.hash(state); self.payload.hash(state); } } impl core::fmt::Debug for Verified where S::VerifyingKey: core::fmt::Debug, S::Signature: core::fmt::Debug, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Verified") .field("signed", &self.signed) .field("payload", &self.payload) .finish() } } impl Verified { /// Create a verified payload from its signed envelope and decoded payload. /// /// This is `pub(crate)` — only constructible via `Signed::try_verify`, /// `Signed::into_verified`, `Signed::seal_verified`, and /// `Signed::seal_verified_async`. #[must_use] pub(crate) const fn new(signed: Signed, payload: T) -> Self { Self { signed, payload } } /// Get the issuer's verifying key. /// /// This is the key that was used to verify the signature. #[must_use] pub const fn issuer(&self) -> &S::VerifyingKey { self.signed.issuer() } /// Get a reference to the verified payload. #[must_use] pub const fn payload(&self) -> &T { &self.payload } /// Get a reference to the original signed envelope. /// /// This provides access to the encoded payload bytes, signature, /// and issuer key without needing to re-sign. #[must_use] pub const fn signed(&self) -> &Signed { &self.signed } /// Consume the witness and return the payload. #[must_use] pub fn into_payload(self) -> T { self.payload } /// Consume the witness and return the original signed envelope. #[must_use] pub fn into_signed(self) -> Signed { self.signed } /// Consume the witness and return the signed envelope and payload. #[must_use] pub fn into_parts(self) -> (Signed, T) { (self.signed, self.payload) } } /// Extension trait for constructing [`Verified`] without verification. /// /// This trait is _intentionally_ not in the prelude. Importing it is an explicit /// acknowledgment that you are bypassing the verification guarantee. /// /// # When to use /// /// - Testing with known-good data /// - Trusted internal contexts where verification happened elsewhere /// - Reconstructing from a trusted database /// /// # Example /// /// ``` /// # #[cfg(feature = "ed25519")] /// # { /// use evidence::{codec::Identity, signature::ed25519::Ed25519, signed::{Signed, SignedUnchecked}, verified::{Verified, VerifiedUnchecked}}; /// /// let key = ed25519_dalek::VerifyingKey::from_bytes(&[0u8; 32]).unwrap(); /// let signature = ed25519_dalek::Signature::from_bytes(&[0u8; 64]); /// let payload = vec![1, 2, 3, 4]; /// /// let signed: Signed, Ed25519, Identity> = /// Signed::from_unchecked_parts(key, signature, payload.clone()); /// /// let verified: Verified, Ed25519, Identity> = /// Verified::from_unchecked_parts(signed, payload); /// # } /// ``` pub trait VerifiedUnchecked { /// Create a verified payload from a signed envelope and decoded payload. /// /// # Safety (logical) /// /// This bypasses the verification guarantee. The caller must ensure /// the payload was actually verified (e.g., in a trusted context). fn from_unchecked_parts(signed: Signed, payload: T) -> Self; } impl VerifiedUnchecked for Verified { fn from_unchecked_parts(signed: Signed, payload: T) -> Self { Self::new(signed, payload) } } #[cfg(feature = "serde")] impl serde::Serialize for Verified where T: serde::Serialize, S::VerifyingKey: serde::Serialize, S::Signature: serde::Serialize, { fn serialize(&self, serializer: Ser) -> Result { use serde::ser::SerializeStruct; let mut state = serializer.serialize_struct("Verified", 2)?; state.serialize_field("signed", &self.signed)?; state.serialize_field("payload", &self.payload)?; state.end() } } #[cfg(feature = "serde")] impl<'de, T, S: SignaturePrimitive, C> serde::Deserialize<'de> for Verified where T: serde::Deserialize<'de>, S::VerifyingKey: serde::Deserialize<'de>, S::Signature: serde::Deserialize<'de>, { fn deserialize>(deserializer: D) -> Result { use core::marker::PhantomData; use serde::de::{MapAccess, Visitor}; struct VerifiedVisitor(PhantomData<(T, S, C)>); impl<'de, T, S: SignaturePrimitive, C> Visitor<'de> for VerifiedVisitor where T: serde::Deserialize<'de>, S::VerifyingKey: serde::Deserialize<'de>, S::Signature: serde::Deserialize<'de>, { type Value = Verified; fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("struct Verified") } fn visit_map>( self, mut map: V, ) -> Result, V::Error> { let mut signed = None; let mut payload = None; while let Some(key) = map.next_key::<&str>()? { match key { "signed" => signed = Some(map.next_value()?), "payload" => payload = Some(map.next_value()?), _ => { let _: serde::de::IgnoredAny = map.next_value()?; } } } let signed = signed.ok_or_else(|| serde::de::Error::missing_field("signed"))?; let payload = payload.ok_or_else(|| serde::de::Error::missing_field("payload"))?; Ok(Verified::new(signed, payload)) } } const FIELDS: &[&str] = &["signed", "payload"]; deserializer.deserialize_struct("Verified", FIELDS, VerifiedVisitor(PhantomData)) } } #[cfg(feature = "arbitrary")] impl<'a, T, S: SignaturePrimitive, C> arbitrary::Arbitrary<'a> for Verified where T: arbitrary::Arbitrary<'a>, S::VerifyingKey: arbitrary::Arbitrary<'a>, S::Signature: arbitrary::Arbitrary<'a>, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { let signed = Signed::arbitrary(u)?; let payload = T::arbitrary(u)?; Ok(Self::new(signed, payload)) } } #[cfg(feature = "bolero")] impl bolero_generator::TypeGenerator for Verified where T: bolero_generator::TypeGenerator, S::VerifyingKey: bolero_generator::TypeGenerator, S::Signature: bolero_generator::TypeGenerator, { fn generate(driver: &mut D) -> Option { let signed = Signed::generate(driver)?; let payload = T::generate(driver)?; Some(Self::new(signed, payload)) } } #[cfg(feature = "proptest")] impl proptest::arbitrary::Arbitrary for Verified where T: proptest::arbitrary::Arbitrary + 'static, S::VerifyingKey: proptest::arbitrary::Arbitrary + 'static, S::Signature: proptest::arbitrary::Arbitrary + 'static, { type Parameters = (); type Strategy = proptest::strategy::BoxedStrategy; fn arbitrary_with((): Self::Parameters) -> Self::Strategy { use proptest::prelude::*; (any::>(), any::()) .prop_map(|(signed, payload)| Self::new(signed, payload)) .boxed() } } #[cfg(feature = "rkyv")] /// Zero-copy [`rkyv`] serialization support for [`Verified`]. pub mod archive { use super::{SignaturePrimitive, Signed, Verified}; use alloc::vec::Vec; use rkyv::{Archive, Archived, Deserialize, Serialize, rancor::Fallible}; impl Archive for Verified where T: Archive + Clone, S::VerifyingKey: Archive + Clone, S::Signature: Archive + Clone, { type Archived = ArchivedVerified; type Resolver = VerifiedResolver; fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place) { let helper = VerifiedHelper { issuer: self.signed.issuer().clone(), signature: self.signed.signature().clone(), encoded_payload: self.signed.encoded_payload().to_vec(), payload: self.payload.clone(), }; helper.resolve(resolver, out); } } impl Serialize for Verified where T: Serialize + Clone, S::VerifyingKey: Serialize + Clone, S::Signature: Serialize + Clone, Ser: Fallible + rkyv::ser::Allocator + rkyv::ser::Writer + ?Sized, { fn serialize(&self, serializer: &mut Ser) -> Result { let helper = VerifiedHelper { issuer: self.signed.issuer().clone(), signature: self.signed.signature().clone(), encoded_payload: self.signed.encoded_payload().to_vec(), payload: self.payload.clone(), }; helper.serialize(serializer) } } impl Deserialize, D> for ArchivedVerified where T: Archive, S::VerifyingKey: Archive, S::Signature: Archive, Archived: Deserialize, Archived: Deserialize, Archived: Deserialize, D: Fallible + ?Sized, D::Error: rkyv::rancor::Source, { fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { let helper: VerifiedHelper = as Deserialize< VerifiedHelper, D, >>::deserialize(self, deserializer)?; let signed = Signed::new(helper.issuer, helper.signature, helper.encoded_payload); Ok(Verified::new(signed, helper.payload)) } } /// Helper struct for rkyv serialization. /// /// The phantom type parameters from [`Verified`] are erased in the archived /// form since they only matter at compile time. #[derive(Debug, Archive, Serialize, Deserialize)] pub struct VerifiedHelper { issuer: VerifyingKey, signature: Signature, encoded_payload: Vec, payload: Payload, } /// Type alias for the archived form of [`Verified`]. pub type ArchivedVerified = ArchivedVerifiedHelper; /// Type alias for the resolver of [`Verified`]. pub type VerifiedResolver = VerifiedHelperResolver; }