near_crypto/
signer.rs

1use crate::key_conversion::convert_secret_key;
2use crate::key_file::KeyFile;
3use crate::{KeyType, PublicKey, SecretKey, Signature};
4use near_account_id::AccountId;
5use std::fmt::{self, Debug};
6use std::io;
7use std::path::Path;
8
9/// Enum for Signer, that can sign with some subset of supported curves.
10#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
11pub enum Signer {
12    /// Dummy signer, does not hold a key. Use for tests only!
13    Empty(EmptySigner),
14    /// Default signer that holds data in memory.
15    InMemory(InMemorySigner),
16}
17
18/// Enum for Signer, that can sign with some subset of supported curves.
19impl Signer {
20    pub fn public_key(&self) -> PublicKey {
21        match self {
22            Signer::Empty(signer) => signer.public_key(),
23            Signer::InMemory(signer) => signer.public_key(),
24        }
25    }
26
27    pub fn sign(&self, data: &[u8]) -> Signature {
28        match self {
29            Signer::Empty(signer) => signer.sign(data),
30            Signer::InMemory(signer) => signer.sign(data),
31        }
32    }
33
34    pub fn verify(&self, data: &[u8], signature: &Signature) -> bool {
35        signature.verify(data, &self.public_key())
36    }
37
38    pub fn compute_vrf_with_proof(&self, data: &[u8]) -> (crate::vrf::Value, crate::vrf::Proof) {
39        match self {
40            Signer::Empty(_) => unimplemented!(),
41            Signer::InMemory(signer) => signer.compute_vrf_with_proof(data),
42        }
43    }
44
45    /// Used by test infrastructure, only implement if make sense for testing otherwise raise `unimplemented`.
46    pub fn write_to_file(&self, path: &Path) -> io::Result<()> {
47        match self {
48            Signer::Empty(_) => unimplemented!(),
49            Signer::InMemory(signer) => signer.write_to_file(path),
50        }
51    }
52
53    pub fn get_account_id(&self) -> AccountId {
54        match self {
55            Signer::Empty(_) => unimplemented!(),
56            Signer::InMemory(signer) => signer.account_id.clone(),
57        }
58    }
59}
60
61impl From<EmptySigner> for Signer {
62    fn from(signer: EmptySigner) -> Self {
63        Signer::Empty(signer)
64    }
65}
66
67impl From<InMemorySigner> for Signer {
68    fn from(signer: InMemorySigner) -> Self {
69        Signer::InMemory(signer)
70    }
71}
72
73impl From<Signer> for KeyFile {
74    fn from(signer: Signer) -> KeyFile {
75        match signer {
76            Signer::Empty(_) => unimplemented!(),
77            Signer::InMemory(signer) => KeyFile {
78                account_id: signer.account_id,
79                public_key: signer.public_key,
80                secret_key: signer.secret_key,
81            },
82        }
83    }
84}
85
86// Signer that returns empty signature. Used for transaction testing.
87#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
88pub struct EmptySigner {}
89
90impl EmptySigner {
91    pub fn new() -> Self {
92        Self {}
93    }
94
95    pub fn public_key(&self) -> PublicKey {
96        PublicKey::empty(KeyType::ED25519)
97    }
98
99    pub fn sign(&self, _data: &[u8]) -> Signature {
100        Signature::empty(KeyType::ED25519)
101    }
102}
103
104/// Signer that keeps secret key in memory.
105#[derive(Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
106pub struct InMemorySigner {
107    pub account_id: AccountId,
108    pub public_key: PublicKey,
109    pub secret_key: SecretKey,
110}
111
112impl InMemorySigner {
113    #[cfg(feature = "rand")]
114    pub fn from_seed(account_id: AccountId, key_type: KeyType, seed: &str) -> Signer {
115        let secret_key = SecretKey::from_seed(key_type, seed);
116        InMemorySigner::from_secret_key(account_id, secret_key)
117    }
118
119    pub fn from_secret_key(account_id: AccountId, secret_key: SecretKey) -> Signer {
120        Signer::InMemory(Self { account_id, public_key: secret_key.public_key(), secret_key })
121    }
122
123    pub fn from_file(path: &Path) -> io::Result<Signer> {
124        KeyFile::from_file(path).map(Self::from).map(|s| Signer::InMemory(s))
125    }
126
127    pub fn public_key(&self) -> PublicKey {
128        self.public_key.clone()
129    }
130
131    pub fn sign(&self, data: &[u8]) -> Signature {
132        self.secret_key.sign(data)
133    }
134
135    pub fn compute_vrf_with_proof(&self, data: &[u8]) -> (crate::vrf::Value, crate::vrf::Proof) {
136        let secret_key = convert_secret_key(self.secret_key.unwrap_as_ed25519());
137        secret_key.compute_vrf_with_proof(&data)
138    }
139
140    pub fn write_to_file(&self, path: &Path) -> io::Result<()> {
141        KeyFile::from(self).write_to_file(path)
142    }
143
144    #[cfg(feature = "rand")]
145    pub fn test_signer(account_id: &AccountId) -> Signer {
146        InMemorySigner::from_seed(account_id.clone(), KeyType::ED25519, account_id.as_ref())
147    }
148}
149
150impl fmt::Debug for InMemorySigner {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        write!(
153            f,
154            "InMemorySigner(account_id: {}, public_key: {})",
155            self.account_id, self.public_key
156        )
157    }
158}
159
160impl From<KeyFile> for InMemorySigner {
161    fn from(key_file: KeyFile) -> Self {
162        Self {
163            account_id: key_file.account_id,
164            public_key: key_file.public_key,
165            secret_key: key_file.secret_key,
166        }
167    }
168}
169
170impl From<&InMemorySigner> for KeyFile {
171    fn from(signer: &InMemorySigner) -> KeyFile {
172        KeyFile {
173            account_id: signer.account_id.clone(),
174            public_key: signer.public_key.clone(),
175            secret_key: signer.secret_key.clone(),
176        }
177    }
178}