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