clone_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, FromStr},
10};
11#[cfg(feature = "std")]
12extern crate std;
13#[cfg(feature = "std")]
14use std::{error::Error, vec::Vec};
15#[cfg(feature = "serde")]
16use {
17    serde_big_array::BigArray,
18    serde_derive::{Deserialize, Serialize},
19};
20
21/// Number of bytes in a signature
22pub const SIGNATURE_BYTES: usize = 64;
23/// Maximum string length of a base58 encoded signature
24const MAX_BASE58_SIGNATURE_LEN: usize = 88;
25
26#[repr(transparent)]
27#[cfg_attr(
28    feature = "frozen-abi",
29    derive(clone_solana_frozen_abi_macro::AbiExample)
30)]
31#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
32#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
33pub struct Signature(
34    #[cfg_attr(feature = "serde", serde(with = "BigArray"))] [u8; SIGNATURE_BYTES],
35);
36
37impl Default for Signature {
38    fn default() -> Self {
39        Self([0u8; 64])
40    }
41}
42
43impl clone_solana_sanitize::Sanitize for Signature {}
44
45impl Signature {
46    /// Return a reference to the `Signature`'s byte array.
47    #[inline(always)]
48    pub const fn as_array(&self) -> &[u8; SIGNATURE_BYTES] {
49        &self.0
50    }
51}
52
53#[cfg(feature = "rand")]
54impl Signature {
55    pub fn new_unique() -> Self {
56        Self::from(core::array::from_fn(|_| rand::random()))
57    }
58}
59
60#[cfg(any(test, feature = "verify"))]
61impl Signature {
62    pub(self) fn verify_verbose(
63        &self,
64        pubkey_bytes: &[u8],
65        message_bytes: &[u8],
66    ) -> Result<(), ed25519_dalek::SignatureError> {
67        let publickey = ed25519_dalek::PublicKey::from_bytes(pubkey_bytes)?;
68        let signature = self.0.as_slice().try_into()?;
69        publickey.verify_strict(message_bytes, &signature)
70    }
71
72    pub fn verify(&self, pubkey_bytes: &[u8], message_bytes: &[u8]) -> bool {
73        self.verify_verbose(pubkey_bytes, message_bytes).is_ok()
74    }
75}
76
77impl AsRef<[u8]> for Signature {
78    fn as_ref(&self) -> &[u8] {
79        &self.0[..]
80    }
81}
82
83fn write_as_base58(f: &mut fmt::Formatter, s: &Signature) -> fmt::Result {
84    let mut out = [0u8; MAX_BASE58_SIGNATURE_LEN];
85    let out_slice: &mut [u8] = &mut out;
86    // This will never fail because the only possible error is BufferTooSmall,
87    // and we will never call it with too small a buffer.
88    let len = bs58::encode(s.0).onto(out_slice).unwrap();
89    let as_str = from_utf8(&out[..len]).unwrap();
90    f.write_str(as_str)
91}
92
93impl fmt::Debug for Signature {
94    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95        write_as_base58(f, self)
96    }
97}
98
99impl fmt::Display for Signature {
100    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101        write_as_base58(f, self)
102    }
103}
104
105impl From<Signature> for [u8; 64] {
106    fn from(signature: Signature) -> Self {
107        signature.0
108    }
109}
110
111impl From<[u8; SIGNATURE_BYTES]> for Signature {
112    #[inline]
113    fn from(signature: [u8; SIGNATURE_BYTES]) -> Self {
114        Self(signature)
115    }
116}
117
118impl<'a> TryFrom<&'a [u8]> for Signature {
119    type Error = <[u8; SIGNATURE_BYTES] as TryFrom<&'a [u8]>>::Error;
120
121    #[inline]
122    fn try_from(signature: &'a [u8]) -> Result<Self, Self::Error> {
123        <[u8; SIGNATURE_BYTES]>::try_from(signature).map(Self::from)
124    }
125}
126
127#[cfg(feature = "std")]
128impl TryFrom<Vec<u8>> for Signature {
129    type Error = <[u8; SIGNATURE_BYTES] as TryFrom<Vec<u8>>>::Error;
130
131    #[inline]
132    fn try_from(signature: Vec<u8>) -> Result<Self, Self::Error> {
133        <[u8; SIGNATURE_BYTES]>::try_from(signature).map(Self::from)
134    }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
138pub enum ParseSignatureError {
139    WrongSize,
140    Invalid,
141}
142
143#[cfg(feature = "std")]
144impl Error for ParseSignatureError {}
145
146impl fmt::Display for ParseSignatureError {
147    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148        match self {
149            ParseSignatureError::WrongSize => {
150                f.write_str("string decoded to wrong size for signature")
151            }
152            ParseSignatureError::Invalid => f.write_str("failed to decode string to signature"),
153        }
154    }
155}
156
157impl FromStr for Signature {
158    type Err = ParseSignatureError;
159
160    fn from_str(s: &str) -> Result<Self, Self::Err> {
161        if s.len() > MAX_BASE58_SIGNATURE_LEN {
162            return Err(ParseSignatureError::WrongSize);
163        }
164        let mut bytes = [0; SIGNATURE_BYTES];
165        let decoded_size = bs58::decode(s)
166            .onto(&mut bytes)
167            .map_err(|_| ParseSignatureError::Invalid)?;
168        if decoded_size != SIGNATURE_BYTES {
169            Err(ParseSignatureError::WrongSize)
170        } else {
171            Ok(bytes.into())
172        }
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    use {
179        super::*,
180        clone_solana_pubkey::Pubkey,
181        serde_derive::{Deserialize, Serialize},
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 = "clone_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}