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 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 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 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 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 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 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 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 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 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
447struct KeystoreInner {
453 path: Option<PathBuf>,
454 additional: HashMap<(KeyTypeId, Vec<u8>), String>,
456 password: Option<SecretString>,
457}
458
459impl KeystoreInner {
460 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 fn password(&self) -> Option<&str> {
472 self.password.as_ref().map(|p| p.expose_secret()).map(|p| p.as_str())
473 }
474
475 fn new_in_memory() -> Self {
477 Self { path: None, additional: HashMap::new(), password: None }
478 }
479
480 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}