1use 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
46pub struct LocalKeystore(RwLock<KeystoreInner>);
48
49impl LocalKeystore {
50 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 pub fn in_memory() -> Self {
65 let inner = KeystoreInner::new_in_memory();
66 Self(RwLock::new(inner))
67 }
68
69 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 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 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 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 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 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 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 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 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
445struct KeystoreInner {
451 path: Option<PathBuf>,
452 additional: HashMap<(KeyTypeId, Vec<u8>), String>,
454 password: Option<SecretString>,
455}
456
457impl KeystoreInner {
458 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 fn password(&self) -> Option<&str> {
470 self.password.as_ref().map(|p| p.expose_secret()).map(|p| p.as_str())
471 }
472
473 fn new_in_memory() -> Self {
475 Self { path: None, additional: HashMap::new(), password: None }
476 }
477
478 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}