1use crate::{ed25519, sr25519};
21#[cfg(all(not(feature = "std"), feature = "serde"))]
22use alloc::{format, string::String, vec};
23use alloc::{str, vec::Vec};
24use bip39::{Language, Mnemonic};
25use codec::{Decode, 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
422#[cfg(feature = "std")]
423impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Public + Derive> Ss58Codec for T {
424 fn from_string(s: &str) -> Result<Self, PublicError> {
425 let cap = AddressUri::parse(s)?;
426 if cap.pass.is_some() {
427 return Err(PublicError::PasswordNotAllowed)
428 }
429 let s = cap.phrase.unwrap_or(DEV_ADDRESS);
430 let addr = if let Some(stripped) = s.strip_prefix("0x") {
431 let d = array_bytes::hex2bytes(stripped).map_err(|_| PublicError::InvalidFormat)?;
432 Self::from_slice(&d).map_err(|()| PublicError::BadLength)?
433 } else {
434 Self::from_ss58check(s)?
435 };
436 if cap.paths.is_empty() {
437 Ok(addr)
438 } else {
439 addr.derive(cap.paths.iter().map(DeriveJunction::from))
440 .ok_or(PublicError::InvalidPath)
441 }
442 }
443
444 fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
445 let cap = AddressUri::parse(s)?;
446 if cap.pass.is_some() {
447 return Err(PublicError::PasswordNotAllowed)
448 }
449 let (addr, v) = Self::from_ss58check_with_version(cap.phrase.unwrap_or(DEV_ADDRESS))?;
450 if cap.paths.is_empty() {
451 Ok((addr, v))
452 } else {
453 addr.derive(cap.paths.iter().map(DeriveJunction::from))
454 .ok_or(PublicError::InvalidPath)
455 .map(|a| (a, v))
456 }
457 }
458}
459
460#[cfg(all(not(feature = "std"), feature = "serde"))]
463impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Public + Derive> Ss58Codec for T {}
464
465pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8], Error = ()> {
467 const LEN: usize;
469
470 fn from_slice(data: &[u8]) -> Result<Self, ()> {
472 Self::try_from(data)
473 }
474
475 fn to_raw_vec(&self) -> Vec<u8> {
477 self.as_slice().to_vec()
478 }
479
480 fn as_slice(&self) -> &[u8] {
482 self.as_ref()
483 }
484}
485
486pub trait Public: CryptoType + ByteArray + PartialEq + Eq + Clone + Send + Sync + Derive {}
488
489pub trait Signature: CryptoType + ByteArray + PartialEq + Eq + Clone + Send + Sync {}
491
492#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo)]
494#[cfg_attr(feature = "std", derive(Hash))]
495pub struct AccountId32([u8; 32]);
496
497impl AccountId32 {
498 pub const fn new(inner: [u8; 32]) -> Self {
503 Self(inner)
504 }
505}
506
507impl UncheckedFrom<crate::hash::H256> for AccountId32 {
508 fn unchecked_from(h: crate::hash::H256) -> Self {
509 AccountId32(h.into())
510 }
511}
512
513impl ByteArray for AccountId32 {
514 const LEN: usize = 32;
515}
516
517#[cfg(feature = "serde")]
518impl Ss58Codec for AccountId32 {}
519
520impl AsRef<[u8]> for AccountId32 {
521 fn as_ref(&self) -> &[u8] {
522 &self.0[..]
523 }
524}
525
526impl AsMut<[u8]> for AccountId32 {
527 fn as_mut(&mut self) -> &mut [u8] {
528 &mut self.0[..]
529 }
530}
531
532impl AsRef<[u8; 32]> for AccountId32 {
533 fn as_ref(&self) -> &[u8; 32] {
534 &self.0
535 }
536}
537
538impl AsMut<[u8; 32]> for AccountId32 {
539 fn as_mut(&mut self) -> &mut [u8; 32] {
540 &mut self.0
541 }
542}
543
544impl From<[u8; 32]> for AccountId32 {
545 fn from(x: [u8; 32]) -> Self {
546 Self::new(x)
547 }
548}
549
550impl<'a> TryFrom<&'a [u8]> for AccountId32 {
551 type Error = ();
552 fn try_from(x: &'a [u8]) -> Result<AccountId32, ()> {
553 if x.len() == 32 {
554 let mut data = [0; 32];
555 data.copy_from_slice(x);
556 Ok(AccountId32(data))
557 } else {
558 Err(())
559 }
560 }
561}
562
563impl From<AccountId32> for [u8; 32] {
564 fn from(x: AccountId32) -> [u8; 32] {
565 x.0
566 }
567}
568
569impl From<sr25519::Public> for AccountId32 {
570 fn from(k: sr25519::Public) -> Self {
571 k.0.into()
572 }
573}
574
575impl From<ed25519::Public> for AccountId32 {
576 fn from(k: ed25519::Public) -> Self {
577 k.0.into()
578 }
579}
580
581#[cfg(feature = "std")]
582impl std::fmt::Display for AccountId32 {
583 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
584 write!(f, "{}", self.to_ss58check())
585 }
586}
587
588impl core::fmt::Debug for AccountId32 {
589 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
590 #[cfg(feature = "serde")]
591 {
592 let s = self.to_ss58check();
593 write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])?;
594 }
595
596 #[cfg(not(feature = "serde"))]
597 write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))?;
598
599 Ok(())
600 }
601}
602
603#[cfg(feature = "serde")]
604impl serde::Serialize for AccountId32 {
605 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
606 where
607 S: serde::Serializer,
608 {
609 serializer.serialize_str(&self.to_ss58check())
610 }
611}
612
613#[cfg(feature = "serde")]
614impl<'de> serde::Deserialize<'de> for AccountId32 {
615 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
616 where
617 D: serde::Deserializer<'de>,
618 {
619 Ss58Codec::from_ss58check(&String::deserialize(deserializer)?)
620 .map_err(|e| serde::de::Error::custom(format!("{:?}", e)))
621 }
622}
623
624#[cfg(feature = "std")]
625impl std::str::FromStr for AccountId32 {
626 type Err = &'static str;
627
628 fn from_str(s: &str) -> Result<Self, Self::Err> {
629 let hex_or_ss58_without_prefix = s.trim_start_matches("0x");
630 if hex_or_ss58_without_prefix.len() == 64 {
631 array_bytes::hex_n_into(hex_or_ss58_without_prefix).map_err(|_| "invalid hex address.")
632 } else {
633 Self::from_ss58check(s).map_err(|_| "invalid ss58 address.")
634 }
635 }
636}
637
638impl FromEntropy for AccountId32 {
640 fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
641 Ok(AccountId32::new(FromEntropy::from_entropy(input)?))
642 }
643}
644
645#[cfg(feature = "std")]
646pub use self::dummy::*;
647
648#[cfg(feature = "std")]
649mod dummy {
650 use super::*;
651
652 #[doc(hidden)]
653 pub struct DummyTag;
654
655 pub type Dummy = CryptoBytes<0, DummyTag>;
657
658 impl CryptoType for Dummy {
659 type Pair = Dummy;
660 }
661
662 impl Derive for Dummy {}
663
664 impl Public for Dummy {}
665
666 impl Signature for Dummy {}
667
668 impl Pair for Dummy {
669 type Public = Dummy;
670 type Seed = Dummy;
671 type Signature = Dummy;
672
673 #[cfg(feature = "std")]
674 fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) {
675 Default::default()
676 }
677
678 #[cfg(feature = "std")]
679 fn from_phrase(_: &str, _: Option<&str>) -> Result<(Self, Self::Seed), SecretStringError> {
680 Ok(Default::default())
681 }
682
683 fn derive<Iter: Iterator<Item = DeriveJunction>>(
684 &self,
685 _: Iter,
686 _: Option<Dummy>,
687 ) -> Result<(Self, Option<Dummy>), DeriveError> {
688 Ok((Self::default(), None))
689 }
690
691 fn from_seed_slice(_: &[u8]) -> Result<Self, SecretStringError> {
692 Ok(Self::default())
693 }
694
695 fn sign(&self, _: &[u8]) -> Self::Signature {
696 Self::default()
697 }
698
699 fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool {
700 true
701 }
702
703 fn public(&self) -> Self::Public {
704 Self::default()
705 }
706
707 fn to_raw_vec(&self) -> Vec<u8> {
708 Default::default()
709 }
710 }
711}
712
713pub struct SecretUri {
777 pub phrase: SecretString,
781 pub password: Option<SecretString>,
783 pub junctions: Vec<DeriveJunction>,
785}
786
787impl alloc::str::FromStr for SecretUri {
788 type Err = SecretStringError;
789
790 fn from_str(s: &str) -> Result<Self, Self::Err> {
791 let cap = AddressUri::parse(s)?;
792 let phrase = cap.phrase.unwrap_or(DEV_PHRASE);
793
794 Ok(Self {
795 phrase: SecretString::from_str(phrase).expect("Returns infallible error; qed"),
796 password: cap
797 .pass
798 .map(|v| SecretString::from_str(v).expect("Returns infallible error; qed")),
799 junctions: cap.paths.iter().map(DeriveJunction::from).collect::<Vec<_>>(),
800 })
801 }
802}
803
804pub trait Pair: CryptoType + Sized {
808 type Public: Public + Hash;
810
811 type Seed: Default + AsRef<[u8]> + AsMut<[u8]> + Clone;
814
815 type Signature: Signature;
818
819 #[cfg(feature = "std")]
824 fn generate() -> (Self, Self::Seed) {
825 let mut seed = Self::Seed::default();
826 OsRng.fill_bytes(seed.as_mut());
827 (Self::from_seed(&seed), seed)
828 }
829
830 #[cfg(feature = "std")]
837 fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) {
838 let mnemonic = Mnemonic::generate(12).expect("Mnemonic generation always works; qed");
839 let phrase = mnemonic.words().join(" ");
840 let (pair, seed) = Self::from_phrase(&phrase, password)
841 .expect("All phrases generated by Mnemonic are valid; qed");
842 (pair, phrase.to_owned(), seed)
843 }
844
845 fn from_phrase(
847 phrase: &str,
848 password: Option<&str>,
849 ) -> Result<(Self, Self::Seed), SecretStringError> {
850 let mnemonic = Mnemonic::parse_in(Language::English, phrase)
851 .map_err(|_| SecretStringError::InvalidPhrase)?;
852 let (entropy, entropy_len) = mnemonic.to_entropy_array();
853 let big_seed =
854 substrate_bip39::seed_from_entropy(&entropy[0..entropy_len], password.unwrap_or(""))
855 .map_err(|_| SecretStringError::InvalidSeed)?;
856 let mut seed = Self::Seed::default();
857 let seed_slice = seed.as_mut();
858 let seed_len = seed_slice.len();
859 debug_assert!(seed_len <= big_seed.len());
860 seed_slice[..seed_len].copy_from_slice(&big_seed[..seed_len]);
861 Self::from_seed_slice(seed_slice).map(|x| (x, seed))
862 }
863
864 fn derive<Iter: Iterator<Item = DeriveJunction>>(
866 &self,
867 path: Iter,
868 seed: Option<Self::Seed>,
869 ) -> Result<(Self, Option<Self::Seed>), DeriveError>;
870
871 fn from_seed(seed: &Self::Seed) -> Self {
876 Self::from_seed_slice(seed.as_ref()).expect("seed has valid length; qed")
877 }
878
879 fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError>;
885
886 #[cfg(feature = "full_crypto")]
888 fn sign(&self, message: &[u8]) -> Self::Signature;
889
890 fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool;
892
893 fn public(&self) -> Self::Public;
895
896 fn from_string_with_seed(
923 s: &str,
924 password_override: Option<&str>,
925 ) -> Result<(Self, Option<Self::Seed>), SecretStringError> {
926 use alloc::str::FromStr;
927 let SecretUri { junctions, phrase, password } = SecretUri::from_str(s)?;
928 let password =
929 password_override.or_else(|| password.as_ref().map(|p| p.expose_secret().as_str()));
930
931 let (root, seed) = if let Some(stripped) = phrase.expose_secret().strip_prefix("0x") {
932 array_bytes::hex2bytes(stripped)
933 .ok()
934 .and_then(|seed_vec| {
935 let mut seed = Self::Seed::default();
936 if seed.as_ref().len() == seed_vec.len() {
937 seed.as_mut().copy_from_slice(&seed_vec);
938 Some((Self::from_seed(&seed), seed))
939 } else {
940 None
941 }
942 })
943 .ok_or(SecretStringError::InvalidSeed)?
944 } else {
945 Self::from_phrase(phrase.expose_secret().as_str(), password)
946 .map_err(|_| SecretStringError::InvalidPhrase)?
947 };
948 root.derive(junctions.into_iter(), Some(seed))
949 .map_err(|_| SecretStringError::InvalidPath)
950 }
951
952 fn from_string(s: &str, password_override: Option<&str>) -> Result<Self, SecretStringError> {
956 Self::from_string_with_seed(s, password_override).map(|x| x.0)
957 }
958
959 fn to_raw_vec(&self) -> Vec<u8>;
961}
962
963pub trait IsWrappedBy<Outer>: From<Outer> + Into<Outer> {
965 fn from_ref(outer: &Outer) -> &Self;
967 fn from_mut(outer: &mut Outer) -> &mut Self;
969}
970
971pub trait Wraps: Sized {
973 type Inner: IsWrappedBy<Self>;
975
976 fn as_inner_ref(&self) -> &Self::Inner {
978 Self::Inner::from_ref(self)
979 }
980}
981
982impl<T, Outer> IsWrappedBy<Outer> for T
983where
984 Outer: AsRef<Self> + AsMut<Self> + From<Self>,
985 T: From<Outer>,
986{
987 fn from_ref(outer: &Outer) -> &Self {
989 outer.as_ref()
990 }
991
992 fn from_mut(outer: &mut Outer) -> &mut Self {
994 outer.as_mut()
995 }
996}
997
998impl<Inner, Outer, T> UncheckedFrom<T> for Outer
999where
1000 Outer: Wraps<Inner = Inner>,
1001 Inner: IsWrappedBy<Outer> + UncheckedFrom<T>,
1002{
1003 fn unchecked_from(t: T) -> Self {
1004 let inner: Inner = t.unchecked_into();
1005 inner.into()
1006 }
1007}
1008
1009pub trait CryptoType {
1011 type Pair: Pair;
1013}
1014
1015#[derive(
1023 Copy,
1024 Clone,
1025 Default,
1026 PartialEq,
1027 Eq,
1028 PartialOrd,
1029 Ord,
1030 Hash,
1031 Encode,
1032 Decode,
1033 PassByInner,
1034 crate::RuntimeDebug,
1035 TypeInfo,
1036)]
1037#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1038pub struct KeyTypeId(pub [u8; 4]);
1039
1040impl From<u32> for KeyTypeId {
1041 fn from(x: u32) -> Self {
1042 Self(x.to_le_bytes())
1043 }
1044}
1045
1046impl From<KeyTypeId> for u32 {
1047 fn from(x: KeyTypeId) -> Self {
1048 u32::from_le_bytes(x.0)
1049 }
1050}
1051
1052impl<'a> TryFrom<&'a str> for KeyTypeId {
1053 type Error = ();
1054
1055 fn try_from(x: &'a str) -> Result<Self, ()> {
1056 let b = x.as_bytes();
1057 if b.len() != 4 {
1058 return Err(())
1059 }
1060 let mut res = KeyTypeId::default();
1061 res.0.copy_from_slice(&b[0..4]);
1062 Ok(res)
1063 }
1064}
1065
1066pub trait VrfCrypto {
1068 type VrfInput;
1070 type VrfPreOutput;
1072 type VrfSignData;
1074 type VrfSignature;
1076}
1077
1078pub trait VrfSecret: VrfCrypto {
1080 fn vrf_pre_output(&self, data: &Self::VrfInput) -> Self::VrfPreOutput;
1082
1083 fn vrf_sign(&self, input: &Self::VrfSignData) -> Self::VrfSignature;
1085}
1086
1087pub trait VrfPublic: VrfCrypto {
1089 fn vrf_verify(&self, data: &Self::VrfSignData, signature: &Self::VrfSignature) -> bool;
1091}
1092
1093#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
1095#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1096pub struct CryptoTypeId(pub [u8; 4]);
1097
1098pub mod key_types {
1104 use super::KeyTypeId;
1105
1106 pub const BABE: KeyTypeId = KeyTypeId(*b"babe");
1108 pub const SASSAFRAS: KeyTypeId = KeyTypeId(*b"sass");
1110 pub const GRANDPA: KeyTypeId = KeyTypeId(*b"gran");
1112 pub const ACCOUNT: KeyTypeId = KeyTypeId(*b"acco");
1114 pub const AURA: KeyTypeId = KeyTypeId(*b"aura");
1116 pub const BEEFY: KeyTypeId = KeyTypeId(*b"beef");
1118 pub const IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon");
1120 pub const AUTHORITY_DISCOVERY: KeyTypeId = KeyTypeId(*b"audi");
1122 pub const STAKING: KeyTypeId = KeyTypeId(*b"stak");
1124 pub const STATEMENT: KeyTypeId = KeyTypeId(*b"stmt");
1126 pub const MIXNET: KeyTypeId = KeyTypeId(*b"mixn");
1128 pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy");
1130}
1131
1132pub trait FromEntropy: Sized {
1134 fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error>;
1137}
1138
1139impl FromEntropy for bool {
1140 fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
1141 Ok(input.read_byte()? % 2 == 1)
1142 }
1143}
1144
1145impl FromEntropy for () {
1147 fn from_entropy(_: &mut impl codec::Input) -> Result<Self, codec::Error> {
1148 Ok(())
1149 }
1150}
1151
1152macro_rules! impl_from_entropy {
1153 ($type:ty , $( $others:tt )*) => {
1154 impl_from_entropy!($type);
1155 impl_from_entropy!($( $others )*);
1156 };
1157 ($type:ty) => {
1158 impl FromEntropy for $type {
1159 fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
1160 <Self as codec::Decode>::decode(input)
1161 }
1162 }
1163 }
1164}
1165
1166macro_rules! impl_from_entropy_base {
1167 ($type:ty , $( $others:tt )*) => {
1168 impl_from_entropy_base!($type);
1169 impl_from_entropy_base!($( $others )*);
1170 };
1171 ($type:ty) => {
1172 impl_from_entropy!($type,
1173 [$type; 1], [$type; 2], [$type; 3], [$type; 4], [$type; 5], [$type; 6], [$type; 7], [$type; 8],
1174 [$type; 9], [$type; 10], [$type; 11], [$type; 12], [$type; 13], [$type; 14], [$type; 15], [$type; 16],
1175 [$type; 17], [$type; 18], [$type; 19], [$type; 20], [$type; 21], [$type; 22], [$type; 23], [$type; 24],
1176 [$type; 25], [$type; 26], [$type; 27], [$type; 28], [$type; 29], [$type; 30], [$type; 31], [$type; 32],
1177 [$type; 36], [$type; 40], [$type; 44], [$type; 48], [$type; 56], [$type; 64], [$type; 72], [$type; 80],
1178 [$type; 96], [$type; 112], [$type; 128], [$type; 160], [$type; 177], [$type; 192], [$type; 224], [$type; 256]
1179 );
1180 }
1181}
1182
1183impl_from_entropy_base!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
1184
1185#[cfg(test)]
1186mod tests {
1187 use super::*;
1188 use crate::DeriveJunction;
1189
1190 struct TestCryptoTag;
1191
1192 #[derive(Clone, Eq, PartialEq, Debug)]
1193 enum TestPair {
1194 Generated,
1195 GeneratedWithPhrase,
1196 GeneratedFromPhrase { phrase: String, password: Option<String> },
1197 Standard { phrase: String, password: Option<String>, path: Vec<DeriveJunction> },
1198 Seed(Vec<u8>),
1199 }
1200
1201 impl Default for TestPair {
1202 fn default() -> Self {
1203 TestPair::Generated
1204 }
1205 }
1206
1207 impl CryptoType for TestPair {
1208 type Pair = Self;
1209 }
1210
1211 type TestPublic = PublicBytes<0, TestCryptoTag>;
1212
1213 impl CryptoType for TestPublic {
1214 type Pair = TestPair;
1215 }
1216
1217 type TestSignature = SignatureBytes<0, TestCryptoTag>;
1218
1219 impl CryptoType for TestSignature {
1220 type Pair = TestPair;
1221 }
1222
1223 impl Pair for TestPair {
1224 type Public = TestPublic;
1225 type Seed = [u8; 8];
1226 type Signature = TestSignature;
1227
1228 fn generate() -> (Self, <Self as Pair>::Seed) {
1229 (TestPair::Generated, [0u8; 8])
1230 }
1231
1232 fn generate_with_phrase(_password: Option<&str>) -> (Self, String, <Self as Pair>::Seed) {
1233 (TestPair::GeneratedWithPhrase, "".into(), [0u8; 8])
1234 }
1235
1236 fn from_phrase(
1237 phrase: &str,
1238 password: Option<&str>,
1239 ) -> Result<(Self, <Self as Pair>::Seed), SecretStringError> {
1240 Ok((
1241 TestPair::GeneratedFromPhrase {
1242 phrase: phrase.to_owned(),
1243 password: password.map(Into::into),
1244 },
1245 [0u8; 8],
1246 ))
1247 }
1248
1249 fn derive<Iter: Iterator<Item = DeriveJunction>>(
1250 &self,
1251 path_iter: Iter,
1252 _: Option<[u8; 8]>,
1253 ) -> Result<(Self, Option<[u8; 8]>), DeriveError> {
1254 Ok((
1255 match self.clone() {
1256 TestPair::Standard { phrase, password, path } => TestPair::Standard {
1257 phrase,
1258 password,
1259 path: path.into_iter().chain(path_iter).collect(),
1260 },
1261 TestPair::GeneratedFromPhrase { phrase, password } =>
1262 TestPair::Standard { phrase, password, path: path_iter.collect() },
1263 x =>
1264 if path_iter.count() == 0 {
1265 x
1266 } else {
1267 return Err(DeriveError::SoftKeyInPath)
1268 },
1269 },
1270 None,
1271 ))
1272 }
1273
1274 fn sign(&self, _message: &[u8]) -> Self::Signature {
1275 TestSignature::default()
1276 }
1277
1278 fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool {
1279 true
1280 }
1281
1282 fn public(&self) -> Self::Public {
1283 TestPublic::default()
1284 }
1285
1286 fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError> {
1287 Ok(TestPair::Seed(seed.to_owned()))
1288 }
1289
1290 fn to_raw_vec(&self) -> Vec<u8> {
1291 vec![]
1292 }
1293 }
1294
1295 #[test]
1296 fn interpret_std_seed_should_work() {
1297 assert_eq!(
1298 TestPair::from_string("0x0123456789abcdef", None),
1299 Ok(TestPair::Seed(array_bytes::hex2bytes_unchecked("0123456789abcdef")))
1300 );
1301 }
1302
1303 #[test]
1304 fn password_override_should_work() {
1305 assert_eq!(
1306 TestPair::from_string("hello world///password", None),
1307 TestPair::from_string("hello world", Some("password")),
1308 );
1309 assert_eq!(
1310 TestPair::from_string("hello world///password", None),
1311 TestPair::from_string("hello world///other password", Some("password")),
1312 );
1313 }
1314
1315 #[test]
1316 fn interpret_std_secret_string_should_work() {
1317 assert_eq!(
1318 TestPair::from_string("hello world", None),
1319 Ok(TestPair::Standard {
1320 phrase: "hello world".to_owned(),
1321 password: None,
1322 path: vec![]
1323 })
1324 );
1325 assert_eq!(
1326 TestPair::from_string("hello world/1", None),
1327 Ok(TestPair::Standard {
1328 phrase: "hello world".to_owned(),
1329 password: None,
1330 path: vec![DeriveJunction::soft(1)]
1331 })
1332 );
1333 assert_eq!(
1334 TestPair::from_string("hello world/DOT", None),
1335 Ok(TestPair::Standard {
1336 phrase: "hello world".to_owned(),
1337 password: None,
1338 path: vec![DeriveJunction::soft("DOT")]
1339 })
1340 );
1341 assert_eq!(
1342 TestPair::from_string("hello world/0123456789012345678901234567890123456789", None),
1343 Ok(TestPair::Standard {
1344 phrase: "hello world".to_owned(),
1345 password: None,
1346 path: vec![DeriveJunction::soft("0123456789012345678901234567890123456789")]
1347 })
1348 );
1349 assert_eq!(
1350 TestPair::from_string("hello world//1", None),
1351 Ok(TestPair::Standard {
1352 phrase: "hello world".to_owned(),
1353 password: None,
1354 path: vec![DeriveJunction::hard(1)]
1355 })
1356 );
1357 assert_eq!(
1358 TestPair::from_string("hello world//DOT", None),
1359 Ok(TestPair::Standard {
1360 phrase: "hello world".to_owned(),
1361 password: None,
1362 path: vec![DeriveJunction::hard("DOT")]
1363 })
1364 );
1365 assert_eq!(
1366 TestPair::from_string("hello world//0123456789012345678901234567890123456789", None),
1367 Ok(TestPair::Standard {
1368 phrase: "hello world".to_owned(),
1369 password: None,
1370 path: vec![DeriveJunction::hard("0123456789012345678901234567890123456789")]
1371 })
1372 );
1373 assert_eq!(
1374 TestPair::from_string("hello world//1/DOT", None),
1375 Ok(TestPair::Standard {
1376 phrase: "hello world".to_owned(),
1377 password: None,
1378 path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]
1379 })
1380 );
1381 assert_eq!(
1382 TestPair::from_string("hello world//DOT/1", None),
1383 Ok(TestPair::Standard {
1384 phrase: "hello world".to_owned(),
1385 password: None,
1386 path: vec![DeriveJunction::hard("DOT"), DeriveJunction::soft(1)]
1387 })
1388 );
1389 assert_eq!(
1390 TestPair::from_string("hello world///password", None),
1391 Ok(TestPair::Standard {
1392 phrase: "hello world".to_owned(),
1393 password: Some("password".to_owned()),
1394 path: vec![]
1395 })
1396 );
1397 assert_eq!(
1398 TestPair::from_string("hello world//1/DOT///password", None),
1399 Ok(TestPair::Standard {
1400 phrase: "hello world".to_owned(),
1401 password: Some("password".to_owned()),
1402 path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]
1403 })
1404 );
1405 assert_eq!(
1406 TestPair::from_string("hello world/1//DOT///password", None),
1407 Ok(TestPair::Standard {
1408 phrase: "hello world".to_owned(),
1409 password: Some("password".to_owned()),
1410 path: vec![DeriveJunction::soft(1), DeriveJunction::hard("DOT")]
1411 })
1412 );
1413 }
1414
1415 #[test]
1416 fn accountid_32_from_str_works() {
1417 use std::str::FromStr;
1418 assert!(AccountId32::from_str("5G9VdMwXvzza9pS8qE8ZHJk3CheHW9uucBn9ngW4C1gmmzpv").is_ok());
1419 assert!(AccountId32::from_str(
1420 "5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1421 )
1422 .is_ok());
1423 assert!(AccountId32::from_str(
1424 "0x5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1425 )
1426 .is_ok());
1427
1428 assert_eq!(
1429 AccountId32::from_str("99G9VdMwXvzza9pS8qE8ZHJk3CheHW9uucBn9ngW4C1gmmzpv").unwrap_err(),
1430 "invalid ss58 address.",
1431 );
1432 assert_eq!(
1433 AccountId32::from_str(
1434 "gc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1435 )
1436 .unwrap_err(),
1437 "invalid hex address.",
1438 );
1439 assert_eq!(
1440 AccountId32::from_str(
1441 "0xgc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1442 )
1443 .unwrap_err(),
1444 "invalid hex address.",
1445 );
1446
1447 assert_eq!(
1449 AccountId32::from_str(
1450 "55c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
1451 )
1452 .unwrap_err(),
1453 "invalid ss58 address.",
1454 );
1455 }
1456}