iota_types/
message_envelope.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6    fmt::{Debug, Display, Formatter},
7    ops::{Deref, DerefMut},
8};
9
10use fastcrypto::traits::KeyPair;
11use iota_sdk_types::crypto::{Intent, IntentScope};
12use once_cell::sync::OnceCell;
13use serde::{Deserialize, Serialize, de::DeserializeOwned};
14use serde_name::{DeserializeNameAdapter, SerializeNameAdapter};
15use tracing::instrument;
16
17use crate::{
18    base_types::AuthorityName,
19    committee::{Committee, EpochId},
20    crypto::{
21        AuthorityKeyPair, AuthorityQuorumSignInfo, AuthoritySignInfo, AuthoritySignInfoTrait,
22        AuthoritySignature, AuthorityStrongQuorumSignInfo, EmptySignInfo, Signer,
23    },
24    error::IotaResult,
25    executable_transaction::CertificateProof,
26    messages_checkpoint::CheckpointSequenceNumber,
27    transaction::SenderSignedData,
28};
29
30pub trait Message {
31    type DigestType: Clone + Debug;
32    const SCOPE: IntentScope;
33
34    fn scope(&self) -> IntentScope {
35        Self::SCOPE
36    }
37
38    fn digest(&self) -> Self::DigestType;
39}
40
41#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
42#[serde(remote = "Envelope")]
43pub struct Envelope<T: Message, S> {
44    #[serde(skip)]
45    digest: OnceCell<T::DigestType>,
46
47    data: T,
48    auth_signature: S,
49}
50
51impl<'de, T, S> Deserialize<'de> for Envelope<T, S>
52where
53    T: Message + Deserialize<'de>,
54    S: Deserialize<'de>,
55{
56    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
57    where
58        D: serde::de::Deserializer<'de>,
59    {
60        Envelope::deserialize(DeserializeNameAdapter::new(
61            deserializer,
62            std::any::type_name::<Self>(),
63        ))
64    }
65}
66
67impl<T, Sig> Serialize for Envelope<T, Sig>
68where
69    T: Message + Serialize,
70    Sig: Serialize,
71{
72    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
73    where
74        S: serde::ser::Serializer,
75    {
76        Envelope::serialize(
77            self,
78            SerializeNameAdapter::new(serializer, std::any::type_name::<Self>()),
79        )
80    }
81}
82
83impl<T: Message, S> Envelope<T, S> {
84    pub fn new_from_data_and_sig(data: T, sig: S) -> Self {
85        Self {
86            digest: Default::default(),
87            data,
88            auth_signature: sig,
89        }
90    }
91
92    pub fn data(&self) -> &T {
93        &self.data
94    }
95
96    pub fn into_data(self) -> T {
97        self.data
98    }
99
100    pub fn into_sig(self) -> S {
101        self.auth_signature
102    }
103
104    pub fn into_data_and_sig(self) -> (T, S) {
105        let Self {
106            data,
107            auth_signature,
108            ..
109        } = self;
110        (data, auth_signature)
111    }
112
113    /// Remove the authority signatures `S` from this envelope.
114    pub fn into_unsigned(self) -> Envelope<T, EmptySignInfo> {
115        Envelope::<T, EmptySignInfo>::new(self.into_data())
116    }
117
118    pub fn auth_sig(&self) -> &S {
119        &self.auth_signature
120    }
121
122    pub fn auth_sig_mut_for_testing(&mut self) -> &mut S {
123        &mut self.auth_signature
124    }
125
126    pub fn digest(&self) -> &T::DigestType {
127        self.digest.get_or_init(|| self.data.digest())
128    }
129
130    pub fn data_mut_for_testing(&mut self) -> &mut T {
131        &mut self.data
132    }
133}
134
135impl<T: Message + PartialEq, S: PartialEq> PartialEq for Envelope<T, S> {
136    fn eq(&self, other: &Self) -> bool {
137        self.data == other.data && self.auth_signature == other.auth_signature
138    }
139}
140
141impl<T: Message> Envelope<T, EmptySignInfo> {
142    pub fn new(data: T) -> Self {
143        Self {
144            digest: OnceCell::new(),
145            data,
146            auth_signature: EmptySignInfo {},
147        }
148    }
149}
150
151impl<T> Envelope<T, AuthoritySignInfo>
152where
153    T: Message + Serialize,
154{
155    pub fn new(
156        epoch: EpochId,
157        data: T,
158        secret: &dyn Signer<AuthoritySignature>,
159        authority: AuthorityName,
160    ) -> Self {
161        let auth_signature = Self::sign(epoch, &data, secret, authority);
162        Self {
163            digest: OnceCell::new(),
164            data,
165            auth_signature,
166        }
167    }
168
169    pub fn sign(
170        epoch: EpochId,
171        data: &T,
172        secret: &dyn Signer<AuthoritySignature>,
173        authority: AuthorityName,
174    ) -> AuthoritySignInfo {
175        AuthoritySignInfo::new(epoch, &data, Intent::iota_app(T::SCOPE), authority, secret)
176    }
177
178    pub fn epoch(&self) -> EpochId {
179        self.auth_signature.epoch
180    }
181}
182
183impl Envelope<SenderSignedData, AuthoritySignInfo> {
184    #[instrument(level = "trace", skip_all)]
185    pub fn verify_committee_sigs_only(&self, committee: &Committee) -> IotaResult {
186        self.auth_signature.verify_secure(
187            self.data(),
188            Intent::iota_app(IntentScope::SenderSignedTransaction),
189            committee,
190        )
191    }
192}
193
194impl<T, const S: bool> Envelope<T, AuthorityQuorumSignInfo<S>>
195where
196    T: Message + Serialize,
197{
198    pub fn new(
199        data: T,
200        signatures: Vec<AuthoritySignInfo>,
201        committee: &Committee,
202    ) -> IotaResult<Self> {
203        let cert = Self {
204            digest: OnceCell::new(),
205            data,
206            auth_signature: AuthorityQuorumSignInfo::<S>::new_from_auth_sign_infos(
207                signatures, committee,
208            )?,
209        };
210
211        Ok(cert)
212    }
213
214    pub fn new_from_keypairs_for_testing(
215        data: T,
216        keypairs: &[AuthorityKeyPair],
217        committee: &Committee,
218    ) -> Self {
219        let signatures = keypairs
220            .iter()
221            .map(|keypair| {
222                AuthoritySignInfo::new(
223                    committee.epoch(),
224                    &data,
225                    Intent::iota_app(T::SCOPE),
226                    keypair.public().into(),
227                    keypair,
228                )
229            })
230            .collect();
231        Self::new(data, signatures, committee).unwrap()
232    }
233
234    pub fn epoch(&self) -> EpochId {
235        self.auth_signature.epoch
236    }
237}
238
239/// TrustedEnvelope is a serializable wrapper around Envelope which is
240/// `Into<VerifiedEnvelope>` - in other words it models a verified message which
241/// has been written to the db (or some other trusted store), and may be read
242/// back from the db without further signature verification.
243///
244/// TrustedEnvelope should *only* appear in database interfaces.
245///
246/// DO NOT USE in networked APIs.
247///
248/// Because it is used very sparingly, it can be audited easily: Use
249/// rust-analyzer, or run: git grep -E 'TrustedEnvelope'
250///
251/// And verify that none of the uses appear in any network APIs.
252#[derive(Clone, Serialize, Deserialize)]
253pub struct TrustedEnvelope<T: Message, S>(Envelope<T, S>);
254
255impl<T, S: Debug> Debug for TrustedEnvelope<T, S>
256where
257    T: Message + Debug,
258{
259    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
260        write!(f, "{:?}", self.0)
261    }
262}
263
264impl<T: Message, S> TrustedEnvelope<T, S> {
265    pub fn into_inner(self) -> Envelope<T, S> {
266        self.0
267    }
268
269    pub fn inner(&self) -> &Envelope<T, S> {
270        &self.0
271    }
272}
273
274// An empty marker struct that can't be serialized.
275#[derive(Clone)]
276struct NoSer;
277// Never remove this assert!
278static_assertions::assert_not_impl_any!(NoSer: Serialize, DeserializeOwned);
279
280#[derive(Clone)]
281pub struct VerifiedEnvelope<T: Message, S>(TrustedEnvelope<T, S>, NoSer);
282
283impl<T, S: Debug> Debug for VerifiedEnvelope<T, S>
284where
285    T: Message + Debug,
286{
287    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
288        write!(f, "{:?}", self.0.0)
289    }
290}
291
292impl<T: Message, S> VerifiedEnvelope<T, S> {
293    /// This API should only be called when the input is already verified.
294    pub fn new_from_verified(inner: Envelope<T, S>) -> Self {
295        Self(TrustedEnvelope(inner), NoSer)
296    }
297
298    /// There are some situations (e.g. fragment verification) where its very
299    /// awkward and/or inefficient to obtain verified certificates from
300    /// calling CertifiedTransaction::verify() Use this carefully.
301    pub fn new_unchecked(inner: Envelope<T, S>) -> Self {
302        Self(TrustedEnvelope(inner), NoSer)
303    }
304
305    pub fn into_inner(self) -> Envelope<T, S> {
306        self.0.0
307    }
308
309    pub fn inner(&self) -> &Envelope<T, S> {
310        &self.0.0
311    }
312
313    pub fn into_message(self) -> T {
314        self.into_inner().into_data()
315    }
316
317    /// Use this when you need to serialize a verified envelope.
318    /// This should generally only be used for database writes.
319    /// ***never use over the network!***
320    pub fn serializable_ref(&self) -> &TrustedEnvelope<T, S> {
321        &self.0
322    }
323
324    /// Use this when you need to serialize a verified envelope.
325    /// This should generally only be used for database writes.
326    /// ***never use over the network!***
327    pub fn serializable(self) -> TrustedEnvelope<T, S> {
328        self.0
329    }
330
331    /// Remove the authority signatures `S` from this envelope.
332    pub fn into_unsigned(self) -> VerifiedEnvelope<T, EmptySignInfo> {
333        VerifiedEnvelope::<T, EmptySignInfo>::new_from_verified(self.into_inner().into_unsigned())
334    }
335}
336
337/// After deserialization, a TrustedTransactionEnvelope can be turned back into
338/// a VerifiedTransactionEnvelope.
339impl<T: Message, S> From<TrustedEnvelope<T, S>> for VerifiedEnvelope<T, S> {
340    fn from(e: TrustedEnvelope<T, S>) -> Self {
341        Self::new_unchecked(e.0)
342    }
343}
344
345impl<T: Message, S> Deref for VerifiedEnvelope<T, S> {
346    type Target = Envelope<T, S>;
347    fn deref(&self) -> &Self::Target {
348        &self.0.0
349    }
350}
351
352impl<T: Message, S> Deref for Envelope<T, S> {
353    type Target = T;
354    fn deref(&self) -> &Self::Target {
355        &self.data
356    }
357}
358
359impl<T: Message, S> DerefMut for Envelope<T, S> {
360    fn deref_mut(&mut self) -> &mut Self::Target {
361        &mut self.data
362    }
363}
364
365impl<T: Message, S> From<VerifiedEnvelope<T, S>> for Envelope<T, S> {
366    fn from(v: VerifiedEnvelope<T, S>) -> Self {
367        v.0.0
368    }
369}
370
371impl<T: Message, S> PartialEq for VerifiedEnvelope<T, S>
372where
373    Envelope<T, S>: PartialEq,
374{
375    fn eq(&self, other: &Self) -> bool {
376        self.0.0 == other.0.0
377    }
378}
379
380impl<T: Message, S> Eq for VerifiedEnvelope<T, S> where Envelope<T, S>: Eq {}
381
382impl<T, S> Display for VerifiedEnvelope<T, S>
383where
384    T: Message,
385    Envelope<T, S>: Display,
386{
387    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
388        write!(f, "{}", self.0.0)
389    }
390}
391
392/// The following implementation provides two ways to construct a
393/// VerifiedEnvelope with CertificateProof. It is implemented in this file such
394/// that we could reuse the digest without having to recompute it.
395/// We allow converting a VerifiedCertificate into a VerifiedEnvelope with
396/// CertificateProof::Certificate; and converting a VerifiedTransaction along
397/// with checkpoint information into a VerifiedEnvelope
398/// with CertificateProof::Checkpoint.
399impl<T: Message> VerifiedEnvelope<T, CertificateProof> {
400    pub fn new_from_certificate(
401        certificate: VerifiedEnvelope<T, AuthorityStrongQuorumSignInfo>,
402    ) -> Self {
403        let inner = certificate.into_inner();
404        let Envelope {
405            digest,
406            data,
407            auth_signature,
408        } = inner;
409        VerifiedEnvelope::new_unchecked(Envelope {
410            digest,
411            data,
412            auth_signature: CertificateProof::new_from_cert_sig(auth_signature),
413        })
414    }
415
416    pub fn new_from_checkpoint(
417        transaction: VerifiedEnvelope<T, EmptySignInfo>,
418        epoch: EpochId,
419        checkpoint: CheckpointSequenceNumber,
420    ) -> Self {
421        let inner = transaction.into_inner();
422        let Envelope {
423            digest,
424            data,
425            auth_signature: _,
426        } = inner;
427        VerifiedEnvelope::new_unchecked(Envelope {
428            digest,
429            data,
430            auth_signature: CertificateProof::new_from_checkpoint(epoch, checkpoint),
431        })
432    }
433
434    pub fn new_system(transaction: VerifiedEnvelope<T, EmptySignInfo>, epoch: EpochId) -> Self {
435        let inner = transaction.into_inner();
436        let Envelope {
437            digest,
438            data,
439            auth_signature: _,
440        } = inner;
441        VerifiedEnvelope::new_unchecked(Envelope {
442            digest,
443            data,
444            auth_signature: CertificateProof::new_system(epoch),
445        })
446    }
447
448    pub fn new_from_quorum_execution(
449        transaction: VerifiedEnvelope<T, EmptySignInfo>,
450        epoch: EpochId,
451    ) -> Self {
452        let inner = transaction.into_inner();
453        let Envelope {
454            digest,
455            data,
456            auth_signature: _,
457        } = inner;
458        VerifiedEnvelope::new_unchecked(Envelope {
459            digest,
460            data,
461            auth_signature: CertificateProof::QuorumExecuted(epoch),
462        })
463    }
464
465    pub fn epoch(&self) -> EpochId {
466        self.auth_signature.epoch()
467    }
468}