stellar_base/crypto/
signature.rs

1//! Transaction signatures.
2use std::io::{Read, Write};
3
4use crate::crypto::{hash, PublicKey};
5use crate::error::{Error, Result};
6use crate::network::Network;
7use crate::transaction::TransactionEnvelope;
8use crate::xdr;
9use ed25519::Signature;
10
11/// Last 4 bytes of a public key.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct SignatureHint(pub [u8; 4]);
14
15/// A `Signature` together with the last 4 bytes of the public key.
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct DecoratedSignature {
18    hint: SignatureHint,
19    signature: Signature,
20}
21
22/// A pre authorized transaction hash.
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct PreAuthTxHash(Vec<u8>);
25
26/// Hash(x)
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct HashX(Vec<u8>);
29
30/// Signer key for Ed25519 signed payload.
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct SignerKeyEd25519SignedPayload {
33    pub ed25519: PublicKey,
34    pub payload: Vec<u8>,
35}
36
37/// A transaction signer key.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum SignerKey {
40    Ed25519(PublicKey),
41    PreAuthTx(PreAuthTxHash),
42    HashX(HashX),
43    Ed25519SignedPayload(SignerKeyEd25519SignedPayload),
44}
45
46/// A transaction signer key with its weight.
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct Signer {
49    key: SignerKey,
50    weight: u32,
51}
52
53pub trait XdrSignature {
54    /// Returns xdr object.
55    fn to_xdr(&self) -> Result<xdr::Signature>;
56
57    /// Creates from xdr object.
58    fn from_xdr(x: &xdr::Signature) -> Result<Signature>;
59}
60
61impl XdrSignature for Signature {
62    /// Returns xdr object.
63    fn to_xdr(&self) -> Result<xdr::Signature> {
64        Ok(xdr::Signature(
65            self.to_bytes()
66                .try_into()
67                .map_err(|_| Error::InvalidSignature)?,
68        ))
69    }
70
71    /// Creates from xdr object.
72    fn from_xdr(x: &xdr::Signature) -> Result<Signature> {
73        Signature::from_slice(&x.0).map_err(|_| Error::InvalidSignature)
74    }
75}
76
77impl SignatureHint {
78    /// Creates a `SignatureHint` with the last 4 bytes of the public key `pk`.
79    pub fn from_public_key(pk: &[u8]) -> SignatureHint {
80        let mut hint: [u8; 4] = Default::default();
81        let len = pk.len();
82        hint.copy_from_slice(&pk[len - 4..len]);
83        SignatureHint(hint)
84    }
85
86    /// Creates a `SignatureHint` from the byte slice.
87    pub fn from_slice(buf: &[u8]) -> Result<SignatureHint> {
88        let mut hint: [u8; 4] = Default::default();
89        if buf.len() != 4 {
90            return Err(Error::InvalidSignatureHint);
91        }
92        hint.copy_from_slice(&buf[0..4]);
93        Ok(SignatureHint(hint))
94    }
95
96    /// Converts to `Vec<u8>`.
97    pub fn to_vec(&self) -> Vec<u8> {
98        self.0.to_vec()
99    }
100
101    /// Returns xdr object.
102    pub fn to_xdr(&self) -> Result<xdr::SignatureHint> {
103        Ok(xdr::SignatureHint(self.0))
104    }
105
106    /// Creates from xdr object.
107    pub fn from_xdr(x: &xdr::SignatureHint) -> Result<SignatureHint> {
108        Ok(SignatureHint(x.0))
109    }
110}
111
112impl DecoratedSignature {
113    /// Creates a new `DecoratedSignature` with `hint` and `signature`.
114    pub fn new(hint: SignatureHint, signature: Signature) -> DecoratedSignature {
115        DecoratedSignature { hint, signature }
116    }
117
118    /// Creates a new `DecoratedSignature` from the pre image.
119    pub fn new_from_preimage(preimage: &[u8]) -> Result<DecoratedSignature> {
120        let hint = SignatureHint::from_slice(&preimage[preimage.len() - 4..])?;
121        let signature = Signature::from_slice(preimage).map_err(|_| Error::InvalidSignature)?;
122        Ok(DecoratedSignature::new(hint, signature))
123    }
124
125    /// Returns the decorated signature `hint`.
126    pub fn hint(&self) -> &SignatureHint {
127        &self.hint
128    }
129
130    /// Returns a mutable reference to the decorated signature `hint`.
131    pub fn hint_mut(&mut self) -> &mut SignatureHint {
132        &mut self.hint
133    }
134
135    /// Returns the decorated signature `signature`.
136    pub fn signature(&self) -> &Signature {
137        &self.signature
138    }
139
140    /// Returns a mutable reference to the decorated signature `signature`.
141    pub fn signature_mut(&mut self) -> &mut Signature {
142        &mut self.signature
143    }
144
145    /// Returns xdr object.
146    pub fn to_xdr(&self) -> Result<xdr::DecoratedSignature> {
147        let hint = self.hint.to_xdr()?;
148        let signature = self.signature.to_xdr()?;
149        Ok(xdr::DecoratedSignature { hint, signature })
150    }
151
152    /// Creates from xdr object.
153    pub fn from_xdr(x: &xdr::DecoratedSignature) -> Result<DecoratedSignature> {
154        let hint = SignatureHint::from_xdr(&x.hint)?;
155        let signature = Signature::from_xdr(&x.signature)?;
156        Ok(DecoratedSignature::new(hint, signature))
157    }
158}
159
160impl SignerKey {
161    /// Creates a `SignerKey` with ed25519 key.
162    pub fn new_from_public_key(key: PublicKey) -> SignerKey {
163        SignerKey::Ed25519(key)
164    }
165
166    /// Creates a `SignerKey` with hash(x) key.
167    pub fn new_from_hashx(hashx: HashX) -> SignerKey {
168        SignerKey::HashX(hashx)
169    }
170
171    /// Creates a `SignerKey` with the hash of the preimage as key.
172    pub fn new_with_hashx(preimage: &[u8]) -> SignerKey {
173        let hashx = HashX::new_from_preimage(preimage);
174        SignerKey::new_from_hashx(hashx)
175    }
176
177    /// Creates a `SignerKey` from the pre authorized transaction hash.
178    pub fn new_from_pre_authorized_transaction(preauthtx: PreAuthTxHash) -> SignerKey {
179        SignerKey::PreAuthTx(preauthtx)
180    }
181
182    /// Creates a `SignerKey` from the transaction envelope as pre authorized transaction.
183    pub fn new_from_transaction_envelope(
184        tx: &TransactionEnvelope,
185        network: &Network,
186    ) -> Result<SignerKey> {
187        let preauthtx = PreAuthTxHash::new_from_transaction_envelope(tx, network)?;
188        Ok(SignerKey::new_from_pre_authorized_transaction(preauthtx))
189    }
190
191    /// If the signer is a Ed25519 key, returns its value. Returns None otherwise.
192    pub fn as_ed25519(&self) -> Option<&PublicKey> {
193        match *self {
194            SignerKey::Ed25519(ref key) => Some(key),
195            _ => None,
196        }
197    }
198
199    /// If the signer is a Ed25519 key, returns its mutable value. Returns None otherwise.
200    pub fn as_ed25519_mut(&mut self) -> Option<&mut PublicKey> {
201        match *self {
202            SignerKey::Ed25519(ref mut key) => Some(key),
203            _ => None,
204        }
205    }
206
207    /// Returns true if the signer is a Ed25519 key.
208    pub fn is_ed25519(&self) -> bool {
209        self.as_ed25519().is_some()
210    }
211
212    /// If the signer is a PreAuthTx, returns its value. Returns None otherwise.
213    pub fn as_pre_authorized_transaction(&self) -> Option<&PreAuthTxHash> {
214        match *self {
215            SignerKey::PreAuthTx(ref hash) => Some(hash),
216            _ => None,
217        }
218    }
219
220    /// If the signer is a PreAuthTx, returns its mutable value. Returns None otherwise.
221    pub fn as_pre_authorized_transaction_mut(&mut self) -> Option<&mut PreAuthTxHash> {
222        match *self {
223            SignerKey::PreAuthTx(ref mut hash) => Some(hash),
224            _ => None,
225        }
226    }
227
228    /// Returns true if the signer is a PreAuthTx.
229    pub fn is_pre_authorized_transaction(&self) -> bool {
230        self.as_pre_authorized_transaction().is_some()
231    }
232
233    /// If the signer is a HashX, returns its value. Returns None otherwise.
234    pub fn as_hashx(&self) -> Option<&HashX> {
235        match *self {
236            SignerKey::HashX(ref hash) => Some(hash),
237            _ => None,
238        }
239    }
240
241    /// If the signer is a HashX, returns its mutable value. Returns None otherwise.
242    pub fn as_hashx_mut(&mut self) -> Option<&mut HashX> {
243        match *self {
244            SignerKey::HashX(ref mut hash) => Some(hash),
245            _ => None,
246        }
247    }
248
249    /// Returns true if the signer is a HashX.
250    pub fn is_hashx(&self) -> bool {
251        self.as_hashx().is_some()
252    }
253
254    /// Returns the xdr object.
255    pub fn to_xdr(&self) -> Result<xdr::SignerKey> {
256        match self {
257            SignerKey::Ed25519(pk) => Ok(xdr::SignerKey::Ed25519(xdr::Uint256(pk.0))),
258            SignerKey::PreAuthTx(hash) => {
259                let inner: xdr::Uint256 = hash
260                    .0
261                    .as_slice()
262                    .try_into()
263                    .map_err(|_| Error::InvalidPreAuthTx)?;
264                Ok(xdr::SignerKey::PreAuthTx(inner))
265            }
266            SignerKey::HashX(hash) => {
267                let inner: xdr::Uint256 = hash
268                    .0
269                    .as_slice()
270                    .try_into()
271                    .map_err(|_| Error::InvalidHashX)?;
272                Ok(xdr::SignerKey::HashX(inner))
273            }
274            SignerKey::Ed25519SignedPayload(signed_payload) => {
275                let payload = signed_payload
276                    .payload
277                    .as_slice()
278                    .try_into()
279                    .map_err(|_| Error::InvalidPayload)?;
280                Ok(xdr::SignerKey::Ed25519SignedPayload(
281                    xdr::SignerKeyEd25519SignedPayload {
282                        ed25519: xdr::Uint256(signed_payload.ed25519.0),
283                        payload,
284                    },
285                ))
286            }
287        }
288    }
289
290    /// Creates from xdr object.
291    pub fn from_xdr(x: &xdr::SignerKey) -> Result<SignerKey> {
292        match x {
293            xdr::SignerKey::Ed25519(bytes) => {
294                let pk = PublicKey::from_slice(&bytes.0)?;
295                Ok(SignerKey::Ed25519(pk))
296            }
297            xdr::SignerKey::PreAuthTx(bytes) => {
298                let inner = PreAuthTxHash(bytes.0.to_vec());
299                Ok(SignerKey::PreAuthTx(inner))
300            }
301            xdr::SignerKey::HashX(bytes) => {
302                let inner = HashX(bytes.0.to_vec());
303                Ok(SignerKey::HashX(inner))
304            }
305            xdr::SignerKey::Ed25519SignedPayload(signed_payload) => {
306                let ed25519 = PublicKey::from_slice(&signed_payload.ed25519.0)?;
307                let payload = signed_payload.payload.to_vec();
308                Ok(SignerKey::Ed25519SignedPayload(
309                    SignerKeyEd25519SignedPayload { ed25519, payload },
310                ))
311            }
312        }
313    }
314}
315
316impl Signer {
317    /// Creates a new `Signer` with `key` and `weight`.
318    pub fn new(key: SignerKey, weight: u32) -> Signer {
319        Signer { key, weight }
320    }
321
322    /// Returns the key.
323    pub fn key(&self) -> &SignerKey {
324        &self.key
325    }
326
327    /// Returns a mutable reference to the key.
328    pub fn key_mut(&mut self) -> &mut SignerKey {
329        &mut self.key
330    }
331
332    /// Returns the weight.
333    pub fn weight(&self) -> &u32 {
334        &self.weight
335    }
336
337    /// Returns a mutable reference to the weight.
338    pub fn weight_mut(&mut self) -> &mut u32 {
339        &mut self.weight
340    }
341
342    /// Returns xdr object.
343    pub fn to_xdr(&self) -> Result<xdr::Signer> {
344        let key = self.key.to_xdr()?;
345        Ok(xdr::Signer {
346            key,
347            weight: self.weight,
348        })
349    }
350
351    /// Creates from xdr object.
352    pub fn from_xdr(x: &xdr::Signer) -> Result<Signer> {
353        let key = SignerKey::from_xdr(&x.key)?;
354        Ok(Signer {
355            key,
356            weight: x.weight,
357        })
358    }
359}
360
361impl PreAuthTxHash {
362    /// Creates a `PreAuthTxHash` from the transaction hash.
363    ///
364    /// The `hash` must be exactly 32 bytes.
365    pub fn new(hash: Vec<u8>) -> Result<PreAuthTxHash> {
366        if hash.len() != 32 {
367            return Err(Error::InvalidPreAuthTx);
368        }
369        Ok(PreAuthTxHash(hash))
370    }
371
372    /// Creates a `PreAuthTxHash` from the transaction envelope.
373    pub fn new_from_transaction_envelope(
374        tx: &TransactionEnvelope,
375        network: &Network,
376    ) -> Result<PreAuthTxHash> {
377        let hash = tx.hash(network)?;
378        PreAuthTxHash::new(hash)
379    }
380
381    /// Returns the pre authorized transaction hash as bytes.
382    pub fn as_bytes(&self) -> &[u8] {
383        &self.0
384    }
385}
386
387impl HashX {
388    /// Creates a `HashX` from a vector of bytes.
389    ///
390    /// `hashx` must be exactly 32 bytes.
391    pub fn new(hashx: Vec<u8>) -> Result<HashX> {
392        if hashx.len() != 32 {
393            return Err(Error::InvalidHashX);
394        }
395        Ok(HashX(hashx))
396    }
397
398    /// Creates a `HashX` from the `preimage`.
399    pub fn new_from_preimage(preimage: &[u8]) -> HashX {
400        // hash always returns a 32 byte value.
401        // no need to check length.
402        HashX(hash(preimage))
403    }
404
405    /// Returns the hashx as bytes.
406    pub fn as_bytes(&self) -> &[u8] {
407        &self.0
408    }
409}
410
411impl xdr::WriteXdr for SignerKey {
412    fn write_xdr<W: Write>(&self, w: &mut xdr::Limited<W>) -> xdr::Result<()> {
413        let xdr = self.to_xdr().map_err(|_| xdr::Error::Invalid)?;
414        xdr.write_xdr(w)
415    }
416}
417
418impl xdr::ReadXdr for SignerKey {
419    fn read_xdr<R: Read>(r: &mut xdr::Limited<R>) -> xdr::Result<Self> {
420        let xdr_result = xdr::SignerKey::read_xdr(r)?;
421        Self::from_xdr(&xdr_result).map_err(|_| xdr::Error::Invalid)
422    }
423}
424
425impl xdr::WriteXdr for Signer {
426    fn write_xdr<W: Write>(&self, w: &mut xdr::Limited<W>) -> xdr::Result<()> {
427        let xdr = self.to_xdr().map_err(|_| xdr::Error::Invalid)?;
428        xdr.write_xdr(w)
429    }
430}
431
432impl xdr::ReadXdr for Signer {
433    fn read_xdr<R: Read>(r: &mut xdr::Limited<R>) -> xdr::Result<Self> {
434        let xdr_result = xdr::Signer::read_xdr(r)?;
435        Self::from_xdr(&xdr_result).map_err(|_| xdr::Error::Invalid)
436    }
437}
438
439#[cfg(test)]
440mod tests {
441    use super::SignerKey;
442    use crate::crypto::PublicKey;
443    use crate::network::Network;
444    use crate::transaction::TransactionEnvelope;
445    use crate::xdr::{XDRDeserialize as _, XDRSerialize as _};
446
447    #[test]
448    fn test_signer_key_from_public_key() {
449        let key =
450            PublicKey::from_account_id("GCEE2MAVLB3D5J64TTHR3T4ZYK4BZJEYIPE7FMG4NAXHY3VQRHW55BNX")
451                .unwrap();
452        let signer_key = SignerKey::new_from_public_key(key);
453        assert!(signer_key.is_ed25519());
454        assert!(!signer_key.is_pre_authorized_transaction());
455        assert!(!signer_key.is_hashx());
456
457        let xdr = signer_key.xdr_base64().unwrap();
458        let expected_xdr = "AAAAAIhNMBVYdj6n3JzPHc+ZwrgcpJhDyfKw3GgufG6wie3e";
459        assert_eq!(expected_xdr, xdr);
460
461        let back = SignerKey::from_xdr_base64(&xdr).unwrap();
462        assert_eq!(back, signer_key);
463    }
464
465    #[test]
466    fn test_signer_key_with_hashx() {
467        let data = "hello".to_string();
468        let signer_key = SignerKey::new_with_hashx(data.as_bytes());
469
470        assert!(!signer_key.is_ed25519());
471        assert!(!signer_key.is_pre_authorized_transaction());
472        assert!(signer_key.is_hashx());
473
474        let hashx = signer_key.as_hashx().unwrap();
475
476        assert_eq!(
477            "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=".to_string(),
478            base64::Engine::encode(&base64::engine::general_purpose::STANDARD, hashx.as_bytes())
479        );
480
481        let xdr = signer_key.xdr_base64().unwrap();
482        let expected_xdr = "AAAAAizyTbpfsKMOJug7KsW54p4bFh5cH6dCXnMEM2KTi5gk";
483        assert_eq!(expected_xdr, xdr);
484
485        let back = SignerKey::from_xdr_base64(&xdr).unwrap();
486        assert_eq!(back, signer_key);
487    }
488
489    #[test]
490    fn test_signer_key_with_pre_authorized_transaction() {
491        let tx = TransactionEnvelope::from_xdr_base64("AAAAAgAAAACITTAVWHY+p9yczx3PmcK4HKSYQ8nysNxoLnxusInt3gAAAGQAAAAAAAAAewAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap();
492        let signer_key =
493            SignerKey::new_from_transaction_envelope(&tx, &Network::new_test()).unwrap();
494
495        assert!(!signer_key.is_ed25519());
496        assert!(signer_key.is_pre_authorized_transaction());
497        assert!(!signer_key.is_hashx());
498
499        let tx_hash = signer_key
500            .as_pre_authorized_transaction()
501            .unwrap()
502            .as_bytes();
503        // Checked in stellar laboraty
504        assert_eq!(
505            "xkhj28AGwJ4ykWcbjN4347wQFhOKXg1qKFKwiXiKtzY=",
506            base64::Engine::encode(&base64::engine::general_purpose::STANDARD, tx_hash)
507        );
508
509        let xdr = signer_key.xdr_base64().unwrap();
510        let expected_xdr = "AAAAAcZIY9vABsCeMpFnG4zeN+O8EBYTil4NaihSsIl4irc2";
511        assert_eq!(expected_xdr, xdr);
512
513        let back = SignerKey::from_xdr_base64(&xdr).unwrap();
514        assert_eq!(back, signer_key);
515    }
516}