cargo_tangle/command/
keys.rs1use bip39::{Language, Mnemonic};
2use blueprint_crypto::bn254::{ArkBlsBn254Public, ArkBlsBn254Secret};
3use blueprint_crypto::k256::{K256Ecdsa, K256SigningKey};
4use blueprint_crypto::sp_core::{
5 SpBls377, SpBls377Pair, SpBls377Public, SpBls381, SpBls381Pair, SpBls381Public, SpEcdsa,
6 SpEcdsaPair, SpEcdsaPublic, SpEd25519, SpEd25519Pair, SpEd25519Public, SpSr25519,
7 SpSr25519Pair, SpSr25519Public,
8};
9use blueprint_crypto::{KeyTypeId, bn254::ArkBlsBn254};
10use blueprint_crypto_core::{BytesEncoding, KeyType};
11use blueprint_keystore::{Keystore, KeystoreConfig, backends::Backend};
12use blueprint_runner::config::Protocol;
13use blueprint_std::path::Path;
14use color_eyre::eyre::Result;
15use dialoguer::{Input, Select};
16
17#[derive(thiserror::Error, Debug)]
18pub enum Error {
19 #[error("Unknown key type: {0}")]
20 UnknownKeyType(String),
21 #[error("Keystore error: {0}")]
22 KeystoreError(#[from] blueprint_keystore::error::Error),
23 #[error("Invalid key format: {0}")]
24 InvalidKeyFormat(String),
25 #[error("Invalid mnemonic word count: {0}. Must be 12, 15, 18, 21, or 24")]
26 InvalidWordCount(u32),
27}
28
29#[allow(clippy::missing_errors_doc)]
30pub fn prompt_for_keys(key_types: Vec<KeyTypeId>) -> color_eyre::Result<Vec<(KeyTypeId, String)>> {
31 let mut collected_keys = Vec::new();
32 let all_key_types = [
33 KeyTypeId::Bn254,
34 KeyTypeId::Ecdsa,
35 KeyTypeId::Sr25519,
36 KeyTypeId::Ed25519,
37 KeyTypeId::Bls381,
38 KeyTypeId::Bls377,
39 ];
40
41 if key_types.is_empty() {
42 loop {
43 let mut options = all_key_types
44 .iter()
45 .map(|kt| format!("Enter key for {:?}", kt))
46 .collect::<Vec<_>>();
47 options.push("Continue".to_string());
48
49 let selection = Select::new()
50 .with_prompt("Select key type to enter (or Continue when done)")
51 .items(&options)
52 .default(0)
53 .interact()?;
54
55 if selection == options.len() - 1 {
56 break;
58 }
59
60 let key_type = all_key_types[selection];
61 let key: String = Input::new()
62 .with_prompt(format!("Enter private key for {:?}", key_type))
63 .interact_text()?;
64
65 collected_keys.push((key_type, key));
66 }
67 } else {
68 for key_type in key_types {
70 let key: String = Input::new()
71 .with_prompt(format!("Enter private key for {:?}", key_type))
72 .interact_text()?;
73
74 collected_keys.push((key_type, key));
75 }
76 }
77
78 Ok(collected_keys)
79}
80
81pub fn generate_key(
89 key_type: KeyTypeId,
90 output: Option<&impl AsRef<Path>>,
91 seed: Option<&[u8]>,
92 show_secret: bool,
93) -> Result<(String, Option<String>)> {
94 let mut config = KeystoreConfig::new();
96 if let Some(path) = output {
97 if !path.as_ref().exists() {
98 std::fs::create_dir_all(path.as_ref())?;
99 }
100 config = config.fs_root(path);
101 }
102
103 let keystore = Keystore::new(config)?;
104
105 let (public_bytes, secret_bytes) = match key_type {
107 KeyTypeId::Sr25519 => {
108 let public = keystore.generate::<SpSr25519>(seed)?;
109 let secret = keystore.get_secret::<SpSr25519>(&public)?;
110 keystore.insert::<SpSr25519>(&secret)?;
111 (public.to_bytes(), secret.to_bytes())
112 }
113 KeyTypeId::Ed25519 => {
114 let public = keystore.generate::<SpEd25519>(seed)?;
115 let secret = keystore.get_secret::<SpEd25519>(&public)?;
116 keystore.insert::<SpEd25519>(&secret)?;
117 (public.to_bytes(), secret.to_bytes())
118 }
119 KeyTypeId::Ecdsa => {
120 let public = keystore.generate::<SpEcdsa>(seed)?;
121 let secret = keystore.get_secret::<SpEcdsa>(&public)?;
122 keystore.insert::<SpEcdsa>(&secret)?;
123 (public.to_bytes(), secret.to_bytes())
124 }
125 KeyTypeId::Bls381 => {
126 let public = keystore.generate::<SpBls381>(seed)?;
127 let secret = keystore.get_secret::<SpBls381>(&public)?;
128 keystore.insert::<SpBls381>(&secret)?;
129 (public.to_bytes(), secret.to_bytes())
130 }
131 KeyTypeId::Bls377 => {
132 let public = keystore.generate::<SpBls377>(seed)?;
133 let secret = keystore.get_secret::<SpBls377>(&public)?;
134 keystore.insert::<SpBls377>(&secret)?;
135 (public.to_bytes(), secret.to_bytes())
136 }
137 KeyTypeId::Bn254 => {
138 let public = keystore.generate::<ArkBlsBn254>(seed)?;
139 let secret = keystore.get_secret::<ArkBlsBn254>(&public)?;
140 keystore.insert::<ArkBlsBn254>(&secret)?;
141 (public.to_bytes(), secret.to_bytes())
142 }
143 };
144
145 let (public, secret) = (hex::encode(public_bytes), hex::encode(secret_bytes));
146
147 let mut secret = Some(secret);
148 if !show_secret {
149 secret = None;
150 }
151
152 Ok((public, secret))
153}
154
155pub fn generate_mnemonic(word_count: Option<u32>) -> Result<String> {
163 let count = match word_count {
164 Some(count) if !(12..=24).contains(&count) || count % 3 != 0 => {
165 return Err(Error::InvalidWordCount(count).into());
166 }
167 Some(count) => count,
168 None => 12,
169 };
170 let mut rng = bip39::rand::thread_rng();
171 let mnemonic = Mnemonic::generate_in_with(&mut rng, Language::English, count as usize)?;
172 Ok(mnemonic.to_string())
173}
174
175pub fn import_key(
183 protocol: Protocol,
184 key_type: KeyTypeId,
185 secret: &str,
186 keystore_path: &Path,
187) -> Result<String> {
188 let mut config = KeystoreConfig::new();
189 config = config.fs_root(keystore_path);
190 let keystore = Keystore::new(config)?;
191
192 let secret_bytes = hex::decode(secret).map_err(|e| Error::InvalidKeyFormat(e.to_string()))?;
193
194 let public_key = match key_type {
195 KeyTypeId::Sr25519 => {
196 let key = SpSr25519Pair::from_bytes(&secret_bytes)?;
197 keystore.insert::<SpSr25519>(&key)?;
198 hex::encode(key.public().to_bytes())
199 }
200 KeyTypeId::Ed25519 => {
201 let key = SpEd25519Pair::from_bytes(&secret_bytes)?;
202 keystore.insert::<SpEd25519>(&key)?;
203 hex::encode(key.public().to_bytes())
204 }
205 KeyTypeId::Ecdsa => match protocol {
206 Protocol::Tangle => {
207 let key = SpEcdsaPair::from_bytes(&secret_bytes)?;
208 keystore.insert::<SpEcdsa>(&key)?;
209 hex::encode(key.public().to_bytes())
210 }
211 _ => {
212 let key = K256SigningKey::from_bytes(&secret_bytes)?;
213 keystore.insert::<K256Ecdsa>(&key)?;
214 hex::encode(key.public().to_bytes())
215 }
216 },
217 KeyTypeId::Bls381 => {
218 let key = SpBls381Pair::from_bytes(&secret_bytes)?;
219 keystore.insert::<SpBls381>(&key)?;
220 hex::encode(key.public().to_bytes())
221 }
222 KeyTypeId::Bls377 => {
223 let key = SpBls377Pair::from_bytes(&secret_bytes)?;
224 keystore.insert::<SpBls377>(&key)?;
225 hex::encode(key.public().to_bytes())
226 }
227 KeyTypeId::Bn254 => {
228 let key = ArkBlsBn254Secret::from_bytes(&secret_bytes)?;
229 keystore.insert::<ArkBlsBn254>(&key)?;
230 let public = ArkBlsBn254::public_from_secret(&key);
231 hex::encode(public.to_bytes())
232 }
233 };
234
235 Ok(public_key)
236}
237
238pub fn export_key(key_type: KeyTypeId, public: &str, keystore_path: &Path) -> Result<String> {
245 let mut config = KeystoreConfig::new();
246 config = config.fs_root(keystore_path);
247 let keystore = Keystore::new(config)?;
248
249 let public_bytes = hex::decode(public).map_err(|e| Error::InvalidKeyFormat(e.to_string()))?;
250
251 let secret = match key_type {
252 KeyTypeId::Sr25519 => {
253 let public = SpSr25519Public::from_bytes(&public_bytes)?;
254 let secret = keystore.get_secret::<SpSr25519>(&public)?;
255 hex::encode(secret.to_bytes())
256 }
257 KeyTypeId::Ed25519 => {
258 let public = SpEd25519Public::from_bytes(&public_bytes)?;
259 let secret = keystore.get_secret::<SpEd25519>(&public)?;
260 hex::encode(secret.to_bytes())
261 }
262 KeyTypeId::Ecdsa => {
263 let public = SpEcdsaPublic::from_bytes(&public_bytes)?;
264 let secret = keystore.get_secret::<SpEcdsa>(&public)?;
265 hex::encode(secret.to_bytes())
266 }
267 KeyTypeId::Bls381 => {
268 let public = SpBls381Public::from_bytes(&public_bytes)?;
269 let secret = keystore.get_secret::<SpBls381>(&public)?;
270 hex::encode(secret.to_bytes())
271 }
272 KeyTypeId::Bls377 => {
273 let public = SpBls377Public::from_bytes(&public_bytes)?;
274 let secret = keystore.get_secret::<SpBls377>(&public)?;
275 hex::encode(secret.to_bytes())
276 }
277 KeyTypeId::Bn254 => {
278 let public = ArkBlsBn254Public::from_bytes(&public_bytes)?;
279 let secret = keystore.get_secret::<ArkBlsBn254>(&public)?;
280 hex::encode(secret.to_bytes())
281 }
282 };
283
284 Ok(secret)
285}
286
287pub fn list_keys(keystore_path: &Path) -> Result<Vec<(KeyTypeId, String)>> {
294 let mut config = KeystoreConfig::new();
295 config = config.fs_root(keystore_path);
296 let keystore = Keystore::new(config)?;
297
298 let mut keys = Vec::new();
299
300 for key in keystore.list_local::<SpSr25519>()? {
302 keys.push((KeyTypeId::Sr25519, hex::encode(key.to_bytes())));
303 }
304 for key in keystore.list_local::<SpEd25519>()? {
305 keys.push((KeyTypeId::Ed25519, hex::encode(key.to_bytes())));
306 }
307 for key in keystore.list_local::<SpEcdsa>()? {
308 keys.push((KeyTypeId::Ecdsa, hex::encode(key.to_bytes())));
309 }
310 for key in keystore.list_local::<SpBls381>()? {
311 keys.push((KeyTypeId::Bls381, hex::encode(key.to_bytes())));
312 }
313 for key in keystore.list_local::<SpBls377>()? {
314 keys.push((KeyTypeId::Bls377, hex::encode(key.to_bytes())));
315 }
316 for key in keystore.list_local::<ArkBlsBn254>()? {
317 keys.push((KeyTypeId::Bn254, hex::encode(key.to_bytes())));
318 }
319
320 Ok(keys)
321}