Skip to main content

solana_signer/
lib.rs

1//! Abstractions and implementations for transaction signers.
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![no_std]
4extern crate alloc;
5#[cfg(feature = "std")]
6extern crate std;
7
8#[cfg(feature = "std")]
9use {
10    alloc::{boxed::Box, string::ToString},
11    std::{
12        error,
13        fs::{self, File, OpenOptions},
14        io::{Read, Write},
15        path::Path,
16    },
17};
18use {
19    alloc::{collections::BTreeSet, string::String, vec::Vec},
20    core::{fmt, ops::Deref},
21    solana_pubkey::Pubkey,
22    solana_signature::Signature,
23    solana_transaction_error::TransactionError,
24};
25
26pub mod null_signer;
27pub mod signers;
28
29#[derive(Debug, PartialEq, Eq)]
30pub enum PresignerError {
31    VerificationFailure,
32}
33
34impl core::error::Error for PresignerError {}
35
36impl fmt::Display for PresignerError {
37    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38        match self {
39            Self::VerificationFailure => f.write_str("pre-generated signature cannot verify data"),
40        }
41    }
42}
43
44#[derive(Debug, PartialEq, Eq)]
45pub enum SignerError {
46    KeypairPubkeyMismatch,
47    NotEnoughSigners,
48    TransactionError(TransactionError),
49    Custom(String),
50    // Presigner-specific Errors
51    PresignerError(PresignerError),
52    // Remote Keypair-specific Errors
53    Connection(String),
54    InvalidInput(String),
55    NoDeviceFound,
56    Protocol(String),
57    UserCancel(String),
58    TooManySigners,
59}
60
61impl core::error::Error for SignerError {
62    fn source(&self) -> ::core::option::Option<&(dyn core::error::Error + 'static)> {
63        match self {
64            Self::KeypairPubkeyMismatch => None,
65            Self::NotEnoughSigners => None,
66            Self::TransactionError(e) => Some(e),
67            Self::Custom(_) => None,
68            Self::PresignerError(e) => Some(e),
69            Self::Connection(_) => None,
70            Self::InvalidInput(_) => None,
71            Self::NoDeviceFound => None,
72            Self::Protocol(_) => None,
73            Self::UserCancel(_) => None,
74            Self::TooManySigners => None,
75        }
76    }
77}
78impl fmt::Display for SignerError {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        match self {
81            SignerError::KeypairPubkeyMismatch => f.write_str("keypair-pubkey mismatch"),
82            SignerError::NotEnoughSigners => f.write_str("not enough signers"),
83            SignerError::TransactionError(_) => f.write_str("transaction error"),
84            SignerError::Custom(e) => write!(f, "custom error: {e}",),
85            SignerError::PresignerError(_) => f.write_str("presigner error"),
86            SignerError::Connection(e) => write!(f, "connection error: {e}",),
87            SignerError::InvalidInput(s) => write!(f, "invalid input: {s}",),
88            SignerError::NoDeviceFound => f.write_str("no device found"),
89            SignerError::Protocol(s) => {
90                write!(f, "{s}")
91            }
92            SignerError::UserCancel(s) => {
93                write!(f, "{s}")
94            }
95            SignerError::TooManySigners => f.write_str("too many signers"),
96        }
97    }
98}
99
100impl From<TransactionError> for SignerError {
101    fn from(source: TransactionError) -> Self {
102        SignerError::TransactionError(source)
103    }
104}
105
106impl From<PresignerError> for SignerError {
107    fn from(source: PresignerError) -> Self {
108        SignerError::PresignerError(source)
109    }
110}
111
112/// The `Signer` trait declares operations that all digital signature providers
113/// must support. It is the primary interface by which signers are specified in
114/// `Transaction` signing interfaces
115pub trait Signer {
116    /// Infallibly gets the implementor's public key. Returns the all-zeros
117    /// `Pubkey` if the implementor has none.
118    fn pubkey(&self) -> Pubkey {
119        self.try_pubkey().unwrap_or_default()
120    }
121    /// Fallibly gets the implementor's public key
122    fn try_pubkey(&self) -> Result<Pubkey, SignerError>;
123    /// Infallibly produces an Ed25519 signature over the provided `message`
124    /// bytes. Returns the all-zeros `Signature` if signing is not possible.
125    fn sign_message(&self, message: &[u8]) -> Signature {
126        self.try_sign_message(message).unwrap_or_default()
127    }
128    /// Fallibly produces an Ed25519 signature over the provided `message` bytes.
129    fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError>;
130    /// Whether the implementation requires user interaction to sign
131    fn is_interactive(&self) -> bool;
132}
133
134/// This implements `Signer` for all ptr types - `Box/Rc/Arc/&/&mut` etc
135impl<Container: Deref<Target = impl Signer + ?Sized>> Signer for Container {
136    #[inline]
137    fn pubkey(&self) -> Pubkey {
138        self.deref().pubkey()
139    }
140
141    fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
142        self.deref().try_pubkey()
143    }
144
145    fn sign_message(&self, message: &[u8]) -> Signature {
146        self.deref().sign_message(message)
147    }
148
149    fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError> {
150        self.deref().try_sign_message(message)
151    }
152
153    fn is_interactive(&self) -> bool {
154        self.deref().is_interactive()
155    }
156}
157
158impl PartialEq for dyn Signer {
159    fn eq(&self, other: &dyn Signer) -> bool {
160        self.pubkey() == other.pubkey()
161    }
162}
163
164impl Eq for dyn Signer {}
165
166impl fmt::Debug for dyn Signer {
167    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
168        write!(fmt, "Signer: {:?}", self.pubkey())
169    }
170}
171
172/// Removes duplicate signers while preserving order. O(n log n)
173pub fn unique_signers(signers: Vec<&dyn Signer>) -> Vec<&dyn Signer> {
174    let capacity = signers.len();
175    let mut out = Vec::with_capacity(capacity);
176    let mut seen = BTreeSet::new();
177    for signer in signers {
178        let pubkey = signer.pubkey();
179        let is_unique = seen.insert(pubkey);
180        if is_unique {
181            out.push(signer);
182        }
183    }
184    out
185}
186
187/// The `EncodableKey` trait defines the interface by which cryptographic keys/keypairs are read,
188/// written, and derived from sources.
189#[cfg(feature = "std")]
190pub trait EncodableKey: Sized {
191    fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>>;
192    fn read_from_file<F: AsRef<Path>>(path: F) -> Result<Self, Box<dyn error::Error>> {
193        let mut file = File::open(path.as_ref())?;
194        Self::read(&mut file)
195    }
196    fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>>;
197    fn write_to_file<F: AsRef<Path>>(&self, outfile: F) -> Result<String, Box<dyn error::Error>> {
198        let outfile = outfile.as_ref();
199
200        if let Some(outdir) = outfile.parent() {
201            fs::create_dir_all(outdir)?;
202        }
203
204        let mut f = {
205            #[cfg(not(unix))]
206            {
207                OpenOptions::new()
208            }
209            #[cfg(unix)]
210            {
211                use std::os::unix::fs::OpenOptionsExt;
212                OpenOptions::new().mode(0o600)
213            }
214        }
215        .write(true)
216        .truncate(true)
217        .create(true)
218        .open(outfile)?;
219
220        self.write(&mut f)
221    }
222}
223
224/// The `EncodableKeypair` trait extends `EncodableKey` for asymmetric keypairs, i.e. have
225/// associated public keys.
226#[cfg(feature = "std")]
227pub trait EncodableKeypair: EncodableKey {
228    type Pubkey: ToString;
229
230    /// Returns an encodable representation of the associated public key.
231    fn encodable_pubkey(&self) -> Self::Pubkey;
232}