Skip to main content

sof_types/
signature.rs

1use std::fmt;
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};
4
5use crate::base58::DecodeBase58Error;
6
7/// Length in bytes of one transaction signature.
8pub const SIGNATURE_BYTES: usize = 64;
9
10/// Stable SOF-owned 64-byte transaction signature wrapper.
11#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
12pub struct SignatureBytes([u8; SIGNATURE_BYTES]);
13
14impl SignatureBytes {
15    /// Creates one wrapper from raw bytes.
16    #[must_use]
17    pub const fn new(bytes: [u8; SIGNATURE_BYTES]) -> Self {
18        Self(bytes)
19    }
20
21    /// Returns the inner fixed-width byte array by value.
22    #[must_use]
23    pub const fn into_array(self) -> [u8; SIGNATURE_BYTES] {
24        self.0
25    }
26
27    /// Returns the inner fixed-width byte array by reference.
28    #[must_use]
29    pub const fn as_array(&self) -> &[u8; SIGNATURE_BYTES] {
30        &self.0
31    }
32
33    /// Decodes one base58-encoded signature string.
34    ///
35    /// # Errors
36    ///
37    /// Returns [`DecodeBase58Error`] when the string is not valid base58 or has the wrong width.
38    pub fn from_base58(value: &str) -> Result<Self, DecodeBase58Error> {
39        let decoded =
40            bs58::decode(value)
41                .into_vec()
42                .map_err(|error| DecodeBase58Error::InvalidBase58 {
43                    message: error.to_string(),
44                })?;
45        let bytes: [u8; SIGNATURE_BYTES] =
46            decoded
47                .try_into()
48                .map_err(|decoded: Vec<u8>| DecodeBase58Error::WrongLength {
49                    expected: SIGNATURE_BYTES,
50                    actual: decoded.len(),
51                })?;
52        Ok(Self(bytes))
53    }
54
55    /// Encodes this signature as a base58 string.
56    #[must_use]
57    pub fn to_base58(self) -> String {
58        bs58::encode(self.0).into_string()
59    }
60}
61
62impl From<[u8; SIGNATURE_BYTES]> for SignatureBytes {
63    fn from(value: [u8; SIGNATURE_BYTES]) -> Self {
64        Self::new(value)
65    }
66}
67
68impl From<SignatureBytes> for [u8; SIGNATURE_BYTES] {
69    fn from(value: SignatureBytes) -> Self {
70        value.into_array()
71    }
72}
73
74impl fmt::Display for SignatureBytes {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        f.write_str(&self.to_base58())
77    }
78}
79
80impl Serialize for SignatureBytes {
81    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82    where
83        S: Serializer,
84    {
85        serializer.serialize_bytes(&self.0)
86    }
87}
88
89impl<'de> Deserialize<'de> for SignatureBytes {
90    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91    where
92        D: Deserializer<'de>,
93    {
94        let bytes = Vec::<u8>::deserialize(deserializer)?;
95        let signature: [u8; SIGNATURE_BYTES] = bytes
96            .try_into()
97            .map_err(|bytes: Vec<u8>| D::Error::invalid_length(bytes.len(), &"64 bytes"))?;
98        Ok(Self::new(signature))
99    }
100}
101
102#[cfg(feature = "solana-compat")]
103impl SignatureBytes {
104    /// Converts one Solana signature into the SOF-owned wrapper.
105    #[must_use]
106    pub fn from_solana(value: solana_signature::Signature) -> Self {
107        Self::new(value.into())
108    }
109
110    /// Converts this SOF-owned wrapper into one Solana signature.
111    #[must_use]
112    pub fn to_solana(self) -> solana_signature::Signature {
113        solana_signature::Signature::from(self.into_array())
114    }
115}
116
117#[cfg(feature = "solana-compat")]
118impl From<solana_signature::Signature> for SignatureBytes {
119    fn from(value: solana_signature::Signature) -> Self {
120        Self::from_solana(value)
121    }
122}
123
124#[cfg(feature = "solana-compat")]
125impl From<SignatureBytes> for solana_signature::Signature {
126    fn from(value: SignatureBytes) -> Self {
127        value.to_solana()
128    }
129}