clone_solana_signer/
lib.rs

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