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