Skip to main content

solana_signature/
lib.rs

1//! 64-byte signature type.
2#![no_std]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
5#[cfg(any(test, feature = "verify"))]
6use core::convert::TryInto;
7use core::{
8    fmt,
9    str::{from_utf8_unchecked, FromStr},
10};
11#[cfg(feature = "alloc")]
12extern crate alloc;
13#[cfg(feature = "std")]
14extern crate std;
15use core::error::Error;
16#[cfg(feature = "std")]
17use std::vec::Vec;
18#[cfg(feature = "wincode")]
19use wincode::{SchemaRead, SchemaWrite};
20#[cfg(feature = "serde")]
21use {
22    serde_big_array::BigArray,
23    serde_derive::{Deserialize, Serialize},
24};
25
26pub mod error;
27
28/// Number of bytes in a signature
29pub const SIGNATURE_BYTES: usize = 64;
30/// Maximum string length of a base58 encoded signature
31const MAX_BASE58_SIGNATURE_LEN: usize = 88;
32
33#[repr(transparent)]
34#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
35#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
36#[cfg_attr(
37    feature = "bytemuck",
38    derive(bytemuck_derive::Pod, bytemuck_derive::Zeroable)
39)]
40#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
41#[cfg_attr(feature = "wincode", derive(SchemaWrite, SchemaRead))]
42pub struct Signature(
43    #[cfg_attr(feature = "serde", serde(with = "BigArray"))] [u8; SIGNATURE_BYTES],
44);
45
46impl Default for Signature {
47    fn default() -> Self {
48        Self([0u8; 64])
49    }
50}
51
52impl solana_sanitize::Sanitize for Signature {}
53
54impl Signature {
55    /// Return a reference to the `Signature`'s byte array.
56    #[inline(always)]
57    pub const fn as_array(&self) -> &[u8; SIGNATURE_BYTES] {
58        &self.0
59    }
60}
61
62#[cfg(feature = "rand")]
63impl Signature {
64    pub fn new_unique() -> Self {
65        Self::from(core::array::from_fn(|_| rand::random()))
66    }
67}
68
69#[cfg(any(test, feature = "verify"))]
70impl Signature {
71    pub(self) fn verify_verbose(
72        &self,
73        pubkey_bytes: &[u8],
74        message_bytes: &[u8],
75    ) -> Result<(), ed25519_dalek::SignatureError> {
76        let publickey = ed25519_dalek::VerifyingKey::try_from(pubkey_bytes)?;
77        let signature = self.0.as_slice().try_into()?;
78        publickey.verify_strict(message_bytes, &signature)
79    }
80
81    pub fn verify(&self, pubkey_bytes: &[u8], message_bytes: &[u8]) -> bool {
82        self.verify_verbose(pubkey_bytes, message_bytes).is_ok()
83    }
84}
85
86impl AsRef<[u8]> for Signature {
87    fn as_ref(&self) -> &[u8] {
88        &self.0[..]
89    }
90}
91
92fn write_as_base58(f: &mut fmt::Formatter, s: &Signature) -> fmt::Result {
93    let mut out = [0u8; MAX_BASE58_SIGNATURE_LEN];
94    let len = five8::encode_64(&s.0, &mut out) as usize;
95    // any sequence of base58 chars is valid utf8
96    let as_str = unsafe { from_utf8_unchecked(&out[..len]) };
97    f.write_str(as_str)
98}
99
100impl fmt::Debug for Signature {
101    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102        write_as_base58(f, self)
103    }
104}
105
106impl fmt::Display for Signature {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        write_as_base58(f, self)
109    }
110}
111
112impl From<Signature> for [u8; 64] {
113    fn from(signature: Signature) -> Self {
114        signature.0
115    }
116}
117
118impl From<[u8; SIGNATURE_BYTES]> for Signature {
119    #[inline]
120    fn from(signature: [u8; SIGNATURE_BYTES]) -> Self {
121        Self(signature)
122    }
123}
124
125impl<'a> TryFrom<&'a [u8]> for Signature {
126    type Error = <[u8; SIGNATURE_BYTES] as TryFrom<&'a [u8]>>::Error;
127
128    #[inline]
129    fn try_from(signature: &'a [u8]) -> Result<Self, Self::Error> {
130        <[u8; SIGNATURE_BYTES]>::try_from(signature).map(Self::from)
131    }
132}
133
134#[cfg(feature = "std")]
135impl TryFrom<Vec<u8>> for Signature {
136    type Error = <[u8; SIGNATURE_BYTES] as TryFrom<Vec<u8>>>::Error;
137
138    #[inline]
139    fn try_from(signature: Vec<u8>) -> Result<Self, Self::Error> {
140        <[u8; SIGNATURE_BYTES]>::try_from(signature).map(Self::from)
141    }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq)]
145pub enum ParseSignatureError {
146    WrongSize,
147    Invalid,
148}
149
150impl Error for ParseSignatureError {}
151
152impl fmt::Display for ParseSignatureError {
153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154        match self {
155            ParseSignatureError::WrongSize => {
156                f.write_str("string decoded to wrong size for signature")
157            }
158            ParseSignatureError::Invalid => f.write_str("failed to decode string to signature"),
159        }
160    }
161}
162
163impl FromStr for Signature {
164    type Err = ParseSignatureError;
165
166    fn from_str(s: &str) -> Result<Self, Self::Err> {
167        use five8::DecodeError;
168        if s.len() > MAX_BASE58_SIGNATURE_LEN {
169            return Err(ParseSignatureError::WrongSize);
170        }
171        let mut bytes = [0; SIGNATURE_BYTES];
172        five8::decode_64(s, &mut bytes).map_err(|e| match e {
173            DecodeError::InvalidChar(_) => ParseSignatureError::Invalid,
174            DecodeError::TooLong
175            | DecodeError::TooShort
176            | DecodeError::LargestTermTooHigh
177            | DecodeError::OutputTooLong => ParseSignatureError::WrongSize,
178        })?;
179        Ok(Self::from(bytes))
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use {
186        super::*,
187        serde_derive::{Deserialize, Serialize},
188        solana_pubkey::Pubkey,
189    };
190
191    #[test]
192    fn test_off_curve_pubkey_verify_fails() {
193        // Golden point off the ed25519 curve
194        let off_curve_bytes = bs58::decode("9z5nJyQar1FUxVJxpBXzon6kHehbomeYiDaLi9WAMhCq")
195            .into_vec()
196            .unwrap();
197
198        // Confirm golden's off-curvedness
199        let mut off_curve_bits = [0u8; 32];
200        off_curve_bits.copy_from_slice(&off_curve_bytes);
201        let off_curve_point = curve25519_dalek::edwards::CompressedEdwardsY(off_curve_bits);
202        assert_eq!(off_curve_point.decompress(), None);
203
204        let pubkey = Pubkey::try_from(off_curve_bytes).unwrap();
205        let signature = Signature::default();
206        // Unfortunately, ed25519-dalek doesn't surface the internal error types that we'd ideally
207        // `source()` out of the `SignatureError` returned by `verify_strict()`.  So the best we
208        // can do is `is_err()` here.
209        assert!(signature.verify_verbose(pubkey.as_ref(), &[0u8]).is_err());
210    }
211
212    #[test]
213    fn test_short_vec() {
214        #[derive(Debug, Deserialize, Serialize, PartialEq)]
215        struct SigShortVec {
216            #[serde(with = "solana_short_vec")]
217            pub signatures: Vec<Signature>,
218        }
219        let sig = Signature::from([
220            120, 138, 162, 185, 59, 209, 241, 157, 71, 157, 74, 131, 4, 87, 54, 28, 38, 180, 222,
221            82, 64, 62, 61, 62, 22, 46, 17, 203, 187, 136, 62, 43, 11, 38, 235, 17, 239, 82, 240,
222            139, 130, 217, 227, 214, 9, 242, 141, 223, 94, 29, 184, 110, 62, 32, 87, 137, 63, 139,
223            100, 221, 20, 137, 4, 5,
224        ]);
225        let to_serialize = SigShortVec {
226            signatures: std::vec![sig],
227        };
228        let json_serialized = serde_json::to_string(&to_serialize).unwrap();
229        assert_eq!(json_serialized, "{\"signatures\":[[1],[120,138,162,185,59,209,241,157,71,157,74,131,4,87,54,28,38,180,222,82,64,62,61,62,22,46,17,203,187,136,62,43,11,38,235,17,239,82,240,139,130,217,227,214,9,242,141,223,94,29,184,110,62,32,87,137,63,139,100,221,20,137,4,5]]}");
230        let json_deserialized: SigShortVec = serde_json::from_str(&json_serialized).unwrap();
231        assert_eq!(json_deserialized, to_serialize);
232        let bincode_serialized = bincode::serialize(&to_serialize).unwrap();
233        assert_eq!(
234            bincode_serialized,
235            [
236                1, 120, 138, 162, 185, 59, 209, 241, 157, 71, 157, 74, 131, 4, 87, 54, 28, 38, 180,
237                222, 82, 64, 62, 61, 62, 22, 46, 17, 203, 187, 136, 62, 43, 11, 38, 235, 17, 239,
238                82, 240, 139, 130, 217, 227, 214, 9, 242, 141, 223, 94, 29, 184, 110, 62, 32, 87,
239                137, 63, 139, 100, 221, 20, 137, 4, 5
240            ]
241        );
242        let bincode_deserialized: SigShortVec = bincode::deserialize(&bincode_serialized).unwrap();
243        assert_eq!(bincode_deserialized, to_serialize);
244    }
245
246    #[test]
247    fn test_signature_fromstr() {
248        let signature = Signature::from([
249            103, 7, 88, 96, 203, 140, 191, 47, 231, 37, 30, 220, 61, 35, 93, 112, 225, 2, 5, 11,
250            158, 105, 246, 147, 133, 64, 109, 252, 119, 73, 108, 248, 167, 240, 160, 18, 222, 3, 1,
251            48, 51, 67, 94, 19, 91, 108, 227, 126, 100, 25, 212, 135, 90, 60, 61, 78, 186, 104, 22,
252            58, 242, 74, 148, 6,
253        ]);
254
255        let mut signature_base58_str = bs58::encode(signature).into_string();
256
257        assert_eq!(signature_base58_str.parse::<Signature>(), Ok(signature));
258
259        signature_base58_str.push_str(&bs58::encode(<[u8; 64]>::from(signature)).into_string());
260        assert_eq!(
261            signature_base58_str.parse::<Signature>(),
262            Err(ParseSignatureError::WrongSize)
263        );
264
265        signature_base58_str.truncate(signature_base58_str.len() / 2);
266        assert_eq!(signature_base58_str.parse::<Signature>(), Ok(signature));
267
268        signature_base58_str.truncate(signature_base58_str.len() / 2);
269        assert_eq!(
270            signature_base58_str.parse::<Signature>(),
271            Err(ParseSignatureError::WrongSize)
272        );
273
274        let mut signature_base58_str = bs58::encode(<[u8; 64]>::from(signature)).into_string();
275        assert_eq!(signature_base58_str.parse::<Signature>(), Ok(signature));
276
277        // throw some non-base58 stuff in there
278        signature_base58_str.replace_range(..1, "I");
279        assert_eq!(
280            signature_base58_str.parse::<Signature>(),
281            Err(ParseSignatureError::Invalid)
282        );
283
284        // too long input string
285        // longest valid encoding
286        let mut too_long = bs58::encode(&[255u8; SIGNATURE_BYTES]).into_string();
287        // and one to grow on
288        too_long.push('1');
289        assert_eq!(
290            too_long.parse::<Signature>(),
291            Err(ParseSignatureError::WrongSize)
292        );
293    }
294
295    #[test]
296    fn test_as_array() {
297        let bytes = [1u8; 64];
298        let signature = Signature::from(bytes);
299        assert_eq!(signature.as_array(), &bytes);
300        assert_eq!(
301            signature.as_array(),
302            &<Signature as Into<[u8; 64]>>::into(signature)
303        );
304        // Sanity check: ensure the pointer is the same.
305        assert_eq!(signature.as_array().as_ptr(), signature.0.as_ptr());
306    }
307}