1use crate::{sr25519, ed25519};
23use tetcore_std::hash::Hash;
24use tetcore_std::vec::Vec;
25use tetcore_std::str;
26#[cfg(feature = "std")]
27use tetcore_std::convert::TryInto;
28use tetcore_std::convert::TryFrom;
29#[cfg(feature = "std")]
30use parking_lot::Mutex;
31#[cfg(feature = "std")]
32use rand::{RngCore, rngs::OsRng};
33use codec::{Encode, Decode};
34#[cfg(feature = "std")]
35use regex::Regex;
36#[cfg(feature = "std")]
37use base58::{FromBase58, ToBase58};
38#[cfg(feature = "std")]
39use crate::hexdisplay::HexDisplay;
40#[doc(hidden)]
41pub use tetcore_std::ops::Deref;
42use tp_runtime_interface::pass_by::PassByInner;
43pub use zeroize::Zeroize;
45pub use secrecy::ExposeSecret;
47#[cfg(feature = "std")]
49pub use secrecy::SecretString;
50
51pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
53
54pub const DEV_ADDRESS: &str = "5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV";
56
57#[derive(crate::RuntimeDebug)]
59pub enum Infallible {}
60
61#[cfg(feature = "full_crypto")]
64pub const JUNCTION_ID_LEN: usize = 32;
65
66pub trait UncheckedFrom<T> {
70 fn unchecked_from(t: T) -> Self;
74}
75
76pub trait UncheckedInto<T> {
78 fn unchecked_into(self) -> T;
80}
81
82impl<S, T: UncheckedFrom<S>> UncheckedInto<T> for S {
83 fn unchecked_into(self) -> T {
84 T::unchecked_from(self)
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq)]
90#[cfg(feature = "full_crypto")]
91pub enum SecretStringError {
92 InvalidFormat,
94 InvalidPhrase,
96 InvalidPassword,
98 InvalidSeed,
100 InvalidSeedLength,
102 InvalidPath,
104}
105
106#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)]
110#[cfg(feature = "full_crypto")]
111pub enum DeriveJunction {
112 Soft([u8; JUNCTION_ID_LEN]),
114 Hard([u8; JUNCTION_ID_LEN]),
116}
117
118#[cfg(feature = "full_crypto")]
119impl DeriveJunction {
120 pub fn soften(self) -> Self { DeriveJunction::Soft(self.unwrap_inner()) }
122
123 pub fn harden(self) -> Self { DeriveJunction::Hard(self.unwrap_inner()) }
125
126 pub fn soft<T: Encode>(index: T) -> Self {
130 let mut cc: [u8; JUNCTION_ID_LEN] = Default::default();
131 index.using_encoded(|data| if data.len() > JUNCTION_ID_LEN {
132 let hash_result = blake2_rfc::blake2b::blake2b(JUNCTION_ID_LEN, &[], data);
133 let hash = hash_result.as_bytes();
134 cc.copy_from_slice(hash);
135 } else {
136 cc[0..data.len()].copy_from_slice(data);
137 });
138 DeriveJunction::Soft(cc)
139 }
140
141 pub fn hard<T: Encode>(index: T) -> Self {
145 Self::soft(index).harden()
146 }
147
148 pub fn unwrap_inner(self) -> [u8; JUNCTION_ID_LEN] {
150 match self {
151 DeriveJunction::Hard(c) | DeriveJunction::Soft(c) => c,
152 }
153 }
154
155 pub fn inner(&self) -> &[u8; JUNCTION_ID_LEN] {
157 match self {
158 DeriveJunction::Hard(ref c) | DeriveJunction::Soft(ref c) => c,
159 }
160 }
161
162 pub fn is_soft(&self) -> bool {
164 match *self {
165 DeriveJunction::Soft(_) => true,
166 _ => false,
167 }
168 }
169
170 pub fn is_hard(&self) -> bool {
172 match *self {
173 DeriveJunction::Hard(_) => true,
174 _ => false,
175 }
176 }
177}
178
179#[cfg(feature = "full_crypto")]
180impl<T: AsRef<str>> From<T> for DeriveJunction {
181 fn from(j: T) -> DeriveJunction {
182 let j = j.as_ref();
183 let (code, hard) = if j.starts_with('/') {
184 (&j[1..], true)
185 } else {
186 (j, false)
187 };
188
189 let res = if let Ok(n) = str::parse::<u64>(code) {
190 DeriveJunction::soft(n)
192 } else {
193 DeriveJunction::soft(code)
195 };
196
197 if hard {
198 res.harden()
199 } else {
200 res
201 }
202 }
203}
204
205#[cfg(feature = "full_crypto")]
207#[derive(Clone, Copy, Eq, PartialEq, Debug)]
208pub enum PublicError {
209 BadBase58,
211 BadLength,
213 UnknownVersion,
215 InvalidChecksum,
217 InvalidFormat,
219 InvalidPath,
221}
222
223#[cfg(feature = "full_crypto")]
225pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
226 #[cfg(feature = "std")]
228 fn from_ss58check(s: &str) -> Result<Self, PublicError> {
229 Self::from_ss58check_with_version(s)
230 .and_then(|(r, v)| match v {
231 v if !v.is_custom() => Ok(r),
232 v if v == *DEFAULT_VERSION.lock() => Ok(r),
233 _ => Err(PublicError::UnknownVersion),
234 })
235 }
236 #[cfg(feature = "std")]
238 fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
239 let mut res = Self::default();
240 let len = res.as_mut().len();
241 let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; if d.len() != len + 3 {
243 return Err(PublicError::BadLength);
245 }
246 let ver = d[0].try_into().map_err(|_: ()| PublicError::UnknownVersion)?;
247
248 if d[len + 1..len + 3] != ss58hash(&d[0..len + 1]).as_bytes()[0..2] {
249 return Err(PublicError::InvalidChecksum);
251 }
252 res.as_mut().copy_from_slice(&d[1..len + 1]);
253 Ok((res, ver))
254 }
255 #[cfg(feature = "std")]
258 fn from_string(s: &str) -> Result<Self, PublicError> {
259 Self::from_string_with_version(s)
260 .and_then(|(r, v)| match v {
261 v if !v.is_custom() => Ok(r),
262 v if v == *DEFAULT_VERSION.lock() => Ok(r),
263 _ => Err(PublicError::UnknownVersion),
264 })
265 }
266
267 #[cfg(feature = "std")]
269 fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String {
270 let mut v = vec![version.into()];
271 v.extend(self.as_ref());
272 let r = ss58hash(&v);
273 v.extend(&r.as_bytes()[0..2]);
274 v.to_base58()
275 }
276
277 #[cfg(feature = "std")]
279 fn to_ss58check(&self) -> String { self.to_ss58check_with_version(*DEFAULT_VERSION.lock()) }
280
281 #[cfg(feature = "std")]
284 fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
285 Self::from_ss58check_with_version(s)
286 }
287}
288
289pub trait Derive: Sized {
291 #[cfg(feature = "std")]
295 fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, _path: Iter) -> Option<Self> {
296 None
297 }
298}
299
300#[cfg(feature = "std")]
301const PREFIX: &[u8] = b"SS58PRE";
302
303#[cfg(feature = "std")]
304fn ss58hash(data: &[u8]) -> blake2_rfc::blake2b::Blake2bResult {
305 let mut context = blake2_rfc::blake2b::Blake2b::new(64);
306 context.update(PREFIX);
307 context.update(data);
308 context.finalize()
309}
310
311#[cfg(feature = "std")]
312lazy_static::lazy_static! {
313 static ref DEFAULT_VERSION: Mutex<Ss58AddressFormat>
314 = Mutex::new(Ss58AddressFormat::TetcoreAccount);
315}
316
317#[cfg(feature = "full_crypto")]
318macro_rules! ss58_address_format {
319 ( $( $identifier:tt => ($number:expr, $name:expr, $desc:tt) )* ) => (
320 #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)]
322 pub enum Ss58AddressFormat {
323 $(#[doc = $desc] $identifier),*,
324 Custom(u8),
326 }
327
328 #[cfg(feature = "std")]
329 impl std::fmt::Display for Ss58AddressFormat {
330 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
331 match self {
332 $(
333 Ss58AddressFormat::$identifier => write!(f, "{}", $name),
334 )*
335 Ss58AddressFormat::Custom(x) => write!(f, "{}", x),
336 }
337
338 }
339 }
340
341 static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormat; 0 $(+ { let _ = $number; 1})*] = [
342 $(Ss58AddressFormat::$identifier),*,
343 ];
344
345 impl Ss58AddressFormat {
346 pub fn all_names() -> &'static [&'static str] {
348 &[
349 $($name),*,
350 ]
351 }
352 pub fn all() -> &'static [Ss58AddressFormat] {
354 &ALL_SS58_ADDRESS_FORMATS
355 }
356
357 pub fn is_custom(&self) -> bool {
359 match self {
360 Self::Custom(_) => true,
361 _ => false,
362 }
363 }
364 }
365
366 impl From<Ss58AddressFormat> for u8 {
367 fn from(x: Ss58AddressFormat) -> u8 {
368 match x {
369 $(Ss58AddressFormat::$identifier => $number),*,
370 Ss58AddressFormat::Custom(n) => n,
371 }
372 }
373 }
374
375 impl TryFrom<u8> for Ss58AddressFormat {
376 type Error = ();
377
378 fn try_from(x: u8) -> Result<Ss58AddressFormat, ()> {
379 match x {
380 $($number => Ok(Ss58AddressFormat::$identifier)),*,
381 _ => {
382 #[cfg(feature = "std")]
383 match Ss58AddressFormat::default() {
384 Ss58AddressFormat::Custom(n) if n == x => Ok(Ss58AddressFormat::Custom(x)),
385 _ => Err(()),
386 }
387
388 #[cfg(not(feature = "std"))]
389 Err(())
390 },
391 }
392 }
393 }
394
395 #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)]
398 pub struct ParseError;
399
400 impl<'a> TryFrom<&'a str> for Ss58AddressFormat {
401 type Error = ParseError;
402
403 fn try_from(x: &'a str) -> Result<Ss58AddressFormat, Self::Error> {
404 match x {
405 $($name => Ok(Ss58AddressFormat::$identifier)),*,
406 a => a.parse::<u8>().map(Ss58AddressFormat::Custom).map_err(|_| ParseError),
407 }
408 }
409 }
410
411 #[cfg(feature = "std")]
412 impl std::str::FromStr for Ss58AddressFormat {
413 type Err = ParseError;
414
415 fn from_str(data: &str) -> Result<Self, Self::Err> {
416 Self::try_from(data)
417 }
418 }
419
420 #[cfg(feature = "std")]
421 impl std::fmt::Display for ParseError {
422 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423 write!(f, "failed to parse network value as u8")
424 }
425 }
426
427 #[cfg(feature = "std")]
428 impl Default for Ss58AddressFormat {
429 fn default() -> Self {
430 *DEFAULT_VERSION.lock()
431 }
432 }
433
434 #[cfg(feature = "std")]
435 impl From<Ss58AddressFormat> for String {
436 fn from(x: Ss58AddressFormat) -> String {
437 x.to_string()
438 }
439 }
440 )
441}
442
443#[cfg(feature = "full_crypto")]
444ss58_address_format!(
445 TetcoinAccount =>
446 (0, "tetcoin", "Tetcoin Relay-chain, standard account (*25519).")
447 Reserved1 =>
448 (1, "reserved1", "Reserved for future use (1).")
449 MetrocoinAccount =>
450 (2, "Metrocoin", "Metrocoin Relay-chain, standard account (*25519).")
451 Reserved3 =>
452 (3, "reserved3", "Reserved for future use (3).")
453 KatalChainAccount =>
454 (4, "katalchain", "Katal Chain, standard account (*25519).")
455 PlasmAccount =>
456 (5, "plasm", "Plasm Network, standard account (*25519).")
457 BifrostAccount =>
458 (6, "bifrost", "Bifrost mainnet, direct checksum, standard account (*25519).")
459 EdgewareAccount =>
460 (7, "edgeware", "Edgeware mainnet, standard account (*25519).")
461 KaruraAccount =>
462 (8, "karura", "Acala Karura canary network, standard account (*25519).")
463 ReynoldsAccount =>
464 (9, "reynolds", "Laminar Reynolds canary network, standard account (*25519).")
465 AcalaAccount =>
466 (10, "acala", "Acala mainnet, standard account (*25519).")
467 LaminarAccount =>
468 (11, "laminar", "Laminar mainnet, standard account (*25519).")
469 PolymathAccount =>
470 (12, "polymath", "Polymath network, standard account (*25519).")
471 TetcoReeAccount =>
472 (13, "tetcoree", "Any TetcoREE off-chain network private account (*25519).")
473 TotemAccount =>
474 (14, "totem", "Any Totem Live Accounting network standard account (*25519).")
475 SynesthesiaAccount =>
476 (15, "synesthesia", "Synesthesia mainnet, standard account (*25519).")
477 KulupuAccount =>
478 (16, "kulupu", "Kulupu mainnet, standard account (*25519).")
479 DarkAccount =>
480 (17, "dark", "Dark mainnet, standard account (*25519).")
481 DarwiniaAccount =>
482 (18, "darwinia", "Darwinia Chain mainnet, standard account (*25519).")
483 GeekAccount =>
484 (19, "geek", "GeekCash mainnet, standard account (*25519).")
485 StafiAccount =>
486 (20, "stafi", "Stafi mainnet, standard account (*25519).")
487 DockTestAccount =>
488 (21, "dock-testnet", "Dock testnet, standard account (*25519).")
489 DockMainAccount =>
490 (22, "dock-mainnet", "Dock mainnet, standard account (*25519).")
491 ShiftNrg =>
492 (23, "shift", "ShiftNrg mainnet, standard account (*25519).")
493 ZeroAccount =>
494 (24, "zero", "ZERO mainnet, standard account (*25519).")
495 AlphavilleAccount =>
496 (25, "alphaville", "ZERO testnet, standard account (*25519).")
497 JupiterAccount =>
498 (26, "jupiter", "Jupiter testnet, standard account (*25519).")
499 PatractAccount =>
500 (27, "patract", "Patract mainnet, standard account (*25519).")
501 SubsocialAccount =>
502 (28, "subsocial", "Subsocial network, standard account (*25519).")
503 DhiwayAccount =>
504 (29, "cord", "Dhiway CORD network, standard account (*25519).")
505 PhalaAccount =>
506 (30, "phala", "Phala Network, standard account (*25519).")
507 LitentryAccount =>
508 (31, "litentry", "Litentry Network, standard account (*25519).")
509 RobonomicsAccount =>
510 (32, "robonomics", "Any Robonomics network standard account (*25519).")
511 DataHighwayAccount =>
512 (33, "datahighway", "DataHighway mainnet, standard account (*25519).")
513 ValiuAccount =>
514 (35, "vln", "Valiu Liquidity Network mainnet, standard account (*25519).")
515 CentrifugeAccount =>
516 (36, "centrifuge", "Centrifuge Chain mainnet, standard account (*25519).")
517 NodleAccount =>
518 (37, "nodle", "Nodle Chain mainnet, standard account (*25519).")
519 KiltAccount =>
520 (38, "kilt", "KILT Chain mainnet, standard account (*25519).")
521 PolimecAccount =>
522 (41, "poli", "Polimec Chain mainnet, standard account (*25519).")
523 TetcoreAccount =>
524 (42, "tetcore", "Any Tetcore network, standard account (*25519).")
525 Reserved43 =>
526 (43, "reserved43", "Reserved for future use (43).")
527 ChainXAccount =>
528 (44, "chainx", "ChainX mainnet, standard account (*25519).")
529 UniartsAccount =>
530 (45, "uniarts", "UniArts Chain mainnet, standard account (*25519).")
531 Reserved46 =>
532 (46, "reserved46", "Reserved for future use (46).")
533 Reserved47 =>
534 (47, "reserved47", "Reserved for future use (47).")
535 );
537
538#[cfg(feature = "std")]
544pub fn set_default_ss58_version(version: Ss58AddressFormat) {
545 *DEFAULT_VERSION.lock() = version
546}
547
548#[cfg(feature = "std")]
549impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
550 fn from_string(s: &str) -> Result<Self, PublicError> {
551 let re = Regex::new(r"^(?P<ss58>[\w\d ]+)?(?P<path>(//?[^/]+)*)$")
552 .expect("constructed from known-good static value; qed");
553 let cap = re.captures(s).ok_or(PublicError::InvalidFormat)?;
554 let re_junction = Regex::new(r"/(/?[^/]+)")
555 .expect("constructed from known-good static value; qed");
556 let s = cap.name("ss58")
557 .map(|r| r.as_str())
558 .unwrap_or(DEV_ADDRESS);
559 let addr = if s.starts_with("0x") {
560 let d = hex::decode(&s[2..]).map_err(|_| PublicError::InvalidFormat)?;
561 let mut r = Self::default();
562 if d.len() == r.as_ref().len() {
563 r.as_mut().copy_from_slice(&d);
564 r
565 } else {
566 Err(PublicError::BadLength)?
567 }
568 } else {
569 Self::from_ss58check(s)?
570 };
571 if cap["path"].is_empty() {
572 Ok(addr)
573 } else {
574 let path = re_junction.captures_iter(&cap["path"])
575 .map(|f| DeriveJunction::from(&f[1]));
576 addr.derive(path)
577 .ok_or(PublicError::InvalidPath)
578 }
579 }
580
581 fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
582 let re = Regex::new(r"^(?P<ss58>[\w\d ]+)?(?P<path>(//?[^/]+)*)$")
583 .expect("constructed from known-good static value; qed");
584 let cap = re.captures(s).ok_or(PublicError::InvalidFormat)?;
585 let re_junction = Regex::new(r"/(/?[^/]+)")
586 .expect("constructed from known-good static value; qed");
587 let (addr, v) = Self::from_ss58check_with_version(
588 cap.name("ss58")
589 .map(|r| r.as_str())
590 .unwrap_or(DEV_ADDRESS)
591 )?;
592 if cap["path"].is_empty() {
593 Ok((addr, v))
594 } else {
595 let path = re_junction.captures_iter(&cap["path"])
596 .map(|f| DeriveJunction::from(&f[1]));
597 addr.derive(path)
598 .ok_or(PublicError::InvalidPath)
599 .map(|a| (a, v))
600 }
601 }
602}
603
604pub trait Public:
606 AsRef<[u8]>
607 + AsMut<[u8]>
608 + Default
609 + Derive
610 + CryptoType
611 + PartialEq
612 + Eq
613 + Clone
614 + Send
615 + Sync
616 + for<'a> TryFrom<&'a [u8]>
617{
618 fn from_slice(data: &[u8]) -> Self;
623
624 fn to_raw_vec(&self) -> Vec<u8> { self.as_slice().to_vec() }
626
627 fn as_slice(&self) -> &[u8] { self.as_ref() }
629 fn to_public_crypto_pair(&self) -> CryptoTypePublicPair;
631}
632
633#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Default, Encode, Decode)]
635#[cfg_attr(feature = "std", derive(Hash))]
636pub struct AccountId32([u8; 32]);
637
638impl AccountId32 {
639 pub const fn new(inner: [u8; 32]) -> Self {
644 Self(inner)
645 }
646}
647
648impl UncheckedFrom<crate::hash::H256> for AccountId32 {
649 fn unchecked_from(h: crate::hash::H256) -> Self {
650 AccountId32(h.into())
651 }
652}
653
654#[cfg(feature = "std")]
655impl Ss58Codec for AccountId32 {}
656
657impl AsRef<[u8]> for AccountId32 {
658 fn as_ref(&self) -> &[u8] {
659 &self.0[..]
660 }
661}
662
663impl AsMut<[u8]> for AccountId32 {
664 fn as_mut(&mut self) -> &mut [u8] {
665 &mut self.0[..]
666 }
667}
668
669impl AsRef<[u8; 32]> for AccountId32 {
670 fn as_ref(&self) -> &[u8; 32] {
671 &self.0
672 }
673}
674
675impl AsMut<[u8; 32]> for AccountId32 {
676 fn as_mut(&mut self) -> &mut [u8; 32] {
677 &mut self.0
678 }
679}
680
681impl From<[u8; 32]> for AccountId32 {
682 fn from(x: [u8; 32]) -> Self {
683 Self::new(x)
684 }
685}
686
687impl<'a> tetcore_std::convert::TryFrom<&'a [u8]> for AccountId32 {
688 type Error = ();
689 fn try_from(x: &'a [u8]) -> Result<AccountId32, ()> {
690 if x.len() == 32 {
691 let mut r = AccountId32::default();
692 r.0.copy_from_slice(x);
693 Ok(r)
694 } else {
695 Err(())
696 }
697 }
698}
699
700impl From<AccountId32> for [u8; 32] {
701 fn from(x: AccountId32) -> [u8; 32] {
702 x.0
703 }
704}
705
706impl From<sr25519::Public> for AccountId32 {
707 fn from(k: sr25519::Public) -> Self {
708 k.0.into()
709 }
710}
711
712impl From<ed25519::Public> for AccountId32 {
713 fn from(k: ed25519::Public) -> Self {
714 k.0.into()
715 }
716}
717
718#[cfg(feature = "std")]
719impl std::fmt::Display for AccountId32 {
720 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
721 write!(f, "{}", self.to_ss58check())
722 }
723}
724
725impl tetcore_std::fmt::Debug for AccountId32 {
726 #[cfg(feature = "std")]
727 fn fmt(&self, f: &mut tetcore_std::fmt::Formatter) -> tetcore_std::fmt::Result {
728 let s = self.to_ss58check();
729 write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
730 }
731
732 #[cfg(not(feature = "std"))]
733 fn fmt(&self, _: &mut tetcore_std::fmt::Formatter) -> tetcore_std::fmt::Result {
734 Ok(())
735 }
736}
737
738#[cfg(feature = "std")]
739impl serde::Serialize for AccountId32 {
740 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
741 serializer.serialize_str(&self.to_ss58check())
742 }
743}
744
745#[cfg(feature = "std")]
746impl<'de> serde::Deserialize<'de> for AccountId32 {
747 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
748 Ss58Codec::from_ss58check(&String::deserialize(deserializer)?)
749 .map_err(|e| serde::de::Error::custom(format!("{:?}", e)))
750 }
751}
752
753#[cfg(feature = "std")]
754impl tetcore_std::str::FromStr for AccountId32 {
755 type Err = &'static str;
756
757 fn from_str(s: &str) -> Result<Self, Self::Err> {
758 let hex_or_ss58_without_prefix = s.trim_start_matches("0x");
759 if hex_or_ss58_without_prefix.len() == 64 {
760 let mut bytes = [0u8; 32];
761 hex::decode_to_slice(hex_or_ss58_without_prefix, &mut bytes)
762 .map_err(|_| "invalid hex address.")
763 .map(|_| Self::from(bytes))
764 } else {
765 Self::from_ss58check(s).map_err(|_| "invalid ss58 address.")
766 }
767 }
768}
769
770#[cfg(feature = "std")]
771pub use self::dummy::*;
772
773#[cfg(feature = "std")]
774mod dummy {
775 use super::*;
776
777 #[derive(Clone, Hash, Default, Eq, PartialEq)]
779 pub struct Dummy;
780
781 impl AsRef<[u8]> for Dummy {
782 fn as_ref(&self) -> &[u8] { &b""[..] }
783 }
784
785 impl AsMut<[u8]> for Dummy {
786 fn as_mut(&mut self) -> &mut[u8] {
787 unsafe {
788 #[allow(mutable_transmutes)]
789 tetcore_std::mem::transmute::<_, &'static mut [u8]>(&b""[..])
790 }
791 }
792 }
793
794 impl<'a> TryFrom<&'a [u8]> for Dummy {
795 type Error = ();
796
797 fn try_from(_: &'a [u8]) -> Result<Self, ()> {
798 Ok(Self)
799 }
800 }
801
802 impl CryptoType for Dummy {
803 type Pair = Dummy;
804 }
805
806 impl Derive for Dummy {}
807
808 impl Public for Dummy {
809 fn from_slice(_: &[u8]) -> Self { Self }
810 #[cfg(feature = "std")]
811 fn to_raw_vec(&self) -> Vec<u8> { vec![] }
812 fn as_slice(&self) -> &[u8] { b"" }
813 fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
814 CryptoTypePublicPair(
815 CryptoTypeId(*b"dumm"), Public::to_raw_vec(self)
816 )
817 }
818 }
819
820 impl Pair for Dummy {
821 type Public = Dummy;
822 type Seed = Dummy;
823 type Signature = Dummy;
824 type DeriveError = ();
825 #[cfg(feature = "std")]
826 fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() }
827 #[cfg(feature = "std")]
828 fn from_phrase(_: &str, _: Option<&str>)
829 -> Result<(Self, Self::Seed), SecretStringError>
830 {
831 Ok(Default::default())
832 }
833 fn derive<
834 Iter: Iterator<Item=DeriveJunction>,
835 >(&self, _: Iter, _: Option<Dummy>) -> Result<(Self, Option<Dummy>), Self::DeriveError> { Ok((Self, None)) }
836 fn from_seed(_: &Self::Seed) -> Self { Self }
837 fn from_seed_slice(_: &[u8]) -> Result<Self, SecretStringError> { Ok(Self) }
838 fn sign(&self, _: &[u8]) -> Self::Signature { Self }
839 fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
840 fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { true }
841 fn public(&self) -> Self::Public { Self }
842 fn to_raw_vec(&self) -> Vec<u8> { vec![] }
843 }
844}
845
846#[cfg(feature = "full_crypto")]
850pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
851 type Public: Public + Hash;
853
854 type Seed: Default + AsRef<[u8]> + AsMut<[u8]> + Clone;
857
858 type Signature: AsRef<[u8]>;
861
862 type DeriveError;
864
865 #[cfg(feature = "std")]
870 fn generate() -> (Self, Self::Seed) {
871 let mut seed = Self::Seed::default();
872 OsRng.fill_bytes(seed.as_mut());
873 (Self::from_seed(&seed), seed)
874 }
875
876 #[cfg(feature = "std")]
883 fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed);
884
885 #[cfg(feature = "std")]
887 fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Self, Self::Seed), SecretStringError>;
888
889 fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
891 path: Iter,
892 seed: Option<Self::Seed>,
893 ) -> Result<(Self, Option<Self::Seed>), Self::DeriveError>;
894
895 fn from_seed(seed: &Self::Seed) -> Self;
900
901 fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError>;
907
908 fn sign(&self, message: &[u8]) -> Self::Signature;
910
911 fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool;
913
914 fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool;
916
917 fn public(&self) -> Self::Public;
919
920 #[cfg(feature = "std")]
949 fn from_string_with_seed(s: &str, password_override: Option<&str>)
950 -> Result<(Self, Option<Self::Seed>), SecretStringError>
951 {
952 let re = Regex::new(r"^(?P<phrase>[\d\w ]+)?(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
953 .expect("constructed from known-good static value; qed");
954 let cap = re.captures(s).ok_or(SecretStringError::InvalidFormat)?;
955
956 let re_junction = Regex::new(r"/(/?[^/]+)")
957 .expect("constructed from known-good static value; qed");
958 let path = re_junction.captures_iter(&cap["path"])
959 .map(|f| DeriveJunction::from(&f[1]));
960
961 let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE);
962 let password = password_override.or_else(|| cap.name("password").map(|m| m.as_str()));
963
964 let (root, seed) = if phrase.starts_with("0x") {
965 hex::decode(&phrase[2..]).ok()
966 .and_then(|seed_vec| {
967 let mut seed = Self::Seed::default();
968 if seed.as_ref().len() == seed_vec.len() {
969 seed.as_mut().copy_from_slice(&seed_vec);
970 Some((Self::from_seed(&seed), seed))
971 } else {
972 None
973 }
974 })
975 .ok_or(SecretStringError::InvalidSeed)?
976 } else {
977 Self::from_phrase(phrase, password)
978 .map_err(|_| SecretStringError::InvalidPhrase)?
979 };
980 root.derive(path, Some(seed)).map_err(|_| SecretStringError::InvalidPath)
981 }
982
983 #[cfg(feature = "std")]
987 fn from_string(s: &str, password_override: Option<&str>) -> Result<Self, SecretStringError> {
988 Self::from_string_with_seed(s, password_override).map(|x| x.0)
989 }
990
991 fn to_raw_vec(&self) -> Vec<u8>;
993}
994
995pub trait IsWrappedBy<Outer>: From<Outer> + Into<Outer> {
997 fn from_ref(outer: &Outer) -> &Self;
999 fn from_mut(outer: &mut Outer) -> &mut Self;
1001}
1002
1003pub trait Wraps: Sized {
1005 type Inner: IsWrappedBy<Self>;
1007}
1008
1009impl<T, Outer> IsWrappedBy<Outer> for T where
1010 Outer: AsRef<Self> + AsMut<Self> + From<Self>,
1011 T: From<Outer>,
1012{
1013 fn from_ref(outer: &Outer) -> &Self { outer.as_ref() }
1015
1016 fn from_mut(outer: &mut Outer) -> &mut Self { outer.as_mut() }
1018}
1019
1020impl<Inner, Outer, T> UncheckedFrom<T> for Outer where
1021 Outer: Wraps<Inner=Inner>,
1022 Inner: IsWrappedBy<Outer> + UncheckedFrom<T>,
1023{
1024 fn unchecked_from(t: T) -> Self {
1025 let inner: Inner = t.unchecked_into();
1026 inner.into()
1027 }
1028}
1029
1030pub trait CryptoType {
1032 #[cfg(feature = "full_crypto")]
1034 type Pair: Pair;
1035}
1036
1037#[derive(
1045 Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode, PassByInner,
1046 crate::RuntimeDebug
1047)]
1048#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
1049pub struct KeyTypeId(pub [u8; 4]);
1050
1051impl From<u32> for KeyTypeId {
1052 fn from(x: u32) -> Self {
1053 Self(x.to_le_bytes())
1054 }
1055}
1056
1057impl From<KeyTypeId> for u32 {
1058 fn from(x: KeyTypeId) -> Self {
1059 u32::from_le_bytes(x.0)
1060 }
1061}
1062
1063impl<'a> TryFrom<&'a str> for KeyTypeId {
1064 type Error = ();
1065
1066 fn try_from(x: &'a str) -> Result<Self, ()> {
1067 let b = x.as_bytes();
1068 if b.len() != 4 {
1069 return Err(());
1070 }
1071 let mut res = KeyTypeId::default();
1072 res.0.copy_from_slice(&b[0..4]);
1073 Ok(res)
1074 }
1075}
1076
1077#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
1079#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
1080pub struct CryptoTypeId(pub [u8; 4]);
1081
1082#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
1084#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
1085pub struct CryptoTypePublicPair(pub CryptoTypeId, pub Vec<u8>);
1086
1087#[cfg(feature = "std")]
1088impl tetcore_std::fmt::Display for CryptoTypePublicPair {
1089 fn fmt(&self, f: &mut tetcore_std::fmt::Formatter) -> tetcore_std::fmt::Result {
1090 let id = match str::from_utf8(&(self.0).0[..]) {
1091 Ok(id) => id.to_string(),
1092 Err(_) => {
1093 format!("{:#?}", self.0)
1094 }
1095 };
1096 write!(f, "{}-{}", id, HexDisplay::from(&self.1))
1097 }
1098}
1099
1100pub mod key_types {
1106 use super::KeyTypeId;
1107
1108 pub const BABE: KeyTypeId = KeyTypeId(*b"babe");
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 IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon");
1118 pub const AUTHORITY_DISCOVERY: KeyTypeId = KeyTypeId(*b"audi");
1120 pub const STAKING: KeyTypeId = KeyTypeId(*b"stak");
1122 pub const REPORTING: KeyTypeId = KeyTypeId(*b"fish");
1124 pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy");
1126}
1127
1128#[cfg(test)]
1129mod tests {
1130 use crate::DeriveJunction;
1131 use hex_literal::hex;
1132 use super::*;
1133
1134 #[derive(Clone, Eq, PartialEq, Debug)]
1135 enum TestPair {
1136 Generated,
1137 GeneratedWithPhrase,
1138 GeneratedFromPhrase{phrase: String, password: Option<String>},
1139 Standard{phrase: String, password: Option<String>, path: Vec<DeriveJunction>},
1140 Seed(Vec<u8>),
1141 }
1142 impl Default for TestPair {
1143 fn default() -> Self {
1144 TestPair::Generated
1145 }
1146 }
1147 impl CryptoType for TestPair {
1148 type Pair = Self;
1149 }
1150
1151 #[derive(Clone, PartialEq, Eq, Hash, Default)]
1152 struct TestPublic;
1153 impl AsRef<[u8]> for TestPublic {
1154 fn as_ref(&self) -> &[u8] {
1155 &[]
1156 }
1157 }
1158 impl AsMut<[u8]> for TestPublic {
1159 fn as_mut(&mut self) -> &mut [u8] {
1160 &mut []
1161 }
1162 }
1163 impl<'a> TryFrom<&'a [u8]> for TestPublic {
1164 type Error = ();
1165
1166 fn try_from(_: &'a [u8]) -> Result<Self, ()> {
1167 Ok(Self)
1168 }
1169 }
1170 impl CryptoType for TestPublic {
1171 type Pair = TestPair;
1172 }
1173 impl Derive for TestPublic {}
1174 impl Public for TestPublic {
1175 fn from_slice(_bytes: &[u8]) -> Self {
1176 Self
1177 }
1178 fn as_slice(&self) -> &[u8] {
1179 &[]
1180 }
1181 fn to_raw_vec(&self) -> Vec<u8> {
1182 vec![]
1183 }
1184 fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
1185 CryptoTypePublicPair(
1186 CryptoTypeId(*b"dumm"), self.to_raw_vec(),
1187 )
1188 }
1189 }
1190 impl Pair for TestPair {
1191 type Public = TestPublic;
1192 type Seed = [u8; 8];
1193 type Signature = [u8; 0];
1194 type DeriveError = ();
1195
1196 fn generate() -> (Self, <Self as Pair>::Seed) { (TestPair::Generated, [0u8; 8]) }
1197 fn generate_with_phrase(_password: Option<&str>) -> (Self, String, <Self as Pair>::Seed) {
1198 (TestPair::GeneratedWithPhrase, "".into(), [0u8; 8])
1199 }
1200 fn from_phrase(phrase: &str, password: Option<&str>)
1201 -> Result<(Self, <Self as Pair>::Seed), SecretStringError>
1202 {
1203 Ok((TestPair::GeneratedFromPhrase {
1204 phrase: phrase.to_owned(),
1205 password: password.map(Into::into)
1206 }, [0u8; 8]))
1207 }
1208 fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path_iter: Iter, _: Option<[u8; 8]>)
1209 -> Result<(Self, Option<[u8; 8]>), Self::DeriveError>
1210 {
1211 Ok((match self.clone() {
1212 TestPair::Standard {phrase, password, path} =>
1213 TestPair::Standard { phrase, password, path: path.into_iter().chain(path_iter).collect() },
1214 TestPair::GeneratedFromPhrase {phrase, password} =>
1215 TestPair::Standard { phrase, password, path: path_iter.collect() },
1216 x => if path_iter.count() == 0 { x } else { return Err(()) },
1217 }, None))
1218 }
1219 fn from_seed(_seed: &<TestPair as Pair>::Seed) -> Self { TestPair::Seed(_seed.as_ref().to_owned()) }
1220 fn sign(&self, _message: &[u8]) -> Self::Signature { [] }
1221 fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
1222 fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(
1223 _sig: &[u8],
1224 _message: M,
1225 _pubkey: P
1226 ) -> bool { true }
1227 fn public(&self) -> Self::Public { TestPublic }
1228 fn from_seed_slice(seed: &[u8])
1229 -> Result<Self, SecretStringError>
1230 {
1231 Ok(TestPair::Seed(seed.to_owned()))
1232 }
1233 fn to_raw_vec(&self) -> Vec<u8> {
1234 vec![]
1235 }
1236 }
1237
1238 #[test]
1239 fn interpret_std_seed_should_work() {
1240 assert_eq!(
1241 TestPair::from_string("0x0123456789abcdef", None),
1242 Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned()))
1243 );
1244 }
1245
1246 #[test]
1247 fn password_override_should_work() {
1248 assert_eq!(
1249 TestPair::from_string("hello world///password", None),
1250 TestPair::from_string("hello world", Some("password")),
1251 );
1252 assert_eq!(
1253 TestPair::from_string("hello world///password", None),
1254 TestPair::from_string("hello world///other password", Some("password")),
1255 );
1256 }
1257
1258 #[test]
1259 fn interpret_std_secret_string_should_work() {
1260 assert_eq!(
1261 TestPair::from_string("hello world", None),
1262 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![]})
1263 );
1264 assert_eq!(
1265 TestPair::from_string("hello world/1", None),
1266 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::soft(1)]})
1267 );
1268 assert_eq!(
1269 TestPair::from_string("hello world/TET", None),
1270 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::soft("TET")]})
1271 );
1272 assert_eq!(
1273 TestPair::from_string("hello world//1", None),
1274 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard(1)]})
1275 );
1276 assert_eq!(
1277 TestPair::from_string("hello world//TET", None),
1278 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard("TET")]})
1279 );
1280 assert_eq!(
1281 TestPair::from_string("hello world//1/TET", None),
1282 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard(1), DeriveJunction::soft("TET")]})
1283 );
1284 assert_eq!(
1285 TestPair::from_string("hello world//TET/1", None),
1286 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard("TET"), DeriveJunction::soft(1)]})
1287 );
1288 assert_eq!(
1289 TestPair::from_string("hello world///password", None),
1290 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![]})
1291 );
1292 assert_eq!(
1293 TestPair::from_string("hello world//1/TET///password", None),
1294 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![DeriveJunction::hard(1), DeriveJunction::soft("TET")]})
1295 );
1296 assert_eq!(
1297 TestPair::from_string("hello world/1//TET///password", None),
1298 Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![DeriveJunction::soft(1), DeriveJunction::hard("TET")]})
1299 );
1300 }
1301
1302 #[test]
1303 fn accountid_32_from_str_works() {
1304 use std::str::FromStr;
1305 assert!(AccountId32::from_str("5G9VdMwXvzza9pS8qE8ZHJk3CheHW9uucBn9ngW4C1gmmzpv").is_ok());
1306 assert!(AccountId32::from_str("5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").is_ok());
1307 assert!(AccountId32::from_str("0x5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").is_ok());
1308
1309 assert_eq!(
1310 AccountId32::from_str("99G9VdMwXvzza9pS8qE8ZHJk3CheHW9uucBn9ngW4C1gmmzpv").unwrap_err(),
1311 "invalid ss58 address.",
1312 );
1313 assert_eq!(
1314 AccountId32::from_str("gc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").unwrap_err(),
1315 "invalid hex address.",
1316 );
1317 assert_eq!(
1318 AccountId32::from_str("0xgc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").unwrap_err(),
1319 "invalid hex address.",
1320 );
1321
1322 assert_eq!(
1324 AccountId32::from_str("55c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").unwrap_err(),
1325 "invalid ss58 address.",
1326 );
1327 }
1328}