1use crate::{ed25519, sr25519, U256};
21use alloc::{format, str, vec::Vec};
22#[cfg(all(not(feature = "std"), feature = "serde"))]
23use alloc::{string::String, vec};
24use bip39::{Language, Mnemonic};
25use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
26use core::hash::Hash;
27#[doc(hidden)]
28pub use core::ops::Deref;
29#[cfg(feature = "std")]
30use itertools::Itertools;
31#[cfg(feature = "std")]
32use rand::{rngs::OsRng, RngCore};
33use scale_info::TypeInfo;
34pub use secrecy::{ExposeSecret, SecretString};
35use sp_runtime_interface::pass_by::PassByInner;
36pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58AddressFormatRegistry};
37pub use zeroize::Zeroize;
39
40pub use crate::{
41 address_uri::{AddressUri, Error as AddressUriError},
42 crypto_bytes::{CryptoBytes, PublicBytes, SignatureBytes},
43};
44
45pub const DEV_PHRASE: &str =
47 "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
48
49pub const DEV_ADDRESS: &str = "5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV";
51
52pub const JUNCTION_ID_LEN: usize = 32;
55
56pub trait UncheckedFrom<T> {
60 fn unchecked_from(t: T) -> Self;
64}
65
66pub trait UncheckedInto<T> {
68 fn unchecked_into(self) -> T;
70}
71
72impl<S, T: UncheckedFrom<S>> UncheckedInto<T> for S {
73 fn unchecked_into(self) -> T {
74 T::unchecked_from(self)
75 }
76}
77
78#[cfg_attr(feature = "std", derive(thiserror::Error))]
80#[derive(Debug, Clone, PartialEq, Eq)]
81pub enum SecretStringError {
82 #[cfg_attr(feature = "std", error("Invalid format {0}"))]
84 InvalidFormat(AddressUriError),
85 #[cfg_attr(feature = "std", error("Invalid phrase"))]
87 InvalidPhrase,
88 #[cfg_attr(feature = "std", error("Invalid password"))]
90 InvalidPassword,
91 #[cfg_attr(feature = "std", error("Invalid seed"))]
93 InvalidSeed,
94 #[cfg_attr(feature = "std", error("Invalid seed length"))]
96 InvalidSeedLength,
97 #[cfg_attr(feature = "std", error("Invalid path"))]
99 InvalidPath,
100}
101
102impl From<AddressUriError> for SecretStringError {
103 fn from(e: AddressUriError) -> Self {
104 Self::InvalidFormat(e)
105 }
106}
107
108#[cfg_attr(feature = "std", derive(thiserror::Error))]
110#[derive(Debug, Clone, PartialEq, Eq)]
111pub enum DeriveError {
112 #[cfg_attr(feature = "std", error("Soft key in path"))]
114 SoftKeyInPath,
115}
116
117#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)]
121pub enum DeriveJunction {
122 Soft([u8; JUNCTION_ID_LEN]),
124 Hard([u8; JUNCTION_ID_LEN]),
126}
127
128impl DeriveJunction {
129 pub fn soften(self) -> Self {
131 DeriveJunction::Soft(self.unwrap_inner())
132 }
133
134 pub fn harden(self) -> Self {
136 DeriveJunction::Hard(self.unwrap_inner())
137 }
138
139 pub fn soft<T: Encode>(index: T) -> Self {
143 let mut cc: [u8; JUNCTION_ID_LEN] = Default::default();
144 index.using_encoded(|data| {
145 if data.len() > JUNCTION_ID_LEN {
146 cc.copy_from_slice(&sp_crypto_hashing::blake2_256(data));
147 } else {
148 cc[0..data.len()].copy_from_slice(data);
149 }
150 });
151 DeriveJunction::Soft(cc)
152 }
153
154 pub fn hard<T: Encode>(index: T) -> Self {
158 Self::soft(index).harden()
159 }
160
161 pub fn unwrap_inner(self) -> [u8; JUNCTION_ID_LEN] {
163 match self {
164 DeriveJunction::Hard(c) | DeriveJunction::Soft(c) => c,
165 }
166 }
167
168 pub fn inner(&self) -> &[u8; JUNCTION_ID_LEN] {
170 match self {
171 DeriveJunction::Hard(ref c) | DeriveJunction::Soft(ref c) => c,
172 }
173 }
174
175 pub fn is_soft(&self) -> bool {
177 matches!(*self, DeriveJunction::Soft(_))
178 }
179
180 pub fn is_hard(&self) -> bool {
182 matches!(*self, DeriveJunction::Hard(_))
183 }
184}
185
186impl<T: AsRef<str>> From<T> for DeriveJunction {
187 fn from(j: T) -> DeriveJunction {
188 let j = j.as_ref();
189 let (code, hard) =
190 if let Some(stripped) = j.strip_prefix('/') { (stripped, true) } else { (j, false) };
191
192 let res = if let Ok(n) = str::parse::<u64>(code) {
193 DeriveJunction::soft(n)
195 } else {
196 DeriveJunction::soft(code)
198 };
199
200 if hard {
201 res.harden()
202 } else {
203 res
204 }
205 }
206}
207
208#[cfg_attr(feature = "std", derive(thiserror::Error))]
210#[cfg_attr(not(feature = "std"), derive(Debug))]
211#[derive(Clone, Eq, PartialEq)]
212#[allow(missing_docs)]
213#[cfg(any(feature = "full_crypto", feature = "serde"))]
214pub enum PublicError {
215 #[cfg_attr(feature = "std", error("Base 58 requirement is violated"))]
216 BadBase58,
217 #[cfg_attr(feature = "std", error("Length is bad"))]
218 BadLength,
219 #[cfg_attr(
220 feature = "std",
221 error(
222 "Unknown SS58 address format `{}`. ` \
223 `To support this address format, you need to call `set_default_ss58_version` at node start up.",
224 _0
225 )
226 )]
227 UnknownSs58AddressFormat(Ss58AddressFormat),
228 #[cfg_attr(feature = "std", error("Invalid checksum"))]
229 InvalidChecksum,
230 #[cfg_attr(feature = "std", error("Invalid SS58 prefix byte."))]
231 InvalidPrefix,
232 #[cfg_attr(feature = "std", error("Invalid SS58 format."))]
233 InvalidFormat,
234 #[cfg_attr(feature = "std", error("Invalid derivation path."))]
235 InvalidPath,
236 #[cfg_attr(feature = "std", error("Disallowed SS58 Address Format for this datatype."))]
237 FormatNotAllowed,
238 #[cfg_attr(feature = "std", error("Password not allowed."))]
239 PasswordNotAllowed,
240 #[cfg(feature = "std")]
241 #[cfg_attr(feature = "std", error("Incorrect URI syntax {0}."))]
242 MalformedUri(#[from] AddressUriError),
243}
244
245#[cfg(feature = "std")]
246impl core::fmt::Debug for PublicError {
247 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
248 write!(f, "{}", self)
250 }
251}
252
253pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray {
258 fn format_is_allowed(f: Ss58AddressFormat) -> bool {
261 !f.is_reserved()
262 }
263
264 #[cfg(feature = "serde")]
266 fn from_ss58check(s: &str) -> Result<Self, PublicError> {
267 Self::from_ss58check_with_version(s).and_then(|(r, v)| match v {
268 v if !v.is_custom() => Ok(r),
269 v if v == default_ss58_version() => Ok(r),
270 v => Err(PublicError::UnknownSs58AddressFormat(v)),
271 })
272 }
273
274 #[cfg(feature = "serde")]
276 fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
277 const CHECKSUM_LEN: usize = 2;
278 let body_len = Self::LEN;
279
280 let data = bs58::decode(s).into_vec().map_err(|_| PublicError::BadBase58)?;
281 if data.len() < 2 {
282 return Err(PublicError::BadLength)
283 }
284 let (prefix_len, ident) = match data[0] {
285 0..=63 => (1, data[0] as u16),
286 64..=127 => {
287 let lower = (data[0] << 2) | (data[1] >> 6);
293 let upper = data[1] & 0b00111111;
294 (2, (lower as u16) | ((upper as u16) << 8))
295 },
296 _ => return Err(PublicError::InvalidPrefix),
297 };
298 if data.len() != prefix_len + body_len + CHECKSUM_LEN {
299 return Err(PublicError::BadLength)
300 }
301 let format = ident.into();
302 if !Self::format_is_allowed(format) {
303 return Err(PublicError::FormatNotAllowed)
304 }
305
306 let hash = ss58hash(&data[0..body_len + prefix_len]);
307 let checksum = &hash[0..CHECKSUM_LEN];
308 if data[body_len + prefix_len..body_len + prefix_len + CHECKSUM_LEN] != *checksum {
309 return Err(PublicError::InvalidChecksum)
311 }
312
313 let result = Self::from_slice(&data[prefix_len..body_len + prefix_len])
314 .map_err(|()| PublicError::BadLength)?;
315 Ok((result, format))
316 }
317
318 #[cfg(feature = "std")]
321 fn from_string(s: &str) -> Result<Self, PublicError> {
322 Self::from_string_with_version(s).and_then(|(r, v)| match v {
323 v if !v.is_custom() => Ok(r),
324 v if v == default_ss58_version() => Ok(r),
325 v => Err(PublicError::UnknownSs58AddressFormat(v)),
326 })
327 }
328
329 #[cfg(feature = "serde")]
331 fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String {
332 let ident: u16 = u16::from(version) & 0b0011_1111_1111_1111;
334 let mut v = match ident {
335 0..=63 => vec![ident as u8],
336 64..=16_383 => {
337 let first = ((ident & 0b0000_0000_1111_1100) as u8) >> 2;
339 let second = ((ident >> 8) as u8) | ((ident & 0b0000_0000_0000_0011) as u8) << 6;
342 vec![first | 0b01000000, second]
343 },
344 _ => unreachable!("masked out the upper two bits; qed"),
345 };
346 v.extend(self.as_ref());
347 let r = ss58hash(&v);
348 v.extend(&r[0..2]);
349 bs58::encode(v).into_string()
350 }
351
352 #[cfg(feature = "serde")]
354 fn to_ss58check(&self) -> String {
355 self.to_ss58check_with_version(default_ss58_version())
356 }
357
358 #[cfg(feature = "std")]
361 fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
362 Self::from_ss58check_with_version(s)
363 }
364}
365
366pub trait Derive: Sized {
368 #[cfg(feature = "serde")]
372 fn derive<Iter: Iterator<Item = DeriveJunction>>(&self, _path: Iter) -> Option<Self> {
373 None
374 }
375}
376
377#[cfg(feature = "serde")]
378const PREFIX: &[u8] = b"SS58PRE";
379
380#[cfg(feature = "serde")]
381fn ss58hash(data: &[u8]) -> Vec<u8> {
382 use blake2::{Blake2b512, Digest};
383
384 let mut ctx = Blake2b512::new();
385 ctx.update(PREFIX);
386 ctx.update(data);
387 ctx.finalize().to_vec()
388}
389
390#[cfg(feature = "serde")]
392static DEFAULT_VERSION: core::sync::atomic::AtomicU16 = core::sync::atomic::AtomicU16::new(
393 from_known_address_format(Ss58AddressFormatRegistry::SubstrateAccount),
394);
395
396#[cfg(feature = "serde")]
398pub fn default_ss58_version() -> Ss58AddressFormat {
399 DEFAULT_VERSION.load(core::sync::atomic::Ordering::Relaxed).into()
400}
401
402#[cfg(feature = "serde")]
404pub fn unwrap_or_default_ss58_version(network: Option<Ss58AddressFormat>) -> Ss58AddressFormat {
405 network.unwrap_or_else(default_ss58_version)
406}
407
408#[cfg(feature = "serde")]
418pub fn set_default_ss58_version(new_default: Ss58AddressFormat) {
419 DEFAULT_VERSION.store(new_default.into(), core::sync::atomic::Ordering::Relaxed);
420}
421
422pub fn get_public_from_string_or_panic<TPublic: Public>(
426 s: &str,
427) -> <TPublic::Pair as Pair>::Public {
428 TPublic::Pair::from_string(&format!("//{}", s), None)
429 .expect("Function expects valid argument; qed")
430 .public()
431}
432
433#[cfg(feature = "std")]
434impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Public + Derive> Ss58Codec for T {
435 fn from_string(s: &str) -> Result<Self, PublicError> {
436 let cap = AddressUri::parse(s)?;
437 if cap.pass.is_some() {
438 return Err(PublicError::PasswordNotAllowed)
439 }
440 let s = cap.phrase.unwrap_or(DEV_ADDRESS);
441 let addr = if let Some(stripped) = s.strip_prefix("0x") {
442 let d = array_bytes::hex2bytes(stripped).map_err(|_| PublicError::InvalidFormat)?;
443 Self::from_slice(&d).map_err(|()| PublicError::BadLength)?
444 } else {
445 Self::from_ss58check(s)?
446 };
447 if cap.paths.is_empty() {
448 Ok(addr)
449 } else {
450 addr.derive(cap.paths.iter().map(DeriveJunction::from))
451 .ok_or(PublicError::InvalidPath)
452 }
453 }
454
455 fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
456 let cap = AddressUri::parse(s)?;
457 if cap.pass.is_some() {
458 return Err(PublicError::PasswordNotAllowed)
459 }
460 let (addr, v) = Self::from_ss58check_with_version(cap.phrase.unwrap_or(DEV_ADDRESS))?;
461 if cap.paths.is_empty() {
462 Ok((addr, v))
463 } else {
464 addr.derive(cap.paths.iter().map(DeriveJunction::from))
465 .ok_or(PublicError::InvalidPath)
466 .map(|a| (a, v))
467 }
468 }
469}
470
471#[cfg(all(not(feature = "std"), feature = "serde"))]
474impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Public + Derive> Ss58Codec for T {}
475
476pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8], Error = ()> {
478 const LEN: usize;
480
481 fn from_slice(data: &[u8]) -> Result<Self, ()> {
483 Self::try_from(data)
484 }
485
486 fn to_raw_vec(&self) -> Vec<u8> {
488 self.as_slice().to_vec()
489 }
490
491 fn as_slice(&self) -> &[u8] {
493 self.as_ref()
494 }
495}
496
497pub trait Public: CryptoType + ByteArray + PartialEq + Eq + Clone + Send + Sync + Derive {}
499
500pub trait Signature: CryptoType + ByteArray + PartialEq + Eq + Clone + Send + Sync {}
502
503#[derive(
505 Clone,
506 Eq,
507 PartialEq,
508 Ord,
509 PartialOrd,
510 Encode,
511 Decode,
512 DecodeWithMemTracking,
513 MaxEncodedLen,
514 TypeInfo,
515)]
516#[cfg_attr(feature = "std", derive(Hash))]
517pub struct AccountId32([u8; 32]);
518
519impl AccountId32 {
520 pub const fn new(inner: [u8; 32]) -> Self {
525 Self(inner)
526 }
527}
528
529impl UncheckedFrom<crate::hash::H256> for AccountId32 {
530 fn unchecked_from(h: crate::hash::H256) -> Self {
531 AccountId32(h.into())
532 }
533}
534
535impl ByteArray for AccountId32 {
536 const LEN: usize = 32;
537}
538
539#[cfg(feature = "serde")]
540impl Ss58Codec for AccountId32 {}
541
542impl AsRef<[u8]> for AccountId32 {
543 fn as_ref(&self) -> &[u8] {
544 &self.0[..]
545 }
546}
547
548impl AsMut<[u8]> for AccountId32 {
549 fn as_mut(&mut self) -> &mut [u8] {
550 &mut self.0[..]
551 }
552}
553
554impl AsRef<[u8; 32]> for AccountId32 {
555 fn as_ref(&self) -> &[u8; 32] {
556 &self.0
557 }
558}
559
560impl AsMut<[u8; 32]> for AccountId32 {
561 fn as_mut(&mut self) -> &mut [u8; 32] {
562 &mut self.0
563 }
564}
565
566impl From<[u8; 32]> for AccountId32 {
567 fn from(x: [u8; 32]) -> Self {
568 Self::new(x)
569 }
570}
571
572impl<'a> TryFrom<&'a [u8]> for AccountId32 {
573 type Error = ();
574 fn try_from(x: &'a [u8]) -> Result<AccountId32, ()> {
575 if x.len() == 32 {
576 let mut data = [0; 32];
577 data.copy_from_slice(x);
578 Ok(AccountId32(data))
579 } else {
580 Err(())
581 }
582 }
583}
584
585impl From<AccountId32> for [u8; 32] {
586 fn from(x: AccountId32) -> [u8; 32] {
587 x.0
588 }
589}
590
591impl From<sr25519::Public> for AccountId32 {
592 fn from(k: sr25519::Public) -> Self {
593 k.0.into()
594 }
595}
596
597impl From<ed25519::Public> for AccountId32 {
598 fn from(k: ed25519::Public) -> Self {
599 k.0.into()
600 }
601}
602
603#[cfg(feature = "std")]
604impl std::fmt::Display for AccountId32 {
605 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
606 write!(f, "{}", self.to_ss58check())
607 }
608}
609
610impl core::fmt::Debug for AccountId32 {
611 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
612 #[cfg(feature = "serde")]
613 {
614 let s = self.to_ss58check();
615 write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])?;
616 }
617
618 #[cfg(not(feature = "serde"))]
619 write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))?;
620
621 Ok(())
622 }
623}
624
625#[cfg(feature = "serde")]
626impl serde::Serialize for AccountId32 {
627 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
628 where
629 S: serde::Serializer,
630 {
631 serializer.serialize_str(&self.to_ss58check())
632 }
633}
634
635#[cfg(feature = "serde")]
636impl<'de> serde::Deserialize<'de> for AccountId32 {
637 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
638 where
639 D: serde::Deserializer<'de>,
640 {
641 Ss58Codec::from_ss58check(&String::deserialize(deserializer)?)
642 .map_err(|e| serde::de::Error::custom(format!("{:?}", e)))
643 }
644}
645
646#[cfg(feature = "std")]
647impl std::str::FromStr for AccountId32 {
648 type Err = &'static str;
649
650 fn from_str(s: &str) -> Result<Self, Self::Err> {
651 let hex_or_ss58_without_prefix = s.trim_start_matches("0x");
652 if hex_or_ss58_without_prefix.len() == 64 {
653 array_bytes::hex_n_into(hex_or_ss58_without_prefix).map_err(|_| "invalid hex address.")
654 } else {
655 Self::from_ss58check(s).map_err(|_| "invalid ss58 address.")
656 }
657 }
658}
659
660impl FromEntropy for AccountId32 {
662 fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
663 Ok(AccountId32::new(FromEntropy::from_entropy(input)?))
664 }
665}
666
667#[cfg(feature = "std")]
668pub use self::dummy::*;
669
670#[cfg(feature = "std")]
671mod dummy {
672 use super::*;
673
674 #[doc(hidden)]
675 pub struct DummyTag;
676
677 pub type Dummy = CryptoBytes<0, DummyTag>;
679
680 impl CryptoType for Dummy {
681 type Pair = Dummy;
682 }
683
684 impl Derive for Dummy {}
685
686 impl Public for Dummy {}
687
688 impl Signature for Dummy {}
689
690 impl Pair for Dummy {
691 type Public = Dummy;
692 type Seed = Dummy;
693 type Signature = Dummy;
694
695 #[cfg(feature = "std")]
696 fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) {
697 Default::default()
698 }
699
700 #[cfg(feature = "std")]
701 fn from_phrase(_: &str, _: Option<&str>) -> Result<(Self, Self::Seed), SecretStringError> {
702 Ok(Default::default())
703 }
704
705 fn derive<Iter: Iterator<Item = DeriveJunction>>(
706 &self,
707 _: Iter,
708 _: Option<Dummy>,
709 ) -> Result<(Self, Option<Dummy>), DeriveError> {
710 Ok((Self::default(), None))
711 }
712
713 fn from_seed_slice(_: &[u8]) -> Result<Self, SecretStringError> {
714 Ok(Self::default())
715 }
716
717 fn sign(&self, _: &[u8]) -> Self::Signature {
718 Self::default()
719 }
720
721 fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool {
722 true
723 }
724
725 fn public(&self) -> Self::Public {
726 Self::default()
727 }
728
729 fn to_raw_vec(&self) -> Vec<u8> {
730 Default::default()
731 }
732 }
733}
734
735pub struct SecretUri {
799 pub phrase: SecretString,
803 pub password: Option<SecretString>,
805 pub junctions: Vec<DeriveJunction>,
807}
808
809impl alloc::str::FromStr for SecretUri {
810 type Err = SecretStringError;
811
812 fn from_str(s: &str) -> Result<Self, Self::Err> {
813 let cap = AddressUri::parse(s)?;
814 let phrase = cap.phrase.unwrap_or(DEV_PHRASE);
815
816 Ok(Self {
817 phrase: SecretString::from_str(phrase).expect("Returns infallible error; qed"),
818 password: cap
819 .pass
820 .map(|v| SecretString::from_str(v).expect("Returns infallible error; qed")),
821 junctions: cap.paths.iter().map(DeriveJunction::from).collect::<Vec<_>>(),
822 })
823 }
824}
825
826pub trait Pair: CryptoType + Sized {
830 type Public: Public + Hash;
832
833 type Seed: Default + AsRef<[u8]> + AsMut<[u8]> + Clone;
836
837 type Signature: Signature;
840
841 #[cfg(feature = "std")]
846 fn generate() -> (Self, Self::Seed) {
847 let mut seed = Self::Seed::default();
848 OsRng.fill_bytes(seed.as_mut());
849 (Self::from_seed(&seed), seed)
850 }
851
852 #[cfg(feature = "std")]
859 fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) {
860 let mnemonic = Mnemonic::generate(12).expect("Mnemonic generation always works; qed");
861 let phrase = mnemonic.words().join(" ");
862 let (pair, seed) = Self::from_phrase(&phrase, password)
863 .expect("All phrases generated by Mnemonic are valid; qed");
864 (pair, phrase.to_owned(), seed)
865 }
866
867 fn from_phrase(
869 phrase: &str,
870 password: Option<&str>,
871 ) -> Result<(Self, Self::Seed), SecretStringError> {
872 let mnemonic = Mnemonic::parse_in(Language::English, phrase)
873 .map_err(|_| SecretStringError::InvalidPhrase)?;
874 let (entropy, entropy_len) = mnemonic.to_entropy_array();
875 let big_seed =
876 substrate_bip39::seed_from_entropy(&entropy[0..entropy_len], password.unwrap_or(""))
877 .map_err(|_| SecretStringError::InvalidSeed)?;
878 let mut seed = Self::Seed::default();
879 let seed_slice = seed.as_mut();
880 let seed_len = seed_slice.len();
881 debug_assert!(seed_len <= big_seed.len());
882 seed_slice[..seed_len].copy_from_slice(&big_seed[..seed_len]);
883 Self::from_seed_slice(seed_slice).map(|x| (x, seed))
884 }
885
886 fn derive<Iter: Iterator<Item = DeriveJunction>>(
888 &self,
889 path: Iter,
890 seed: Option<Self::Seed>,
891 ) -> Result<(Self, Option<Self::Seed>), DeriveError>;
892
893 fn from_seed(seed: &Self::Seed) -> Self {
898 Self::from_seed_slice(seed.as_ref()).expect("seed has valid length; qed")
899 }
900
901 fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError>;
907
908 #[cfg(feature = "full_crypto")]
910 fn sign(&self, message: &[u8]) -> Self::Signature;
911
912 fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool;
914
915 fn public(&self) -> Self::Public;
917
918 fn from_string_with_seed(
945 s: &str,
946 password_override: Option<&str>,
947 ) -> Result<(Self, Option<Self::Seed>), SecretStringError> {
948 use alloc::str::FromStr;
949 let SecretUri { junctions, phrase, password } = SecretUri::from_str(s)?;
950 let password =
951 password_override.or_else(|| password.as_ref().map(|p| p.expose_secret().as_str()));
952
953 let (root, seed) = if let Some(stripped) = phrase.expose_secret().strip_prefix("0x") {
954 array_bytes::hex2bytes(stripped)
955 .ok()
956 .and_then(|seed_vec| {
957 let mut seed = Self::Seed::default();
958 if seed.as_ref().len() == seed_vec.len() {
959 seed.as_mut().copy_from_slice(&seed_vec);
960 Some((Self::from_seed(&seed), seed))
961 } else {
962 None
963 }
964 })
965 .ok_or(SecretStringError::InvalidSeed)?
966 } else {
967 Self::from_phrase(phrase.expose_secret().as_str(), password)
968 .map_err(|_| SecretStringError::InvalidPhrase)?
969 };
970 root.derive(junctions.into_iter(), Some(seed))
971 .map_err(|_| SecretStringError::InvalidPath)
972 }
973
974 fn from_string(s: &str, password_override: Option<&str>) -> Result<Self, SecretStringError> {
978 Self::from_string_with_seed(s, password_override).map(|x| x.0)
979 }
980
981 fn to_raw_vec(&self) -> Vec<u8>;
983}
984
985pub trait IsWrappedBy<Outer>: From<Outer> + Into<Outer> {
987 fn from_ref(outer: &Outer) -> &Self;
989 fn from_mut(outer: &mut Outer) -> &mut Self;
991}
992
993pub trait Wraps: Sized {
995 type Inner: IsWrappedBy<Self>;
997
998 fn as_inner_ref(&self) -> &Self::Inner {
1000 Self::Inner::from_ref(self)
1001 }
1002}
1003
1004impl<T, Outer> IsWrappedBy<Outer> for T
1005where
1006 Outer: AsRef<Self> + AsMut<Self> + From<Self>,
1007 T: From<Outer>,
1008{
1009 fn from_ref(outer: &Outer) -> &Self {
1011 outer.as_ref()
1012 }
1013
1014 fn from_mut(outer: &mut Outer) -> &mut Self {
1016 outer.as_mut()
1017 }
1018}
1019
1020impl<Inner, Outer, T> UncheckedFrom<T> for Outer
1021where
1022 Outer: Wraps<Inner = Inner>,
1023 Inner: IsWrappedBy<Outer> + UncheckedFrom<T>,
1024{
1025 fn unchecked_from(t: T) -> Self {
1026 let inner: Inner = t.unchecked_into();
1027 inner.into()
1028 }
1029}
1030
1031pub trait CryptoType {
1033 type Pair: Pair;
1035}
1036
1037#[derive(
1045 Copy,
1046 Clone,
1047 Default,
1048 PartialEq,
1049 Eq,
1050 PartialOrd,
1051 Ord,
1052 Hash,
1053 Encode,
1054 Decode,
1055 PassByInner,
1056 crate::RuntimeDebug,
1057 TypeInfo,
1058)]
1059#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1060pub struct KeyTypeId(pub [u8; 4]);
1061
1062impl From<u32> for KeyTypeId {
1063 fn from(x: u32) -> Self {
1064 Self(x.to_le_bytes())
1065 }
1066}
1067
1068impl From<KeyTypeId> for u32 {
1069 fn from(x: KeyTypeId) -> Self {
1070 u32::from_le_bytes(x.0)
1071 }
1072}
1073
1074impl<'a> TryFrom<&'a str> for KeyTypeId {
1075 type Error = ();
1076
1077 fn try_from(x: &'a str) -> Result<Self, ()> {
1078 let b = x.as_bytes();
1079 if b.len() != 4 {
1080 return Err(())
1081 }
1082 let mut res = KeyTypeId::default();
1083 res.0.copy_from_slice(&b[0..4]);
1084 Ok(res)
1085 }
1086}
1087
1088pub trait VrfCrypto {
1090 type VrfInput;
1092 type VrfPreOutput;
1094 type VrfSignData;
1096 type VrfSignature;
1098}
1099
1100pub trait VrfSecret: VrfCrypto {
1102 fn vrf_pre_output(&self, data: &Self::VrfInput) -> Self::VrfPreOutput;
1104
1105 fn vrf_sign(&self, input: &Self::VrfSignData) -> Self::VrfSignature;
1107}
1108
1109pub trait VrfPublic: VrfCrypto {
1111 fn vrf_verify(&self, data: &Self::VrfSignData, signature: &Self::VrfSignature) -> bool;
1113}
1114
1115#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
1117#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1118pub struct CryptoTypeId(pub [u8; 4]);
1119
1120pub mod key_types {
1126 use super::KeyTypeId;
1127
1128 pub const BABE: KeyTypeId = KeyTypeId(*b"babe");
1130 pub const SASSAFRAS: KeyTypeId = KeyTypeId(*b"sass");
1132 pub const GRANDPA: KeyTypeId = KeyTypeId(*b"gran");
1134 pub const ACCOUNT: KeyTypeId = KeyTypeId(*b"acco");
1136 pub const AURA: KeyTypeId = KeyTypeId(*b"aura");
1138 pub const BEEFY: KeyTypeId = KeyTypeId(*b"beef");
1140 pub const IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon");
1142 pub const AUTHORITY_DISCOVERY: KeyTypeId = KeyTypeId(*b"audi");
1144 pub const STAKING: KeyTypeId = KeyTypeId(*b"stak");
1146 pub const STATEMENT: KeyTypeId = KeyTypeId(*b"stmt");
1148 pub const MIXNET: KeyTypeId = KeyTypeId(*b"mixn");
1150 pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy");
1152}
1153
1154pub trait FromEntropy: Sized {
1156 fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error>;
1159}
1160
1161impl FromEntropy for bool {
1162 fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
1163 Ok(input.read_byte()? % 2 == 1)
1164 }
1165}
1166
1167impl FromEntropy for () {
1169 fn from_entropy(_: &mut impl codec::Input) -> Result<Self, codec::Error> {
1170 Ok(())
1171 }
1172}
1173
1174macro_rules! impl_from_entropy {
1175 ($type:ty , $( $others:tt )*) => {
1176 impl_from_entropy!($type);
1177 impl_from_entropy!($( $others )*);
1178 };
1179 ($type:ty) => {
1180 impl FromEntropy for $type {
1181 fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
1182 <Self as codec::Decode>::decode(input)
1183 }
1184 }
1185 }
1186}
1187
1188macro_rules! impl_from_entropy_base {
1189 ($type:ty , $( $others:tt )*) => {
1190 impl_from_entropy_base!($type);
1191 impl_from_entropy_base!($( $others )*);
1192 };
1193 ($type:ty) => {
1194 impl_from_entropy!($type,
1195 [$type; 1], [$type; 2], [$type; 3], [$type; 4], [$type; 5], [$type; 6], [$type; 7], [$type; 8],
1196 [$type; 9], [$type; 10], [$type; 11], [$type; 12], [$type; 13], [$type; 14], [$type; 15], [$type; 16],
1197 [$type; 17], [$type; 18], [$type; 19], [$type; 20], [$type; 21], [$type; 22], [$type; 23], [$type; 24],
1198 [$type; 25], [$type; 26], [$type; 27], [$type; 28], [$type; 29], [$type; 30], [$type; 31], [$type; 32],
1199 [$type; 36], [$type; 40], [$type; 44], [$type; 48], [$type; 56], [$type; 64], [$type; 72], [$type; 80],
1200 [$type; 96], [$type; 112], [$type; 128], [$type; 160], [$type; 177], [$type; 192], [$type; 224], [$type; 256]
1201 );
1202 }
1203}
1204
1205impl_from_entropy_base!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, U256);
1206
1207#[cfg(test)]
1208mod tests {
1209 use super::*;
1210 use crate::DeriveJunction;
1211
1212 struct TestCryptoTag;
1213
1214 #[derive(Clone, Eq, PartialEq, Debug)]
1215 enum TestPair {
1216 Generated,
1217 GeneratedWithPhrase,
1218 GeneratedFromPhrase { phrase: String, password: Option<String> },
1219 Standard { phrase: String, password: Option<String>, path: Vec<DeriveJunction> },
1220 Seed(Vec<u8>),
1221 }
1222
1223 impl Default for TestPair {
1224 fn default() -> Self {
1225 TestPair::Generated
1226 }
1227 }
1228
1229 impl CryptoType for TestPair {
1230 type Pair = Self;
1231 }
1232
1233 type TestPublic = PublicBytes<0, TestCryptoTag>;
1234
1235 impl CryptoType for TestPublic {
1236 type Pair = TestPair;
1237 }
1238
1239 type TestSignature = SignatureBytes<0, TestCryptoTag>;
1240
1241 impl CryptoType for TestSignature {
1242 type Pair = TestPair;
1243 }
1244
1245 impl Pair for TestPair {
1246 type Public = TestPublic;
1247 type Seed = [u8; 8];
1248 type Signature = TestSignature;
1249
1250 fn generate() -> (Self, <Self as Pair>::Seed) {
1251 (TestPair::Generated, [0u8; 8])
1252 }
1253
1254 fn generate_with_phrase(_password: Option<&str>) -> (Self, String, <Self as Pair>::Seed) {
1255 (TestPair::GeneratedWithPhrase, "".into(), [0u8; 8])
1256 }
1257
1258 fn from_phrase(
1259 phrase: &str,
1260 password: Option<&str>,
1261 ) -> Result<(Self, <Self as Pair>::Seed), SecretStringError> {
1262 Ok((
1263 TestPair::GeneratedFromPhrase {
1264 phrase: phrase.to_owned(),
1265 password: password.map(Into::into),
1266 },
1267 [0u8; 8],
1268 ))
1269 }
1270
1271 fn derive<Iter: Iterator<Item = DeriveJunction>>(
1272 &self,
1273 path_iter: Iter,
1274 _: Option<[u8; 8]>,
1275 ) -> Result<(Self, Option<[u8; 8]>), DeriveError> {
1276 Ok((
1277 match self.clone() {
1278 TestPair::Standard { phrase, password, path } => TestPair::Standard {
1279 phrase,
1280 password,
1281 path: path.into_iter().chain(path_iter).collect(),
1282 },
1283 TestPair::GeneratedFromPhrase { phrase, password } =>
1284 TestPair::Standard { phrase, password, path: path_iter.collect() },
1285 x =>
1286 if path_iter.count() == 0 {
1287 x
1288 } else {
1289 return Err(DeriveError::SoftKeyInPath)
1290 },
1291 },
1292 None,
1293 ))
1294 }
1295
1296 fn sign(&self, _message: &[u8]) -> Self::Signature {
1297 TestSignature::default()
1298 }
1299
1300 fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool {
1301 true
1302 }
1303
1304 fn public(&self) -> Self::Public {
1305 TestPublic::default()
1306 }
1307
1308 fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError> {
1309 Ok(TestPair::Seed(seed.to_owned()))
1310 }
1311
1312 fn to_raw_vec(&self) -> Vec<u8> {
1313 vec![]
1314 }
1315 }
1316
1317 #[test]
1318 fn interpret_std_seed_should_work() {
1319 assert_eq!(
1320 TestPair::from_string("0x0123456789abcdef", None),
1321 Ok(TestPair::Seed(array_bytes::hex2bytes_unchecked("0123456789abcdef")))
1322 );
1323 }
1324
1325 #[test]
1326 fn password_override_should_work() {
1327 assert_eq!(
1328 TestPair::from_string("hello world///password", None),
1329 TestPair::from_string("hello world", Some("password")),
1330 );
1331 assert_eq!(
1332 TestPair::from_string("hello world///password", None),
1333 TestPair::from_string("hello world///other password", Some("password")),
1334 );
1335 }
1336
1337 #[test]
1338 fn interpret_std_secret_string_should_work() {
1339 assert_eq!(
1340 TestPair::from_string("hello world", None),
1341 Ok(TestPair::Standard {
1342 phrase: "hello world".to_owned(),
1343 password: None,
1344 path: vec![]
1345 })
1346 );
1347 assert_eq!(
1348 TestPair::from_string("hello world/1", None),
1349 Ok(TestPair::Standard {
1350 phrase: "hello world".to_owned(),
1351 password: None,
1352 path: vec![DeriveJunction::soft(1)]
1353 })
1354 );
1355 assert_eq!(
1356 TestPair::from_string("hello world/DOT", None),
1357 Ok(TestPair::Standard {
1358 phrase: "hello world".to_owned(),
1359 password: None,
1360 path: vec![DeriveJunction::soft("DOT")]
1361 })
1362 );
1363 assert_eq!(
1364 TestPair::from_string("hello world/0123456789012345678901234567890123456789", None),
1365 Ok(TestPair::Standard {
1366 phrase: "hello world".to_owned(),
1367 password: None,
1368 path: vec![DeriveJunction::soft("0123456789012345678901234567890123456789")]
1369 })
1370 );
1371 assert_eq!(
1372 TestPair::from_string("hello world//1", None),
1373 Ok(TestPair::Standard {
1374 phrase: "hello world".to_owned(),
1375 password: None,
1376 path: vec![DeriveJunction::hard(1)]
1377 })
1378 );
1379 assert_eq!(
1380 TestPair::from_string("hello world//DOT", None),
1381 Ok(TestPair::Standard {
1382 phrase: "hello world".to_owned(),
1383 password: None,
1384 path: vec![DeriveJunction::hard("DOT")]
1385 })
1386 );
1387 assert_eq!(
1388 TestPair::from_string("hello world//0123456789012345678901234567890123456789", None),
1389 Ok(TestPair::Standard {
1390 phrase: "hello world".to_owned(),
1391 password: None,
1392 path: vec![DeriveJunction::hard("0123456789012345678901234567890123456789")]
1393 })
1394 );
1395 assert_eq!(
1396 TestPair::from_string("hello world//1/DOT", None),
1397 Ok(TestPair::Standard {
1398 phrase: "hello world".to_owned(),
1399 password: None,
1400 path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]
1401 })
1402 );
1403 assert_eq!(
1404 TestPair::from_string("hello world//DOT/1", None),
1405 Ok(TestPair::Standard {
1406 phrase: "hello world".to_owned(),
1407 password: None,
1408 path: vec![DeriveJunction::hard("DOT"), DeriveJunction::soft(1)]
1409 })
1410 );
1411 assert_eq!(
1412 TestPair::from_string("hello world///password", None),
1413 Ok(TestPair::Standard {
1414 phrase: "hello world".to_owned(),
1415 password: Some("password".to_owned()),
1416 path: vec![]
1417 })
1418 );
1419 assert_eq!(
1420 TestPair::from_string("hello world//1/DOT///password", None),
1421 Ok(TestPair::Standard {
1422 phrase: "hello world".to_owned(),
1423 password: Some("password".to_owned()),
1424 path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]
1425 })
1426 );
1427 assert_eq!(
1428 TestPair::from_string("hello world/1//DOT///password", None),
1429 Ok(TestPair::Standard {
1430 phrase: "hello world".to_owned(),
1431 password: Some("password".to_owned()),
1432 path: vec![DeriveJunction::soft(1), DeriveJunction::hard("DOT")]
1433 })
1434 );
1435 }
1436
1437 #[test]
1438 fn accountid_32_from_str_works() {
1439 use std::str::FromStr;
1440 assert!(AccountId32::from_str("5G9VdMwXvzza9pS8qE8ZHJk3CheHW9uucBn9ngW4C1gmmzpv").is_ok());
1441 assert!(AccountId32::from_str(
1442 "5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1443 )
1444 .is_ok());
1445 assert!(AccountId32::from_str(
1446 "0x5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1447 )
1448 .is_ok());
1449
1450 assert_eq!(
1451 AccountId32::from_str("99G9VdMwXvzza9pS8qE8ZHJk3CheHW9uucBn9ngW4C1gmmzpv").unwrap_err(),
1452 "invalid ss58 address.",
1453 );
1454 assert_eq!(
1455 AccountId32::from_str(
1456 "gc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1457 )
1458 .unwrap_err(),
1459 "invalid hex address.",
1460 );
1461 assert_eq!(
1462 AccountId32::from_str(
1463 "0xgc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1464 )
1465 .unwrap_err(),
1466 "invalid hex address.",
1467 );
1468
1469 assert_eq!(
1471 AccountId32::from_str(
1472 "55c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1473 )
1474 .unwrap_err(),
1475 "invalid ss58 address.",
1476 );
1477 }
1478}