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