referrerpolicy=no-referrer-when-downgrade

sc_keystore/
local.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18//
19//! Local keystore implementation
20
21use parking_lot::RwLock;
22use sp_application_crypto::{AppCrypto, AppPair, IsWrappedBy};
23use sp_core::{
24	crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString, VrfSecret},
25	ecdsa, ed25519, sr25519,
26};
27use sp_keystore::{Error as TraitError, Keystore, KeystorePtr};
28use std::{
29	collections::HashMap,
30	fs::{self, File},
31	io::Write,
32	path::PathBuf,
33	sync::Arc,
34};
35
36sp_keystore::bandersnatch_experimental_enabled! {
37use sp_core::bandersnatch;
38}
39
40sp_keystore::bls_experimental_enabled! {
41use sp_core::{bls381, ecdsa_bls381, KeccakHasher, proof_of_possession::ProofOfPossessionGenerator};
42}
43
44use crate::{Error, Result};
45
46/// A local based keystore that is either memory-based or filesystem-based.
47pub struct LocalKeystore(RwLock<KeystoreInner>);
48
49impl LocalKeystore {
50	/// Create a local keystore from filesystem.
51	///
52	/// The keystore will be created at `path`. The keystore optionally supports to encrypt/decrypt
53	/// the keys in the keystore using `password`.
54	///
55	/// NOTE: Even when passing a `password`, the keys on disk appear to look like normal secret
56	/// uris. However, without having the correct password the secret uri will not generate the
57	/// correct private key. See [`SecretUri`](sp_core::crypto::SecretUri) for more information.
58	pub fn open<T: Into<PathBuf>>(path: T, password: Option<SecretString>) -> Result<Self> {
59		let inner = KeystoreInner::open(path, password)?;
60		Ok(Self(RwLock::new(inner)))
61	}
62
63	/// Create a local keystore in memory.
64	pub fn in_memory() -> Self {
65		let inner = KeystoreInner::new_in_memory();
66		Self(RwLock::new(inner))
67	}
68
69	/// Get a key pair for the given public key.
70	///
71	/// Returns `Ok(None)` if the key doesn't exist, `Ok(Some(_))` if the key exists and
72	/// `Err(_)` when something failed.
73	pub fn key_pair<Pair: AppPair>(
74		&self,
75		public: &<Pair as AppCrypto>::Public,
76	) -> Result<Option<Pair>> {
77		self.0.read().key_pair::<Pair>(public)
78	}
79
80	fn public_keys<T: CorePair>(&self, key_type: KeyTypeId) -> Vec<T::Public> {
81		self.0
82			.read()
83			.raw_public_keys(key_type)
84			.map(|v| {
85				v.into_iter().filter_map(|k| T::Public::from_slice(k.as_slice()).ok()).collect()
86			})
87			.unwrap_or_default()
88	}
89
90	fn generate_new<T: CorePair>(
91		&self,
92		key_type: KeyTypeId,
93		seed: Option<&str>,
94	) -> std::result::Result<T::Public, TraitError> {
95		let pair = match seed {
96			Some(seed) => self.0.write().insert_ephemeral_from_seed_by_type::<T>(seed, key_type),
97			None => self.0.write().generate_by_type::<T>(key_type),
98		}
99		.map_err(|e| -> TraitError { e.into() })?;
100		Ok(pair.public())
101	}
102
103	fn sign<T: CorePair>(
104		&self,
105		key_type: KeyTypeId,
106		public: &T::Public,
107		msg: &[u8],
108	) -> std::result::Result<Option<T::Signature>, TraitError> {
109		let signature = self
110			.0
111			.read()
112			.key_pair_by_type::<T>(public, key_type)?
113			.map(|pair| pair.sign(msg));
114		Ok(signature)
115	}
116
117	fn vrf_sign<T: CorePair + VrfSecret>(
118		&self,
119		key_type: KeyTypeId,
120		public: &T::Public,
121		data: &T::VrfSignData,
122	) -> std::result::Result<Option<T::VrfSignature>, TraitError> {
123		let sig = self
124			.0
125			.read()
126			.key_pair_by_type::<T>(public, key_type)?
127			.map(|pair| pair.vrf_sign(data));
128		Ok(sig)
129	}
130
131	fn vrf_pre_output<T: CorePair + VrfSecret>(
132		&self,
133		key_type: KeyTypeId,
134		public: &T::Public,
135		input: &T::VrfInput,
136	) -> std::result::Result<Option<T::VrfPreOutput>, TraitError> {
137		let pre_output = self
138			.0
139			.read()
140			.key_pair_by_type::<T>(public, key_type)?
141			.map(|pair| pair.vrf_pre_output(input));
142		Ok(pre_output)
143	}
144
145	sp_keystore::bls_experimental_enabled! {
146		fn generate_proof_of_possession<T: CorePair + ProofOfPossessionGenerator>(
147			&self,
148			key_type: KeyTypeId,
149			public: &T::Public,
150			owner: &[u8],
151		) -> std::result::Result<Option<T::ProofOfPossession>, TraitError> {
152			let proof_of_possession = self
153				.0
154				.read()
155				.key_pair_by_type::<T>(public, key_type)?
156				.map(|mut pair| pair.generate_proof_of_possession(owner));
157			Ok(proof_of_possession)
158		}
159	}
160}
161
162impl Keystore for LocalKeystore {
163	/// Insert a new secret key.
164	///
165	/// WARNING: if the secret keypair has been manually generated using a password
166	/// (e.g. using methods such as [`sp_core::crypto::Pair::from_phrase`]) then such
167	/// a password must match the one used to open the keystore via [`LocalKeystore::open`].
168	/// If the passwords doesn't match then the inserted key ends up being unusable under
169	/// the current keystore instance.
170	fn insert(
171		&self,
172		key_type: KeyTypeId,
173		suri: &str,
174		public: &[u8],
175	) -> std::result::Result<(), ()> {
176		self.0.write().insert(key_type, suri, public).map_err(|_| ())
177	}
178
179	fn keys(&self, key_type: KeyTypeId) -> std::result::Result<Vec<Vec<u8>>, TraitError> {
180		self.0.read().raw_public_keys(key_type).map_err(|e| e.into())
181	}
182
183	fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
184		public_keys
185			.iter()
186			.all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some())
187	}
188
189	fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec<sr25519::Public> {
190		self.public_keys::<sr25519::Pair>(key_type)
191	}
192
193	/// Generate a new pair compatible with the 'ed25519' signature scheme.
194	///
195	/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
196	fn sr25519_generate_new(
197		&self,
198		key_type: KeyTypeId,
199		seed: Option<&str>,
200	) -> std::result::Result<sr25519::Public, TraitError> {
201		self.generate_new::<sr25519::Pair>(key_type, seed)
202	}
203
204	fn sr25519_sign(
205		&self,
206		key_type: KeyTypeId,
207		public: &sr25519::Public,
208		msg: &[u8],
209	) -> std::result::Result<Option<sr25519::Signature>, TraitError> {
210		self.sign::<sr25519::Pair>(key_type, public, msg)
211	}
212
213	fn sr25519_vrf_sign(
214		&self,
215		key_type: KeyTypeId,
216		public: &sr25519::Public,
217		data: &sr25519::vrf::VrfSignData,
218	) -> std::result::Result<Option<sr25519::vrf::VrfSignature>, TraitError> {
219		self.vrf_sign::<sr25519::Pair>(key_type, public, data)
220	}
221
222	fn sr25519_vrf_pre_output(
223		&self,
224		key_type: KeyTypeId,
225		public: &sr25519::Public,
226		input: &sr25519::vrf::VrfInput,
227	) -> std::result::Result<Option<sr25519::vrf::VrfPreOutput>, TraitError> {
228		self.vrf_pre_output::<sr25519::Pair>(key_type, public, input)
229	}
230
231	fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public> {
232		self.public_keys::<ed25519::Pair>(key_type)
233	}
234
235	/// Generate a new pair compatible with the 'sr25519' signature scheme.
236	///
237	/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
238	fn ed25519_generate_new(
239		&self,
240		key_type: KeyTypeId,
241		seed: Option<&str>,
242	) -> std::result::Result<ed25519::Public, TraitError> {
243		self.generate_new::<ed25519::Pair>(key_type, seed)
244	}
245
246	fn ed25519_sign(
247		&self,
248		key_type: KeyTypeId,
249		public: &ed25519::Public,
250		msg: &[u8],
251	) -> std::result::Result<Option<ed25519::Signature>, TraitError> {
252		self.sign::<ed25519::Pair>(key_type, public, msg)
253	}
254
255	fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa::Public> {
256		self.public_keys::<ecdsa::Pair>(key_type)
257	}
258
259	/// Generate a new pair compatible with the 'ecdsa' signature scheme.
260	///
261	/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
262	fn ecdsa_generate_new(
263		&self,
264		key_type: KeyTypeId,
265		seed: Option<&str>,
266	) -> std::result::Result<ecdsa::Public, TraitError> {
267		self.generate_new::<ecdsa::Pair>(key_type, seed)
268	}
269
270	fn ecdsa_sign(
271		&self,
272		key_type: KeyTypeId,
273		public: &ecdsa::Public,
274		msg: &[u8],
275	) -> std::result::Result<Option<ecdsa::Signature>, TraitError> {
276		self.sign::<ecdsa::Pair>(key_type, public, msg)
277	}
278
279	fn ecdsa_sign_prehashed(
280		&self,
281		key_type: KeyTypeId,
282		public: &ecdsa::Public,
283		msg: &[u8; 32],
284	) -> std::result::Result<Option<ecdsa::Signature>, TraitError> {
285		let sig = self
286			.0
287			.read()
288			.key_pair_by_type::<ecdsa::Pair>(public, key_type)?
289			.map(|pair| pair.sign_prehashed(msg));
290		Ok(sig)
291	}
292
293	sp_keystore::bandersnatch_experimental_enabled! {
294		fn bandersnatch_public_keys(&self, key_type: KeyTypeId) -> Vec<bandersnatch::Public> {
295			self.public_keys::<bandersnatch::Pair>(key_type)
296		}
297
298		/// Generate a new pair compatible with the 'bandersnatch' signature scheme.
299		///
300		/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
301		fn bandersnatch_generate_new(
302			&self,
303			key_type: KeyTypeId,
304			seed: Option<&str>,
305		) -> std::result::Result<bandersnatch::Public, TraitError> {
306			self.generate_new::<bandersnatch::Pair>(key_type, seed)
307		}
308
309		fn bandersnatch_sign(
310			&self,
311			key_type: KeyTypeId,
312			public: &bandersnatch::Public,
313			msg: &[u8],
314		) -> std::result::Result<Option<bandersnatch::Signature>, TraitError> {
315			self.sign::<bandersnatch::Pair>(key_type, public, msg)
316		}
317
318		fn bandersnatch_vrf_sign(
319			&self,
320			key_type: KeyTypeId,
321			public: &bandersnatch::Public,
322			data: &bandersnatch::vrf::VrfSignData,
323		) -> std::result::Result<Option<bandersnatch::vrf::VrfSignature>, TraitError> {
324			self.vrf_sign::<bandersnatch::Pair>(key_type, public, data)
325		}
326
327		fn bandersnatch_vrf_pre_output(
328			&self,
329			key_type: KeyTypeId,
330			public: &bandersnatch::Public,
331			input: &bandersnatch::vrf::VrfInput,
332		) -> std::result::Result<Option<bandersnatch::vrf::VrfPreOutput>, TraitError> {
333			self.vrf_pre_output::<bandersnatch::Pair>(key_type, public, input)
334		}
335
336		fn bandersnatch_ring_vrf_sign(
337			&self,
338			key_type: KeyTypeId,
339			public: &bandersnatch::Public,
340			data: &bandersnatch::vrf::VrfSignData,
341			prover: &bandersnatch::ring_vrf::RingProver,
342		) -> std::result::Result<Option<bandersnatch::ring_vrf::RingVrfSignature>, TraitError> {
343			let sig = self
344				.0
345				.read()
346				.key_pair_by_type::<bandersnatch::Pair>(public, key_type)?
347				.map(|pair| pair.ring_vrf_sign(data, prover));
348			Ok(sig)
349		}
350	}
351
352	sp_keystore::bls_experimental_enabled! {
353		fn bls381_public_keys(&self, key_type: KeyTypeId) -> Vec<bls381::Public> {
354			self.public_keys::<bls381::Pair>(key_type)
355		}
356
357		/// Generate a new pair compatible with the 'bls381' signature scheme.
358		///
359		/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
360		fn bls381_generate_new(
361			&self,
362			key_type: KeyTypeId,
363			seed: Option<&str>,
364		) -> std::result::Result<bls381::Public, TraitError> {
365			self.generate_new::<bls381::Pair>(key_type, seed)
366		}
367
368		fn bls381_sign(
369			&self,
370			key_type: KeyTypeId,
371			public: &bls381::Public,
372			msg: &[u8],
373		) -> std::result::Result<Option<bls381::Signature>, TraitError> {
374			self.sign::<bls381::Pair>(key_type, public, msg)
375		}
376
377		fn bls381_generate_proof_of_possession(
378			&self,
379			key_type: KeyTypeId,
380			public: &bls381::Public,
381			owner: &[u8],
382		) -> std::result::Result<Option<bls381::ProofOfPossession>, TraitError> {
383			self.generate_proof_of_possession::<bls381::Pair>(key_type, public, owner)
384		}
385
386		fn ecdsa_bls381_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa_bls381::Public> {
387			self.public_keys::<ecdsa_bls381::Pair>(key_type)
388		}
389
390		/// Generate a new pair of paired-keys compatible with the '(ecdsa,bls381)' signature scheme.
391		///
392		/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
393		fn ecdsa_bls381_generate_new(
394			&self,
395			key_type: KeyTypeId,
396			seed: Option<&str>,
397		) -> std::result::Result<ecdsa_bls381::Public, TraitError> {
398			let pubkey = self.generate_new::<ecdsa_bls381::Pair>(key_type, seed)?;
399
400			let s = self
401				.0
402				.read()
403				.additional
404				.get(&(key_type, pubkey.to_vec()))
405				.map(|s| s.to_string())
406				.expect("Can retrieve seed");
407
408			// This is done to give the keystore access to individual keys, this is necessary to avoid
409			// unnecessary host functions for paired keys and re-use host functions implemented for each
410			// element of the pair.
411			self.generate_new::<ecdsa::Pair>(key_type, Some(&*s)).expect("seed slice is valid");
412			self.generate_new::<bls381::Pair>(key_type, Some(&*s)).expect("seed slice is valid");
413
414			Ok(pubkey)
415		}
416
417		fn ecdsa_bls381_sign(
418			&self,
419			key_type: KeyTypeId,
420			public: &ecdsa_bls381::Public,
421			msg: &[u8],
422		) -> std::result::Result<Option<ecdsa_bls381::Signature>, TraitError> {
423			self.sign::<ecdsa_bls381::Pair>(key_type, public, msg)
424		}
425
426		fn ecdsa_bls381_sign_with_keccak256(
427			&self,
428			key_type: KeyTypeId,
429			public: &ecdsa_bls381::Public,
430			msg: &[u8],
431		) -> std::result::Result<Option<ecdsa_bls381::Signature>, TraitError> {
432			 let sig = self.0
433			.read()
434			.key_pair_by_type::<ecdsa_bls381::Pair>(public, key_type)?
435			.map(|pair| pair.sign_with_hasher::<KeccakHasher>(msg));
436			Ok(sig)
437		}
438	}
439}
440
441impl Into<KeystorePtr> for LocalKeystore {
442	fn into(self) -> KeystorePtr {
443		Arc::new(self)
444	}
445}
446
447/// A local key store.
448///
449/// Stores key pairs in a file system store + short lived key pairs in memory.
450///
451/// Every pair that is being generated by a `seed`, will be placed in memory.
452struct KeystoreInner {
453	path: Option<PathBuf>,
454	/// Map over `(KeyTypeId, Raw public key)` -> `Key phrase/seed`
455	additional: HashMap<(KeyTypeId, Vec<u8>), String>,
456	password: Option<SecretString>,
457}
458
459impl KeystoreInner {
460	/// Open the store at the given path.
461	///
462	/// Optionally takes a password that will be used to encrypt/decrypt the keys.
463	fn open<T: Into<PathBuf>>(path: T, password: Option<SecretString>) -> Result<Self> {
464		let path = path.into();
465		fs::create_dir_all(&path)?;
466
467		Ok(Self { path: Some(path), additional: HashMap::new(), password })
468	}
469
470	/// Get the password for this store.
471	fn password(&self) -> Option<&str> {
472		self.password.as_ref().map(|p| p.expose_secret()).map(|p| p.as_str())
473	}
474
475	/// Create a new in-memory store.
476	fn new_in_memory() -> Self {
477		Self { path: None, additional: HashMap::new(), password: None }
478	}
479
480	/// Get the key phrase for the given public key and key type from the in-memory store.
481	fn get_additional_pair(&self, public: &[u8], key_type: KeyTypeId) -> Option<&String> {
482		let key = (key_type, public.to_vec());
483		self.additional.get(&key)
484	}
485
486	/// Insert the given public/private key pair with the given key type.
487	///
488	/// Does not place it into the file system store.
489	fn insert_ephemeral_pair<Pair: CorePair>(
490		&mut self,
491		pair: &Pair,
492		seed: &str,
493		key_type: KeyTypeId,
494	) {
495		let key = (key_type, pair.public().to_raw_vec());
496		self.additional.insert(key, seed.into());
497	}
498
499	/// Insert a new key with anonymous crypto.
500	///
501	/// Places it into the file system store, if a path is configured.
502	fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<()> {
503		if let Some(path) = self.key_file_path(public, key_type) {
504			Self::write_to_file(path, suri)?;
505		}
506
507		Ok(())
508	}
509
510	/// Generate a new key.
511	///
512	/// Places it into the file system store, if a path is configured. Otherwise insert
513	/// it into the memory cache only.
514	fn generate_by_type<Pair: CorePair>(&mut self, key_type: KeyTypeId) -> Result<Pair> {
515		let (pair, phrase, _) = Pair::generate_with_phrase(self.password());
516		if let Some(path) = self.key_file_path(pair.public().as_slice(), key_type) {
517			Self::write_to_file(path, &phrase)?;
518		} else {
519			self.insert_ephemeral_pair(&pair, &phrase, key_type);
520		}
521
522		Ok(pair)
523	}
524
525	/// Write the given `data` to `file`.
526	fn write_to_file(file: PathBuf, data: &str) -> Result<()> {
527		let mut file = File::create(file)?;
528
529		#[cfg(target_family = "unix")]
530		{
531			use std::os::unix::fs::PermissionsExt;
532			file.set_permissions(fs::Permissions::from_mode(0o600))?;
533		}
534
535		serde_json::to_writer(&file, data)?;
536		file.flush()?;
537		Ok(())
538	}
539
540	/// Create a new key from seed.
541	///
542	/// Does not place it into the file system store.
543	fn insert_ephemeral_from_seed_by_type<Pair: CorePair>(
544		&mut self,
545		seed: &str,
546		key_type: KeyTypeId,
547	) -> Result<Pair> {
548		let pair = Pair::from_string(seed, None).map_err(|_| Error::InvalidSeed)?;
549		self.insert_ephemeral_pair(&pair, seed, key_type);
550		Ok(pair)
551	}
552
553	/// Get the key phrase for a given public key and key type.
554	fn key_phrase_by_type(&self, public: &[u8], key_type: KeyTypeId) -> Result<Option<String>> {
555		if let Some(phrase) = self.get_additional_pair(public, key_type) {
556			return Ok(Some(phrase.clone()))
557		}
558
559		let path = if let Some(path) = self.key_file_path(public, key_type) {
560			path
561		} else {
562			return Ok(None)
563		};
564
565		if path.exists() {
566			let file = File::open(path)?;
567
568			serde_json::from_reader(&file).map_err(Into::into).map(Some)
569		} else {
570			Ok(None)
571		}
572	}
573
574	/// Get a key pair for the given public key and key type.
575	fn key_pair_by_type<Pair: CorePair>(
576		&self,
577		public: &Pair::Public,
578		key_type: KeyTypeId,
579	) -> Result<Option<Pair>> {
580		let phrase = if let Some(p) = self.key_phrase_by_type(public.as_slice(), key_type)? {
581			p
582		} else {
583			return Ok(None)
584		};
585
586		let pair = Pair::from_string(&phrase, self.password()).map_err(|_| Error::InvalidPhrase)?;
587
588		if &pair.public() == public {
589			Ok(Some(pair))
590		} else {
591			Err(Error::PublicKeyMismatch)
592		}
593	}
594
595	/// Get the file path for the given public key and key type.
596	///
597	/// Returns `None` if the keystore only exists in-memory and there isn't any path to provide.
598	fn key_file_path(&self, public: &[u8], key_type: KeyTypeId) -> Option<PathBuf> {
599		let mut buf = self.path.as_ref()?.clone();
600		let key_type = array_bytes::bytes2hex("", &key_type.0);
601		let key = array_bytes::bytes2hex("", public);
602		buf.push(key_type + key.as_str());
603		Some(buf)
604	}
605
606	/// Returns a list of raw public keys filtered by `KeyTypeId`
607	fn raw_public_keys(&self, key_type: KeyTypeId) -> Result<Vec<Vec<u8>>> {
608		let mut public_keys: Vec<Vec<u8>> = self
609			.additional
610			.keys()
611			.into_iter()
612			.filter_map(|k| if k.0 == key_type { Some(k.1.clone()) } else { None })
613			.collect();
614
615		if let Some(path) = &self.path {
616			for entry in fs::read_dir(&path)? {
617				let entry = entry?;
618				let path = entry.path();
619
620				// skip directories and non-unicode file names (hex is unicode)
621				if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
622					match array_bytes::hex2bytes(name) {
623						Ok(ref hex) if hex.len() > 4 => {
624							if hex[0..4] != key_type.0 {
625								continue
626							}
627							let public = hex[4..].to_vec();
628							public_keys.push(public);
629						},
630						_ => continue,
631					}
632				}
633			}
634		}
635
636		Ok(public_keys)
637	}
638
639	/// Get a key pair for the given public key.
640	///
641	/// Returns `Ok(None)` if the key doesn't exist, `Ok(Some(_))` if the key exists or `Err(_)`
642	/// when something failed.
643	pub fn key_pair<Pair: AppPair>(
644		&self,
645		public: &<Pair as AppCrypto>::Public,
646	) -> Result<Option<Pair>> {
647		self.key_pair_by_type::<Pair::Generic>(IsWrappedBy::from_ref(public), Pair::ID)
648			.map(|v| v.map(Into::into))
649	}
650}
651
652#[cfg(test)]
653mod tests {
654	use super::*;
655	use sp_application_crypto::{ed25519, sr25519, AppPublic};
656	use sp_core::{crypto::Ss58Codec, testing::SR25519, Pair};
657	use std::{fs, str::FromStr};
658	use tempfile::TempDir;
659
660	const TEST_KEY_TYPE: KeyTypeId = KeyTypeId(*b"test");
661
662	impl KeystoreInner {
663		fn insert_ephemeral_from_seed<Pair: AppPair>(&mut self, seed: &str) -> Result<Pair> {
664			self.insert_ephemeral_from_seed_by_type::<Pair::Generic>(seed, Pair::ID)
665				.map(Into::into)
666		}
667
668		fn public_keys<Public: AppPublic>(&self) -> Result<Vec<Public>> {
669			self.raw_public_keys(Public::ID).map(|v| {
670				v.into_iter().filter_map(|k| Public::from_slice(k.as_slice()).ok()).collect()
671			})
672		}
673
674		fn generate<Pair: AppPair>(&mut self) -> Result<Pair> {
675			self.generate_by_type::<Pair::Generic>(Pair::ID).map(Into::into)
676		}
677	}
678
679	#[test]
680	fn basic_store() {
681		let temp_dir = TempDir::new().unwrap();
682		let mut store = KeystoreInner::open(temp_dir.path(), None).unwrap();
683
684		assert!(store.public_keys::<ed25519::AppPublic>().unwrap().is_empty());
685
686		let key: ed25519::AppPair = store.generate().unwrap();
687		let key2: ed25519::AppPair = store.key_pair(&key.public()).unwrap().unwrap();
688
689		assert_eq!(key.public(), key2.public());
690
691		assert_eq!(store.public_keys::<ed25519::AppPublic>().unwrap()[0], key.public());
692	}
693
694	#[test]
695	fn has_keys_works() {
696		let temp_dir = TempDir::new().unwrap();
697		let store = LocalKeystore::open(temp_dir.path(), None).unwrap();
698
699		let key: ed25519::AppPair = store.0.write().generate().unwrap();
700		let key2 = ed25519::Pair::generate().0;
701
702		assert!(!store.has_keys(&[(key2.public().to_vec(), ed25519::AppPublic::ID)]));
703
704		assert!(!store.has_keys(&[
705			(key2.public().to_vec(), ed25519::AppPublic::ID),
706			(key.public().to_raw_vec(), ed25519::AppPublic::ID),
707		],));
708
709		assert!(store.has_keys(&[(key.public().to_raw_vec(), ed25519::AppPublic::ID)]));
710	}
711
712	#[test]
713	fn test_insert_ephemeral_from_seed() {
714		let temp_dir = TempDir::new().unwrap();
715		let mut store = KeystoreInner::open(temp_dir.path(), None).unwrap();
716
717		let pair: ed25519::AppPair = store
718			.insert_ephemeral_from_seed(
719				"0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc",
720			)
721			.unwrap();
722		assert_eq!(
723			"5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HJCA",
724			pair.public().to_ss58check()
725		);
726
727		drop(store);
728		let store = KeystoreInner::open(temp_dir.path(), None).unwrap();
729		// Keys generated from seed should not be persisted!
730		assert!(store.key_pair::<ed25519::AppPair>(&pair.public()).unwrap().is_none());
731	}
732
733	#[test]
734	fn password_being_used() {
735		let password = String::from("password");
736		let temp_dir = TempDir::new().unwrap();
737		let mut store = KeystoreInner::open(
738			temp_dir.path(),
739			Some(FromStr::from_str(password.as_str()).unwrap()),
740		)
741		.unwrap();
742
743		let pair: ed25519::AppPair = store.generate().unwrap();
744		assert_eq!(
745			pair.public(),
746			store.key_pair::<ed25519::AppPair>(&pair.public()).unwrap().unwrap().public(),
747		);
748
749		// Without the password the key should not be retrievable
750		let store = KeystoreInner::open(temp_dir.path(), None).unwrap();
751		assert!(store.key_pair::<ed25519::AppPair>(&pair.public()).is_err());
752
753		let store = KeystoreInner::open(
754			temp_dir.path(),
755			Some(FromStr::from_str(password.as_str()).unwrap()),
756		)
757		.unwrap();
758		assert_eq!(
759			pair.public(),
760			store.key_pair::<ed25519::AppPair>(&pair.public()).unwrap().unwrap().public(),
761		);
762	}
763
764	#[test]
765	fn public_keys_are_returned() {
766		let temp_dir = TempDir::new().unwrap();
767		let mut store = KeystoreInner::open(temp_dir.path(), None).unwrap();
768
769		let mut keys = Vec::new();
770		for i in 0..10 {
771			keys.push(store.generate::<ed25519::AppPair>().unwrap().public());
772			keys.push(
773				store
774					.insert_ephemeral_from_seed::<ed25519::AppPair>(&format!(
775						"0x3d97c819d68f9bafa7d6e79cb991eebcd7{}d966c5334c0b94d9e1fa7ad0869dc",
776						i
777					))
778					.unwrap()
779					.public(),
780			);
781		}
782
783		// Generate a key of a different type
784		store.generate::<sr25519::AppPair>().unwrap();
785
786		keys.sort();
787		let mut store_pubs = store.public_keys::<ed25519::AppPublic>().unwrap();
788		store_pubs.sort();
789
790		assert_eq!(keys, store_pubs);
791	}
792
793	#[test]
794	fn store_unknown_and_extract_it() {
795		let temp_dir = TempDir::new().unwrap();
796		let store = KeystoreInner::open(temp_dir.path(), None).unwrap();
797
798		let secret_uri = "//Alice";
799		let key_pair = sr25519::AppPair::from_string(secret_uri, None).expect("Generates key pair");
800
801		store
802			.insert(SR25519, secret_uri, key_pair.public().as_ref())
803			.expect("Inserts unknown key");
804
805		let store_key_pair = store
806			.key_pair_by_type::<sr25519::AppPair>(&key_pair.public(), SR25519)
807			.expect("Gets key pair from keystore")
808			.unwrap();
809
810		assert_eq!(key_pair.public(), store_key_pair.public());
811	}
812
813	#[test]
814	fn store_ignores_files_with_invalid_name() {
815		let temp_dir = TempDir::new().unwrap();
816		let store = LocalKeystore::open(temp_dir.path(), None).unwrap();
817
818		let file_name = temp_dir.path().join(array_bytes::bytes2hex("", &SR25519.0[..2]));
819		fs::write(file_name, "test").expect("Invalid file is written");
820
821		assert!(store.sr25519_public_keys(SR25519).is_empty());
822	}
823
824	#[test]
825	fn generate_with_seed_is_not_stored() {
826		let temp_dir = TempDir::new().unwrap();
827		let store = LocalKeystore::open(temp_dir.path(), None).unwrap();
828		let _alice_tmp_key = store.sr25519_generate_new(TEST_KEY_TYPE, Some("//Alice")).unwrap();
829
830		assert_eq!(store.sr25519_public_keys(TEST_KEY_TYPE).len(), 1);
831
832		drop(store);
833		let store = LocalKeystore::open(temp_dir.path(), None).unwrap();
834		assert_eq!(store.sr25519_public_keys(TEST_KEY_TYPE).len(), 0);
835	}
836
837	#[test]
838	fn generate_can_be_fetched_in_memory() {
839		let store = LocalKeystore::in_memory();
840		store.sr25519_generate_new(TEST_KEY_TYPE, Some("//Alice")).unwrap();
841
842		assert_eq!(store.sr25519_public_keys(TEST_KEY_TYPE).len(), 1);
843		store.sr25519_generate_new(TEST_KEY_TYPE, None).unwrap();
844		assert_eq!(store.sr25519_public_keys(TEST_KEY_TYPE).len(), 2);
845	}
846
847	#[test]
848	#[cfg(target_family = "unix")]
849	fn uses_correct_file_permissions_on_unix() {
850		use std::os::unix::fs::PermissionsExt;
851
852		let temp_dir = TempDir::new().unwrap();
853		let store = LocalKeystore::open(temp_dir.path(), None).unwrap();
854
855		let public = store.sr25519_generate_new(TEST_KEY_TYPE, None).unwrap();
856
857		let path = store.0.read().key_file_path(public.as_ref(), TEST_KEY_TYPE).unwrap();
858		let permissions = File::open(path).unwrap().metadata().unwrap().permissions();
859
860		assert_eq!(0o100600, permissions.mode());
861	}
862
863	#[test]
864	#[cfg(feature = "bls-experimental")]
865	fn ecdsa_bls381_generate_with_none_works() {
866		use sp_core::testing::ECDSA_BLS381;
867
868		let store = LocalKeystore::in_memory();
869		let ecdsa_bls381_key =
870			store.ecdsa_bls381_generate_new(ECDSA_BLS381, None).expect("Cant generate key");
871
872		let ecdsa_keys = store.ecdsa_public_keys(ECDSA_BLS381);
873		let bls381_keys = store.bls381_public_keys(ECDSA_BLS381);
874		let ecdsa_bls381_keys = store.ecdsa_bls381_public_keys(ECDSA_BLS381);
875
876		assert_eq!(ecdsa_keys.len(), 1);
877		assert_eq!(bls381_keys.len(), 1);
878		assert_eq!(ecdsa_bls381_keys.len(), 1);
879
880		let ecdsa_key = ecdsa_keys[0];
881		let bls381_key = bls381_keys[0];
882
883		let mut combined_key_raw = [0u8; ecdsa_bls381::PUBLIC_KEY_LEN];
884		combined_key_raw[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].copy_from_slice(ecdsa_key.as_ref());
885		combined_key_raw[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..].copy_from_slice(bls381_key.as_ref());
886		let combined_key = ecdsa_bls381::Public::from_raw(combined_key_raw);
887
888		assert_eq!(combined_key, ecdsa_bls381_key);
889	}
890
891	#[test]
892	#[cfg(feature = "bls-experimental")]
893	fn ecdsa_bls381_generate_with_seed_works() {
894		use sp_core::testing::ECDSA_BLS381;
895
896		let store = LocalKeystore::in_memory();
897		let ecdsa_bls381_key = store
898			.ecdsa_bls381_generate_new(ECDSA_BLS381, Some("//Alice"))
899			.expect("Cant generate key");
900
901		let ecdsa_keys = store.ecdsa_public_keys(ECDSA_BLS381);
902		let bls381_keys = store.bls381_public_keys(ECDSA_BLS381);
903		let ecdsa_bls381_keys = store.ecdsa_bls381_public_keys(ECDSA_BLS381);
904
905		assert_eq!(ecdsa_keys.len(), 1);
906		assert_eq!(bls381_keys.len(), 1);
907		assert_eq!(ecdsa_bls381_keys.len(), 1);
908
909		let ecdsa_key = ecdsa_keys[0];
910		let bls381_key = bls381_keys[0];
911
912		let mut combined_key_raw = [0u8; ecdsa_bls381::PUBLIC_KEY_LEN];
913		combined_key_raw[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].copy_from_slice(ecdsa_key.as_ref());
914		combined_key_raw[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..].copy_from_slice(bls381_key.as_ref());
915		let combined_key = ecdsa_bls381::Public::from_raw(combined_key_raw);
916
917		assert_eq!(combined_key, ecdsa_bls381_key);
918	}
919}