solana_signature/
lib.rs

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