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