1use bip38::Encrypt;
137use bitcoin_bech32::constants::Network;
138use bitcoin_bech32::{u5, WitnessProgram};
139use clap::{
140 builder::OsStringValueParser, builder::TypedValueParser, crate_version, Arg, ArgMatches,
141 Command,
142};
143use hmac::{Hmac, Mac};
144use ripemd::Ripemd160;
145use secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey};
146use sha2::Digest;
147use std::ffi::OsString;
148
149const ABOUT: &str = "Inform extended key and optional path and/or range to show derivation. Insert
151address, hexadecimal entropy or wif private key to show information about it.
152Optional range is closed (include start and end). Optionally encrypts private
153keys. Default separator of results can be customized.";
154
155const DEF_RNG: (u32, u32) = (0, 9);
157
158const DEF_SEP: &str = " | ";
160
161const HARD_NB: u32 = 0x80000000;
163
164const HARD_CHAR: char = 'h';
166
167const LEN_ARG_MIN: usize = 27;
169
170const LEN_XKEY: usize = 111;
172
173const LEN_LEG_MAX: usize = 35;
175
176const LEN_LEG_MIN: usize = 27;
178
179const LEN_SEGWIT: usize = 42;
181
182const LEN_WIF_C: usize = 52;
184
185const LEN_WIF_U: usize = 51;
187
188const NBBY_PUBC: usize = 33;
190
191const NBBY_PUBU: usize = 65;
193
194const NBBY_WIFC: usize = 34;
196
197const NBBY_WIFU: usize = 33;
199
200const NBBY_XKEY: usize = 78;
202
203const OP_0: u8 = 0x00;
205
206const OP_PUSH20: u8 = 0x14;
208
209const PATH_START: &str = "m";
211
212const PRE_ADDR: &str = "13bc";
214
215const PRE_P2WPKH_P2SH_B: u8 = 0x05;
217
218const PRE_WIF_C: &str = "KL";
220
221const PRE_WIF_B: u8 = 0x80;
223
224const PRE_WIF_U: &str = "5";
226
227const PRE_PRV_KEY: [&str; 6] = ["tprv", "uprv", "vprv", "xprv", "yprv", "zprv"];
229
230const PRE_PUB_KEY: [&str; 6] = ["tpub", "upub", "vpub", "xpub", "ypub", "zpub"];
232
233const SEP_PATH: char = '/';
235
236const SEP_RANGE: &str = "..";
238
239const TPRV: [u8; 4] = [0x04, 0x35, 0x83, 0x94];
241
242const TPUB: [u8; 4] = [0x04, 0x35, 0x87, 0xcf];
244
245const UPRV: [u8; 4] = [0x04, 0x4a, 0x4e, 0x28];
247
248const UPUB: [u8; 4] = [0x04, 0x4a, 0x52, 0x62];
250
251const VPRV: [u8; 4] = [0x04, 0x5f, 0x18, 0xbc];
253
254const VPUB: [u8; 4] = [0x04, 0x5f, 0x1c, 0xf6];
256
257const XPRV: [u8; 4] = [0x04, 0x88, 0xad, 0xe4];
259
260const XPUB: [u8; 4] = [0x04, 0x88, 0xb2, 0x1e];
262
263const YPRV: [u8; 4] = [0x04, 0x9d, 0x78, 0x78];
265
266const YPUB: [u8; 4] = [0x04, 0x9d, 0x7c, 0xb2];
268
269const ZPRV: [u8; 4] = [0x04, 0xb2, 0x43, 0x0c];
271
272const ZPUB: [u8; 4] = [0x04, 0xb2, 0x47, 0x46];
274
275#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd)]
277#[doc(hidden)]
278pub enum Error {
279 Address,
281 Argument(String),
283 Base58,
285 Bech32,
287 Bip38(bip38::Error),
289 Checksum,
291 Context(String),
293 FromHard,
295 HexStr,
297 Hmac,
299 KeyLen,
301 KeyVer,
303 NbPubB(usize),
305 NotFound,
307 Path(String),
309 PrvData,
311 PubData,
313 Range(String),
315 SecEnt,
317 WifKey,
319}
320
321#[derive(Clone, Copy, Debug, PartialEq)]
323struct ExtPrvKey {
324 pub version: [u8; 4],
325 pub depth: u8,
326 pub parentf: [u8; 4],
327 pub childnb: u32,
328 pub chaincd: [u8; 32],
329 pub prvdata: [u8; 32], pub purpose: u32,
331}
332
333#[derive(Clone, Copy, Debug, PartialEq)]
335struct ExtPubKey {
336 pub version: [u8; 4],
337 pub depth: u8,
338 pub parentf: [u8; 4],
339 pub childnb: u32,
340 pub chaincd: [u8; 32],
341 pub pubdata: [u8; 33],
342 pub purpose: u32,
343}
344
345trait BytesManipulation {
347 fn encode_base58ck(&self) -> String;
349
350 fn hash160(&self) -> [u8; 20];
352
353 fn hash256(&self) -> [u8; 32];
355
356 fn hex_string(&self) -> String;
358
359 fn p2wpkh(&self) -> Result<String, Error>;
361}
362
363trait PathManipulation {
365 fn encode_path(&self) -> String;
367}
368
369trait PrivateKeyManipulation {
371 fn encode_wif(&self, compress: bool) -> Result<String, Error>;
373
374 fn public_key(&self, compress: bool) -> Result<Vec<u8>, Error>;
376}
377
378trait PublicKeyCompressedManipulation {
380 fn segwit_p2wpkh(&self) -> Result<String, Error>;
382
383 fn segwit_p2wpkh_p2sh(&self) -> Result<String, Error>;
385}
386
387trait StringManipulation {
389 fn decode_address(&self) -> Result<Vec<u8>, Error>;
391
392 fn decode_base58ck(&self) -> Result<Vec<u8>, Error>;
394
395 fn decode_wif(&self) -> Result<([u8; 32], bool), Error>;
397
398 fn hex_bytes(&self) -> Result<Vec<u8>, Error>;
400
401 fn info_entropy(&self, pass: &str, separator: &str) -> Result<(), Error>;
403
404 fn info_wif(&self, pass: &str, separator: &str) -> Result<(), Error>;
406
407 fn is_hex(&self) -> bool;
409
410 fn decode_path(&self, public: bool) -> Result<Vec<u32>, Error>;
412
413 fn decode_range(&self) -> Result<(u32, u32), Error>;
415}
416
417impl core::fmt::Display for Error {
418 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
419 match self {
420 Error::Address => write!(f, "invalid address"),
421 Error::Argument(a) => write!(f, "invalid argument: '\x1b[33m{}\x1b[m'", a),
422 Error::Base58 => write!(f, "invalid base 58 string"),
423 Error::Bech32 => write!(f, "invalid bech32 string"),
424 Error::Bip38(err) => write!(f, "{}", err),
425 Error::Checksum => write!(f, "invalid checksum"),
426 Error::Context(o) => write!(
427 f,
428 "option '\x1b[33m{}\x1b[m' invalid in this context (aborted)",
429 o
430 ),
431 Error::FromHard => write!(f, "cannot derive hardened from public"),
432 Error::HexStr => write!(f, "invalid hexadecimal string"),
433 Error::Hmac => write!(f, "invalid input in hmac"),
434 Error::KeyLen => write!(f, "invalid key length"),
435 Error::KeyVer => write!(f, "invalid key version (prefix)"),
436 Error::NbPubB(nb) => write!(
437 f,
438 "invalid number of bytes in the public key: '\x1b[33m{}\x1b[m'",
439 nb
440 ),
441 Error::NotFound => write!(f, "data to process not found"),
442 Error::Path(v) => write!(f, "invalid path value: '\x1b[33m{}\x1b[m'", v),
443 Error::PrvData => write!(f, "invalid private data"),
444 Error::PubData => write!(f, "invalid public data"),
445 Error::Range(r) => write!(f, "invalid range value: '\x1b[33m{}\x1b[m'", r),
446 Error::SecEnt => write!(f, "invalid secret entropy"),
447 Error::WifKey => write!(f, "invalid wif secret key"),
448 }
449 }
450}
451
452impl From<bip38::Error> for Error {
453 fn from(err: bip38::Error) -> Self {
454 Error::Bip38(err)
455 }
456}
457
458impl BytesManipulation for [u8] {
460 #[inline]
461 fn encode_base58ck(&self) -> String {
462 let mut decoded: Vec<u8> = self.to_vec();
463 decoded.append(&mut decoded.hash256()[..4].to_vec());
464 bs58::encode(decoded).into_string()
465 }
466
467 #[inline]
468 fn hash160(&self) -> [u8; 20] {
469 let mut result = [0x00; 20];
470 result[..].copy_from_slice(&Ripemd160::digest(&sha2::Sha256::digest(self)));
471 result
472 }
473
474 #[inline]
475 fn hash256(&self) -> [u8; 32] {
476 let mut result = [0x00; 32];
477 result[..].copy_from_slice(&sha2::Sha256::digest(&sha2::Sha256::digest(self)));
478 result
479 }
480
481 #[inline]
482 fn hex_string(&self) -> String {
483 let mut result = String::new();
484 for byte in self {
485 result = format!("{}{:02x}", result, byte);
486 }
487 result
488 }
489
490 #[inline]
491 fn p2wpkh(&self) -> Result<String, Error> {
492 if self.len() != NBBY_PUBC && self.len() != NBBY_PUBU {
493 return Err(Error::NbPubB(self.len()));
494 }
495 let mut address_bytes = vec![0x00]; address_bytes.append(&mut self.hash160().to_vec());
497 Ok(address_bytes.encode_base58ck())
498 }
499}
500
501impl Error {
503 #[doc(hidden)]
505 pub fn status(&self) -> i32 {
506 match self {
507 Error::Address => 1,
508 Error::Argument(_) => 2,
509 Error::Base58 => 3,
510 Error::Bech32 => 4,
511 Error::Bip38(_) => 5,
512 Error::Checksum => 6,
513 Error::Context(_) => 7,
514 Error::FromHard => 8,
515 Error::HexStr => 9,
516 Error::Hmac => 10,
517 Error::KeyLen => 11,
518 Error::KeyVer => 12,
519 Error::NbPubB(_) => 13,
520 Error::NotFound => 14,
521 Error::Path(_) => 15,
522 Error::PrvData => 16,
523 Error::PubData => 17,
524 Error::Range(_) => 18,
525 Error::SecEnt => 19,
526 Error::WifKey => 20,
527 }
528 }
529}
530
531impl ExtPrvKey {
533 fn as_bs58ck_prv(&self) -> String {
535 let mut result = [0x00; 82];
536 result[..NBBY_XKEY].copy_from_slice(&self.bytes_prv());
537 result[NBBY_XKEY..].copy_from_slice(&self.bytes_prv().hash256()[..4]);
538 bs58::encode(result).into_string()
539 }
540
541 fn bytes_prv(&self) -> [u8; 78] {
543 let mut result = [0x00; 78];
544 result[..4].copy_from_slice(&self.version);
545 result[4] = self.depth;
546 result[5..9].copy_from_slice(&self.parentf);
547 result[9..13].copy_from_slice(&self.childnb.to_be_bytes());
548 result[13..45].copy_from_slice(&self.chaincd);
549 result[45] = 0x00;
550 result[46..].copy_from_slice(&self.prvdata);
551 result
552 }
553
554 fn ckd_prv(&self, childnb: &u32) -> Result<ExtPrvKey, Error> {
556 let mut hmac =
557 Hmac::<sha2::Sha512>::new_from_slice(&self.chaincd).map_err(|_| Error::Hmac)?;
558
559 if childnb >= &HARD_NB {
560 hmac.update(&[0x00]); hmac.update(&self.prvdata);
562 } else {
563 hmac.update(&self.prvdata.public_key(true)?);
564 }
565
566 hmac.update(&childnb.to_be_bytes());
567
568 let r_hmac = hmac.finalize().into_bytes();
569 let mut sk = SecretKey::from_slice(&r_hmac[..32]).map_err(|_| Error::SecEnt)?;
570
571 sk = sk
572 .add_tweak(&Scalar::from_be_bytes(self.prvdata).map_err(|_| Error::SecEnt)?)
573 .map_err(|_| Error::SecEnt)?;
574
575 let (mut parentf, mut chaincd, mut prvdata) = ([0x00; 4], [0x00; 32], [0x00; 32]);
576
577 parentf[..].copy_from_slice(&self.prvdata.public_key(true)?.hash160()[..4]);
578 chaincd[..].copy_from_slice(&r_hmac[32..]);
579 prvdata[..].copy_from_slice(&sk[..]);
580
581 Ok(Self {
582 version: self.version,
583 depth: self.depth + 1,
584 parentf,
585 childnb: *childnb,
586 chaincd,
587 prvdata,
588 purpose: self.purpose,
589 })
590 }
591
592 fn derive_prv(&self, path: &[u32]) -> Result<ExtPrvKey, Error> {
594 let mut derived = *self;
595 for cnb in path {
596 derived = derived.ckd_prv(cnb)?;
597 }
598 Ok(derived)
599 }
600
601 fn from_bs58_prv(prvk: &str) -> Result<Self, Error> {
603 if prvk.len() < 4 || !prvk.is_char_boundary(4) || !PRE_PRV_KEY.contains(&(&prvk[..4])) {
604 return Err(Error::KeyVer);
605 } else if prvk.len() != LEN_XKEY {
606 return Err(Error::KeyLen);
607 }
608 let prvk = prvk.decode_base58ck()?;
609
610 if prvk.len() != NBBY_XKEY {
611 return Err(Error::KeyLen);
612 }
613 if prvk[45] != 0 {
614 return Err(Error::PrvData);
615 }
616
617 let (mut version, mut parentf, mut childnb, mut chaincd, mut prvdata) =
618 ([0x00; 4], [0x00; 4], [0x00; 4], [0x00; 32], [0x00; 32]);
619 version[..].copy_from_slice(&prvk[..4]);
620 parentf[..].copy_from_slice(&prvk[5..9]);
621 childnb[..].copy_from_slice(&prvk[9..13]);
622 chaincd[..].copy_from_slice(&prvk[13..45]);
623 prvdata[..].copy_from_slice(&prvk[46..]);
624
625 Ok(Self {
626 version,
627 depth: prvk[4],
628 parentf,
629 childnb: u32::from_be_bytes(childnb),
630 chaincd,
631 prvdata,
632 purpose: if prvk[..4] == TPRV || prvk[..4] == XPRV {
633 44
634 } else if prvk[..4] == UPRV || prvk[..4] == YPRV {
635 49
636 } else {
637 84
639 },
640 })
641 }
642
643 fn show_prv(
645 &self,
646 path: &[u32],
647 range: (u32, u32),
648 pass: &str,
649 separator: &str,
650 ) -> Result<(), Error> {
651 let base_path_str = path.encode_path();
652 let parent = self.derive_prv(path)?;
653
654 println!(
655 "{}\n{}",
656 parent.as_bs58ck_prv(),
657 ExtPubKey::from_prv(&parent)?.as_bs58ck_pub()
658 );
659
660 let encrypt = !pass.is_empty();
661
662 for child_nb in range.0..range.1 + 1 {
664 let child_prv = parent.derive_prv(&[child_nb])?;
665 let child_pub = ExtPubKey::from_prv(&child_prv)?;
666 let address = match child_prv.purpose {
667 44 => child_pub.pubdata.p2wpkh()?,
668 49 => child_pub.pubdata.segwit_p2wpkh_p2sh()?,
669 84 => child_pub.pubdata.segwit_p2wpkh()?,
670 _ => String::from("please, don't"),
671 };
672 let prv_str = if encrypt {
673 child_prv.prvdata.encrypt(pass, true)?
674 } else {
675 child_prv.prvdata.encode_wif(true)?
676 };
677 println!(
678 "{}/{}{}{}{}{}{}{}",
679 base_path_str,
680 child_nb,
681 separator,
682 address,
683 separator,
684 child_pub.pubdata.hex_string(),
685 separator,
686 prv_str
687 );
688 }
689 Ok(())
690 }
691}
692
693impl ExtPubKey {
695 fn as_bs58ck_pub(&self) -> String {
697 let mut result = [0x00; 82];
698 result[..NBBY_XKEY].copy_from_slice(&self.bytes_pub());
699 result[NBBY_XKEY..].copy_from_slice(&self.bytes_pub().hash256()[..4]);
700 bs58::encode(result).into_string()
701 }
702
703 fn bytes_pub(&self) -> [u8; 78] {
705 let mut result = [0x00; 78];
706 result[..4].copy_from_slice(&self.version);
707 result[4] = self.depth;
708 result[5..9].copy_from_slice(&self.parentf);
709 result[9..13].copy_from_slice(&self.childnb.to_be_bytes());
710 result[13..45].copy_from_slice(&self.chaincd);
711 result[45..].copy_from_slice(&self.pubdata);
712 result
713 }
714
715 fn ckd_pub(&self, childnb: &u32) -> Result<ExtPubKey, Error> {
717 if childnb >= &HARD_NB {
718 return Err(Error::FromHard);
719 }
720
721 let mut hmac =
722 Hmac::<sha2::Sha512>::new_from_slice(&self.chaincd).map_err(|_| Error::Hmac)?;
723
724 hmac.update(&self.pubdata);
725 hmac.update(&childnb.to_be_bytes());
726
727 let r_hmac = hmac.finalize().into_bytes();
728 let mut pubk = PublicKey::from_slice(&self.pubdata).map_err(|_| Error::PubData)?;
729
730 pubk = pubk
731 .add_exp_tweak(
732 &Secp256k1::new(),
733 &Scalar::from(SecretKey::from_slice(&r_hmac[..32]).map_err(|_| Error::SecEnt)?),
734 )
735 .map_err(|_| Error::SecEnt)?;
736
737 let (mut parentf, mut chaincd) = ([0x00; 4], [0x00; 32]);
738 parentf[..].copy_from_slice(&self.pubdata.hash160()[..4]);
739 chaincd[..].copy_from_slice(&r_hmac[32..]);
740
741 Ok(Self {
742 version: self.version,
743 depth: self.depth + 1,
744 parentf,
745 childnb: *childnb,
746 chaincd,
747 pubdata: pubk.serialize(),
748 purpose: self.purpose,
749 })
750 }
751
752 fn derive_pub(&self, path: &[u32]) -> Result<ExtPubKey, Error> {
754 let mut derived = *self;
755 for child_nb in path {
756 derived = derived.ckd_pub(child_nb)?;
757 }
758 Ok(derived)
759 }
760
761 fn from_bs58_pub(pubk: &str) -> Result<Self, Error> {
763 if pubk.len() < 4 || !pubk.is_char_boundary(4) || !PRE_PUB_KEY.contains(&(&pubk[..4])) {
764 return Err(Error::KeyVer);
765 } else if pubk.len() != LEN_XKEY {
766 return Err(Error::KeyLen);
767 }
768 let pubk = pubk.decode_base58ck()?;
769 if pubk.len() != NBBY_XKEY {
770 return Err(Error::KeyLen);
771 }
772
773 let (mut version, mut parentf, mut childnb, mut chaincd, mut pubdata) = (
774 [0x00; 4],
775 [0x00; 4],
776 [0x00; 4],
777 [0x00; 32],
778 [0x00; NBBY_PUBC],
779 );
780 version[..].copy_from_slice(&pubk[..4]);
781 parentf[..].copy_from_slice(&pubk[5..9]);
782 childnb[..].copy_from_slice(&pubk[9..13]);
783 chaincd[..].copy_from_slice(&pubk[13..45]);
784 pubdata[..].copy_from_slice(&pubk[45..]);
785
786 Ok(Self {
787 version,
788 depth: pubk[4],
789 parentf,
790 childnb: u32::from_be_bytes(childnb),
791 chaincd,
792 pubdata,
793 purpose: if pubk[..4] == TPUB || pubk[..4] == XPUB {
794 44
795 } else if pubk[..4] == UPUB || pubk[..4] == YPUB {
796 49
797 } else {
798 84
800 },
801 })
802 }
803
804 fn from_prv(prv: &ExtPrvKey) -> Result<ExtPubKey, Error> {
806 let mut pubdata = [0x00; NBBY_PUBC];
807 pubdata[..].copy_from_slice(&prv.prvdata.public_key(true)?);
808 Ok(ExtPubKey {
809 version: match prv.version {
810 TPRV => TPUB,
811 UPRV => UPUB,
812 VPRV => VPUB,
813 XPRV => XPUB,
814 YPRV => YPUB,
815 ZPRV => ZPUB,
816 _ => XPUB,
817 },
818 depth: prv.depth,
819 parentf: prv.parentf,
820 childnb: prv.childnb,
821 chaincd: prv.chaincd,
822 pubdata,
823 purpose: prv.purpose,
824 })
825 }
826
827 fn show_pub(&self, path: &[u32], range: (u32, u32), separator: &str) -> Result<(), Error> {
829 if range.0 >= HARD_NB || range.1 >= HARD_NB {
830 return Err(Error::FromHard);
831 }
832 let base_path_str = path.encode_path();
833 let parent = self.derive_pub(path)?;
834 println!("{}", parent.as_bs58ck_pub());
835 for child_nb in range.0..range.1 + 1 {
836 let child = parent.derive_pub(&[child_nb])?;
837 let address = match child.purpose {
838 44 => child.pubdata.p2wpkh()?,
839 49 => child.pubdata.segwit_p2wpkh_p2sh()?,
840 84 => child.pubdata.segwit_p2wpkh()?,
841 _ => String::from("please, don't"),
842 };
843
844 println!(
845 "{}/{}{}{}{}{}",
846 base_path_str,
847 child_nb,
848 separator,
849 address,
850 separator,
851 child.pubdata.hex_string()
852 );
853 }
854 Ok(())
855 }
856}
857
858impl PathManipulation for [u32] {
860 #[inline]
861 fn encode_path(&self) -> String {
862 if self.is_empty() {
863 return String::from(PATH_START);
864 }
865 let mut encoded_path = String::from(PATH_START);
866 for value in self {
867 let child = if value < &HARD_NB {
868 format!("{}", value)
869 } else {
870 format!("{}{}", value - HARD_NB, HARD_CHAR)
871 };
872 encoded_path += &format!("{}{}", SEP_PATH, child);
873 }
874 encoded_path
875 }
876}
877
878impl PrivateKeyManipulation for [u8; 32] {
880 #[inline]
881 fn encode_wif(&self, compress: bool) -> Result<String, Error> {
882 let mut decoded: Vec<u8> = vec![PRE_WIF_B];
883 decoded.append(&mut self.to_vec());
884 if compress {
885 decoded.push(0x01);
886 }
887 Ok(decoded.encode_base58ck())
888 }
889
890 #[inline]
891 fn public_key(&self, compress: bool) -> Result<Vec<u8>, Error> {
892 let secp_pub = PublicKey::from_secret_key(
893 &Secp256k1::new(),
894 &SecretKey::from_slice(self).map_err(|_| Error::SecEnt)?,
895 );
896 if compress {
897 Ok(secp_pub.serialize().to_vec())
898 } else {
899 Ok(secp_pub.serialize_uncompressed().to_vec())
900 }
901 }
902}
903
904impl PublicKeyCompressedManipulation for [u8; NBBY_PUBC] {
906 #[inline]
907 fn segwit_p2wpkh(&self) -> Result<String, Error> {
908 let witness_program = WitnessProgram::new(
910 u5::try_from_u8(0).map_err(|_| Error::Bech32)?,
911 self.hash160().to_vec(),
912 Network::Bitcoin,
913 )
914 .map_err(|_| Error::Bech32)?;
915 Ok(witness_program.to_address())
916 }
917
918 #[inline]
919 fn segwit_p2wpkh_p2sh(&self) -> Result<String, Error> {
920 let mut redeem_script = vec![OP_0, OP_PUSH20];
921 redeem_script.append(&mut self.hash160().to_vec());
922 let mut address_bytes = vec![PRE_P2WPKH_P2SH_B];
923 address_bytes.append(&mut redeem_script.hash160().to_vec());
924 Ok(address_bytes.encode_base58ck())
925 }
926}
927
928impl StringManipulation for str {
930 #[inline]
931 fn decode_address(&self) -> Result<Vec<u8>, Error> {
932 if self.len() == LEN_SEGWIT && self.starts_with("bc") {
933 let decoded = WitnessProgram::from_address(&self)
934 .map_err(|_| Error::Bech32)?
935 .program()
936 .to_vec();
937 Ok(decoded)
938 } else if (self.starts_with('1') || self.starts_with('3'))
939 && self.len() >= LEN_LEG_MIN
940 && self.len() <= LEN_LEG_MAX
941 {
942 let decoded = &self.decode_base58ck()?[1..]; Ok(decoded.to_vec())
944 } else {
945 Err(Error::Address)
946 }
947 }
948
949 #[inline]
950 fn decode_base58ck(&self) -> Result<Vec<u8>, Error> {
951 if self.len() < LEN_ARG_MIN {
952 return Err(Error::Argument(String::from(self)));
954 }
955 let raw = bs58::decode(self).into_vec().map_err(|_| Error::Base58)?;
956 if raw[raw.len() - 4..] == raw[..raw.len() - 4].hash256()[..4] {
957 Ok(raw[..(raw.len() - 4)].to_vec())
958 } else {
959 Err(Error::Checksum)
960 }
961 }
962
963 #[inline]
964 fn decode_wif(&self) -> Result<([u8; 32], bool), Error> {
965 if (!self.is_char_boundary(1) || !PRE_WIF_C.contains(&self[..1]) || self.len() != LEN_WIF_C)
966 && (!self.starts_with(PRE_WIF_U) || self.len() != LEN_WIF_U)
967 {
968 return Err(Error::WifKey);
969 }
970 let raw_bytes = self.decode_base58ck()?;
971 if (raw_bytes.len() != NBBY_WIFC && raw_bytes.len() != NBBY_WIFU)
972 || raw_bytes[0] != PRE_WIF_B
973 {
974 return Err(Error::WifKey);
975 }
976 let mut payload = [0x00; 32];
977 payload[..].copy_from_slice(&raw_bytes[1..33]);
978 Ok((payload, raw_bytes.len() == NBBY_WIFC))
979 }
980
981 #[inline]
982 fn hex_bytes(&self) -> Result<Vec<u8>, Error> {
983 let mut out = Vec::new();
984 for index in (0..self.len()).step_by(2) {
985 out.push(u8::from_str_radix(&self[index..index + 2], 16).map_err(|_| Error::HexStr)?);
986 }
987 Ok(out)
988 }
989
990 #[inline]
991 fn info_entropy(&self, pass: &str, separator: &str) -> Result<(), Error> {
992 if self.len() != 64 {
993 return Err(Error::SecEnt);
994 }
995 let mut secret = [0x00; 32];
996 secret[..].copy_from_slice(&self.hex_bytes()?);
997 let mut pubc = [0x00; NBBY_PUBC];
998 pubc[..].copy_from_slice(&secret.public_key(true)?);
999 let pubu = secret.public_key(false)?;
1000 let hex_pubc = pubc.hex_string();
1001 let secret_str = if pass.is_empty() {
1002 secret.encode_wif(true)?
1003 } else {
1004 secret.encrypt(pass, true)?
1005 };
1006
1007 if separator == DEF_SEP {
1008 println!(
1009 "{:42}{}{}{}{}\n{:42}{}{}{}{}\n{}{}{}{}{}",
1010 pubc.p2wpkh()?,
1011 separator,
1012 hex_pubc,
1013 separator,
1014 secret_str,
1015 pubc.segwit_p2wpkh_p2sh()?,
1016 separator,
1017 hex_pubc,
1018 separator,
1019 secret_str,
1020 pubc.segwit_p2wpkh()?,
1021 separator,
1022 hex_pubc,
1023 separator,
1024 secret_str
1025 );
1026 } else {
1027 println!(
1028 "{}{}{}{}{}\n{}{}{}{}{}\n{}{}{}{}{}",
1029 pubc.p2wpkh()?,
1030 separator,
1031 hex_pubc,
1032 separator,
1033 secret_str,
1034 pubc.segwit_p2wpkh_p2sh()?,
1035 separator,
1036 hex_pubc,
1037 separator,
1038 secret_str,
1039 pubc.segwit_p2wpkh()?,
1040 separator,
1041 hex_pubc,
1042 separator,
1043 secret_str
1044 );
1045 }
1046
1047 println!(
1048 "{}{}{}{}{}",
1049 pubu.p2wpkh()?,
1050 separator,
1051 pubu.hex_string(),
1052 separator,
1053 if pass.is_empty() {
1054 secret.encode_wif(false)?
1055 } else {
1056 secret.encrypt(pass, false)?
1057 }
1058 );
1059 Ok(())
1060 }
1061
1062 #[inline]
1063 fn info_wif(&self, pass: &str, separator: &str) -> Result<(), Error> {
1064 let (secret, compress) = self.decode_wif()?;
1065 let public = secret.public_key(compress)?;
1066 let secret = if !pass.is_empty() {
1067 secret.encrypt(pass, compress)?
1068 } else {
1069 String::from(self)
1070 };
1071
1072 if compress {
1073 let hex_pubc = public.hex_string();
1074 let mut public_comp = [0x00; NBBY_PUBC];
1075 public_comp[..].copy_from_slice(&public);
1076 if separator == DEF_SEP {
1077 println!(
1078 "{:42}{}{}{}{}\n{:42}{}{}{}{}\n{}{}{}{}{}",
1079 public_comp.p2wpkh()?,
1080 separator,
1081 hex_pubc,
1082 separator,
1083 secret,
1084 public_comp.segwit_p2wpkh_p2sh()?,
1085 separator,
1086 hex_pubc,
1087 separator,
1088 secret,
1089 public_comp.segwit_p2wpkh()?,
1090 separator,
1091 hex_pubc,
1092 separator,
1093 secret
1094 );
1095 } else {
1096 println!(
1097 "{}{}{}{}{}\n{}{}{}{}{}\n{}{}{}{}{}",
1098 public_comp.p2wpkh()?,
1099 separator,
1100 hex_pubc,
1101 separator,
1102 secret,
1103 public_comp.segwit_p2wpkh_p2sh()?,
1104 separator,
1105 hex_pubc,
1106 separator,
1107 secret,
1108 public_comp.segwit_p2wpkh()?,
1109 separator,
1110 hex_pubc,
1111 separator,
1112 secret
1113 );
1114 };
1115 } else {
1116 println!(
1117 "{}{}{}{}{}",
1118 public.p2wpkh()?,
1119 separator,
1120 public.hex_string(),
1121 separator,
1122 secret
1123 );
1124 }
1125 Ok(())
1126 }
1127
1128 #[inline]
1129 fn is_hex(&self) -> bool {
1130 for c in self.chars() {
1131 if !c.is_ascii_hexdigit() {
1132 return false;
1133 }
1134 }
1135 true
1136 }
1137
1138 #[inline]
1139 fn decode_path(&self, public: bool) -> Result<Vec<u32>, Error> {
1140 if self.is_empty() || !self.starts_with(PATH_START) {
1141 return Err(Error::Path(String::from(self)));
1142 } else if public && self.contains(HARD_CHAR) {
1143 return Err(Error::FromHard);
1144 }
1145
1146 let mut result: Vec<u32> = Vec::new();
1147 let mut first_m = true; for cnb in self.split_terminator(SEP_PATH) {
1150 let mut total: u32 = 0;
1151
1152 if cnb.is_empty() {
1153 return Err(Error::Path(String::from("//")));
1154 } else if cnb == PATH_START && first_m {
1155 first_m = false;
1156 continue;
1157 } else if cnb.ends_with(HARD_CHAR) {
1158 total += match cnb.trim_end_matches(HARD_CHAR).parse::<u32>() {
1159 Ok(value) => {
1160 if value < HARD_NB {
1161 HARD_NB + value } else {
1163 return Err(Error::Path(String::from(cnb)));
1164 }
1165 }
1166 Err(_) => return Err(Error::Path(String::from(cnb))),
1167 };
1168 } else {
1169 total = match cnb.parse::<u32>() {
1170 Ok(value) => {
1171 if value < HARD_NB {
1172 value
1174 } else {
1175 return Err(Error::Path(String::from(cnb)));
1176 }
1177 }
1178 Err(_) => return Err(Error::Path(String::from(cnb))),
1179 };
1180 }
1181 result.push(total);
1182 }
1183 Ok(result)
1184 }
1185
1186 #[inline]
1187 fn decode_range(&self) -> Result<(u32, u32), Error> {
1188 if !self.contains(SEP_RANGE) {
1189 match self.trim_end_matches(HARD_CHAR).parse::<u32>() {
1190 Ok(value) => {
1191 if self.ends_with(HARD_CHAR) {
1192 return Ok((value + HARD_NB, value + HARD_NB));
1193 } else {
1194 return Ok((value, value));
1195 }
1196 }
1197 Err(_) => return Err(Error::Range(String::from(self))),
1198 }
1199 }
1200
1201 let (start, stop) = self
1202 .split_once(SEP_RANGE)
1203 .ok_or_else(|| Error::Range(String::from(self)))?;
1204
1205 if start.ends_with(HARD_CHAR) && !stop.is_empty() && !stop.ends_with(HARD_CHAR) {
1206 return Err(Error::Range(String::from(stop)));
1207 }
1208
1209 let start = match start.parse::<u32>() {
1210 Ok(value) => {
1211 if value < HARD_NB {
1212 value
1213 } else {
1214 return Err(Error::Range(String::from(start)));
1215 }
1216 }
1217 Err(_) => {
1218 if start.is_empty() {
1219 0
1220 } else if start.ends_with(HARD_CHAR) {
1221 match start.trim_end_matches(HARD_CHAR).parse::<u32>() {
1222 Ok(value) => {
1223 if value < HARD_NB {
1224 value + HARD_NB
1225 } else {
1226 return Err(Error::Range(String::from(start)));
1227 }
1228 }
1229 Err(_) => return Err(Error::Range(String::from(start))),
1230 }
1231 } else {
1232 return Err(Error::Range(String::from(start)));
1233 }
1234 }
1235 };
1236
1237 let stop = match stop.parse::<u32>() {
1238 Ok(value) => {
1239 if value < HARD_NB {
1240 value
1241 } else {
1242 return Err(Error::Range(String::from(stop)));
1243 }
1244 }
1245 Err(_) => {
1246 if stop.is_empty() && start < HARD_NB {
1247 HARD_NB - 1
1248 } else if stop.is_empty() && start >= HARD_NB {
1249 u32::MAX
1250 } else if stop.ends_with(HARD_CHAR) {
1251 match stop.trim_end_matches(HARD_CHAR).parse::<u32>() {
1252 Ok(value) => {
1253 if value < HARD_NB {
1254 value + HARD_NB
1255 } else {
1256 return Err(Error::Range(String::from(stop)));
1257 }
1258 }
1259 Err(_) => return Err(Error::Range(String::from(stop))),
1260 }
1261 } else {
1262 return Err(Error::Range(String::from(stop)));
1263 }
1264 }
1265 };
1266
1267 if start >= stop {
1268 Err(Error::Range(String::from(self)))
1269 } else {
1270 Ok((start, stop))
1271 }
1272 }
1273}
1274
1275#[doc(hidden)]
1277pub fn handle_arguments(matches: ArgMatches) -> Result<(), Error> {
1278 let nothing = "".to_string();
1279 let def_sep = DEF_SEP.to_string();
1280 let data = matches.get_one::<String>("DATA").ok_or(Error::NotFound)?;
1281 let passphrase = matches.get_one::<String>("passphrase").unwrap_or(¬hing);
1282 let path = matches.get_one::<String>("path").unwrap_or(¬hing);
1283 let range = matches.get_one::<String>("range").unwrap_or(¬hing);
1284 let rng_t = if range.is_empty() {
1285 DEF_RNG
1286 } else {
1287 range.decode_range()?
1288 };
1289 let separator = matches.get_one::<String>("separator").unwrap_or(&def_sep);
1290
1291 if PRE_WIF_C.contains(&data[..1]) || data.starts_with(PRE_WIF_U) {
1292 if !path.is_empty() {
1293 return Err(Error::Context(String::from("p")));
1294 } else if !range.is_empty() {
1295 return Err(Error::Context(String::from("r")));
1296 }
1297 data.info_wif(passphrase, separator)?;
1298 } else if data.is_hex() && data.len() == 64 {
1299 if !path.is_empty() {
1300 return Err(Error::Context(String::from("p")));
1301 } else if !range.is_empty() {
1302 return Err(Error::Context(String::from("r")));
1303 }
1304 data.info_entropy(passphrase, separator)?;
1305 } else if PRE_ADDR.contains(&data[..1]) || PRE_ADDR.contains(&data[..2]) {
1306 if matches.contains_id("passphrase") {
1307 return Err(Error::Context(String::from("e")));
1309 } else if !path.is_empty() {
1310 return Err(Error::Context(String::from("p")));
1311 } else if !range.is_empty() {
1312 return Err(Error::Context(String::from("r")));
1313 } else if matches.contains_id("separator") {
1314 return Err(Error::Context(String::from("s")));
1316 }
1317 println!("{}", data.decode_address()?.hex_string());
1318 } else if PRE_PRV_KEY.contains(&(&data[..4])) {
1319 let parent = ExtPrvKey::from_bs58_prv(data)?;
1320 parent.show_prv(
1321 &if path.is_empty() {
1322 vec![parent.purpose + HARD_NB, HARD_NB, HARD_NB, 0]
1324 } else {
1325 path.decode_path(false)?
1326 },
1327 rng_t,
1328 passphrase,
1329 separator,
1330 )?;
1331 } else if PRE_PUB_KEY.contains(&(&data[..4])) {
1332 if matches.contains_id("passphrase") {
1333 return Err(Error::Context(String::from("e")));
1334 }
1335 ExtPubKey::from_bs58_pub(data)?.show_pub(
1336 &if path.is_empty() {
1337 vec![]
1339 } else {
1340 path.decode_path(true)?
1341 },
1342 rng_t,
1343 separator,
1344 )?;
1345 } else {
1346 return Err(Error::Argument(String::from(data)));
1347 }
1348 Ok(())
1349}
1350
1351#[doc(hidden)]
1353pub fn init_clap() -> Command {
1354 Command::new("derivation32")
1355 .about(ABOUT)
1356 .version(crate_version!())
1357 .arg(
1358 Arg::new("DATA")
1359 .help("Address, hexadecimal entropy, extended key or wif key")
1360 .required(true)
1361 .value_parser(OsStringValueParser::new().try_map(validate_data)),
1362 )
1363 .arg(
1364 Arg::new("passphrase")
1365 .help("Encrypt resulting private keys (bip-0038)")
1366 .short('e'),
1367 )
1368 .arg(
1369 Arg::new("path")
1370 .help("Path used to derive the extended private key")
1371 .short('p')
1372 .value_parser(OsStringValueParser::new().try_map(validate_path)),
1373 )
1374 .arg(
1375 Arg::new("range")
1376 .help("Closed range in the form of (1..9h) used on derivation")
1377 .short('r')
1378 .value_parser(OsStringValueParser::new().try_map(validate_range)),
1379 )
1380 .arg(
1381 Arg::new("separator")
1382 .help("Specify a character (or string) to separate results")
1383 .short('s'),
1384 )
1385}
1386
1387fn validate_data(data_os: OsString) -> Result<String, &'static str> {
1389 let data = data_os.to_str().unwrap_or("");
1390 if data.len() >= LEN_ARG_MIN && (data.len() == LEN_WIF_C &&
1391 data.is_char_boundary(1) && PRE_WIF_C.contains(&data[..1])) ||
1392 (data.len() == LEN_WIF_U && data.starts_with(PRE_WIF_U)) || data.len() == 64 && data.is_hex() || (data.len() >= LEN_LEG_MIN && data.len() <= LEN_LEG_MAX &&
1395 data.is_char_boundary(1) && PRE_ADDR.contains(&data[..1])) ||
1396 (data.len() == LEN_SEGWIT && data.is_char_boundary(2) &&
1397 PRE_ADDR.contains(&data[..2])) || data.is_char_boundary(4) && (PRE_PRV_KEY.contains(&(&data[..4]))
1399 || PRE_PUB_KEY.contains(&(&data[..4]))) && data.len() == LEN_XKEY
1400 {
1401 Ok(data.to_string()) } else {
1403 Err("not a hexadecimal entropy, extended key or wif key")
1404 }
1405}
1406
1407fn validate_path(path_os: OsString) -> Result<String, &'static str> {
1409 let path = path_os.to_str().unwrap_or("");
1410 if path.decode_path(false).is_ok() {
1411 Ok(path.to_string())
1412 } else {
1413 Err("path error")
1414 }
1415}
1416
1417fn validate_range(range_os: OsString) -> Result<String, &'static str> {
1419 let range = range_os.to_str().unwrap_or("");
1420 if range.decode_range().is_ok() {
1421 Ok(range.to_string())
1422 } else {
1423 Err("range error")
1424 }
1425}
1426
1427#[cfg(test)]
1429mod tests {
1430 use super::*;
1431
1432 const DS256_F: [u8; 32] = [
1434 0x71, 0xca, 0x50, 0x49, 0x66, 0x1b, 0x67, 0xd2, 0xba, 0xba, 0xf3, 0x06, 0xcd, 0x9b, 0xc8,
1435 0x09, 0x0a, 0x93, 0x32, 0x4c, 0x2d, 0x4f, 0xf1, 0xbb, 0x12, 0xa3, 0x71, 0xa0, 0x2c, 0xc2,
1436 0x3e, 0xb8,
1437 ];
1438
1439 const DS256_L: [u8; 32] = [
1441 0xc1, 0x61, 0xd0, 0x98, 0x17, 0x97, 0x65, 0xc7, 0x6b, 0x8a, 0x2e, 0xae, 0xbd, 0xd1, 0xcc,
1442 0x27, 0x6c, 0xfa, 0x02, 0x72, 0x18, 0xe6, 0x9c, 0x09, 0xb7, 0xa0, 0x94, 0x7e, 0x81, 0xc7,
1443 0x60, 0x85,
1444 ];
1445
1446 const DS256_Z: [u8; 32] = [
1448 0x14, 0x06, 0xe0, 0x58, 0x81, 0xe2, 0x99, 0x36, 0x77, 0x66, 0xd3, 0x13, 0xe2, 0x6c, 0x05,
1449 0x56, 0x4e, 0xc9, 0x1b, 0xf7, 0x21, 0xd3, 0x17, 0x26, 0xbd, 0x6e, 0x46, 0xe6, 0x06, 0x89,
1450 0x53, 0x9a,
1451 ];
1452
1453 const H160_33_1: [u8; 20] = [
1455 0x8e, 0xc4, 0xcf, 0x3e, 0xe1, 0x60, 0xb0, 0x54, 0xe0, 0xab, 0xb6, 0xf5, 0xc8, 0x17, 0x7b,
1456 0x9e, 0xe5, 0x6f, 0xa5, 0x1e,
1457 ];
1458
1459 const H160_33_L: [u8; 20] = [
1461 0x05, 0x88, 0xa4, 0x7e, 0x70, 0xb0, 0x2d, 0x64, 0x6a, 0xb0, 0x65, 0x80, 0x50, 0x74, 0x66,
1462 0x25, 0xb0, 0x51, 0x03, 0xc8,
1463 ];
1464
1465 const HEX_STR_0: &str = "0000000000000000000000000000000000000000000000000000000000000000";
1467
1468 const HEX_STR_1: &str = "1111111111111111111111111111111111111111111111111111111111111111";
1470
1471 const HEX_STR_F: &str = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
1473
1474 const HEX_STR_L: &str = "6969696969696969696969696969696969696969696969696969696969696969";
1476
1477 const P2WPKH_C_1: &str = "1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9";
1479
1480 const P2WPKH_C_A: &str = "16JrGhLx5bcBSA34kew9V6Mufa4aXhFe9X";
1482
1483 const P2WPKH_C_L: &str = "1N7qxowv8SnfdBYhmvpxZxyjsYQDPd88ES";
1485
1486 const P2WPKH_P2SH_1: &str = "3PFpzMLrKWsphFtc8BesF3MGPnimKMuF4x";
1488
1489 const P2WPKH_P2SH_A: &str = "34N3tf5m5rdNhW5zpTXNEJucHviFEa8KEq";
1491
1492 const P2WPKH_P2SH_L: &str = "35E9BxrEWjgHDFWucazLK5VVxH5oGLRj4g";
1494
1495 const P2WPKH_U_1: &str = "1MsHWS1BnwMc3tLE8G35UXsS58fKipzB7a";
1497
1498 const P2WPKH_U_A: &str = "19P1LctLQmH6tuHCRkv8QznNBGBvFCyKxi";
1500
1501 const P2WPKH_U_L: &str = "17iS4e5ib2t2Bj2UFjPbxSDdmecHNnCAwy";
1503
1504 const P2WPKH_Z_0: &str = "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA";
1506
1507 const P2WPKH_Z_19: &str = "19hp5PzFjsD6z1hwMucUbLHAYeYDWdvB1B";
1509
1510 const P2WPKH_B: [u8; 32] = [
1512 0xa9, 0x66, 0xeb, 0x60, 0x58, 0xf8, 0xec, 0x9f, 0x47, 0x07, 0x4a, 0x2f, 0xaa, 0xdd, 0x3d,
1513 0xab, 0x42, 0xe2, 0xc6, 0x0e, 0xd0, 0x5b, 0xc3, 0x4d, 0x39, 0xd6, 0xc0, 0xe1, 0xd3, 0x2b,
1514 0x8b, 0xdf,
1515 ];
1516
1517 const PUB_C_A: [u8; NBBY_PUBC] = [
1519 0x02, 0x3c, 0xba, 0x1f, 0x4d, 0x12, 0xd1, 0xce, 0x0b, 0xce, 0xd7, 0x25, 0x37, 0x37, 0x69,
1520 0xb2, 0x26, 0x2c, 0x6d, 0xaa, 0x97, 0xbe, 0x6a, 0x05, 0x88, 0xcf, 0xec, 0x8c, 0xe1, 0xa5,
1521 0xf0, 0xbd, 0x09,
1522 ];
1523
1524 const PUB_C_1: [u8; NBBY_PUBC] = [
1526 0x03, 0x4f, 0x35, 0x5b, 0xdc, 0xb7, 0xcc, 0x0a, 0xf7, 0x28, 0xef, 0x3c, 0xce, 0xb9, 0x61,
1527 0x5d, 0x90, 0x68, 0x4b, 0xb5, 0xb2, 0xca, 0x5f, 0x85, 0x9a, 0xb0, 0xf0, 0xb7, 0x04, 0x07,
1528 0x58, 0x71, 0xaa,
1529 ];
1530
1531 const PUB_C_L: [u8; NBBY_PUBC] = [
1533 0x02, 0x66, 0x6b, 0xdf, 0x20, 0x25, 0xe3, 0x2f, 0x41, 0x08, 0x88, 0x99, 0xf2, 0xbc, 0xb4,
1534 0xbf, 0x69, 0x83, 0x18, 0x7f, 0x38, 0x0e, 0x72, 0xfc, 0x7d, 0xee, 0x11, 0x5b, 0x1f, 0x99,
1535 0x57, 0xcc, 0x72,
1536 ];
1537
1538 const PUB_U_1: [u8; NBBY_PUBU] = [
1540 0x04, 0x4f, 0x35, 0x5b, 0xdc, 0xb7, 0xcc, 0x0a, 0xf7, 0x28, 0xef, 0x3c, 0xce, 0xb9, 0x61,
1541 0x5d, 0x90, 0x68, 0x4b, 0xb5, 0xb2, 0xca, 0x5f, 0x85, 0x9a, 0xb0, 0xf0, 0xb7, 0x04, 0x07,
1542 0x58, 0x71, 0xaa, 0x38, 0x5b, 0x6b, 0x1b, 0x8e, 0xad, 0x80, 0x9c, 0xa6, 0x74, 0x54, 0xd9,
1543 0x68, 0x3f, 0xcf, 0x2b, 0xa0, 0x34, 0x56, 0xd6, 0xfe, 0x2c, 0x4a, 0xbe, 0x2b, 0x07, 0xf0,
1544 0xfb, 0xdb, 0xb2, 0xf1, 0xc1,
1545 ];
1546
1547 const PUB_U_A: [u8; NBBY_PUBU] = [
1549 0x04, 0x3c, 0xba, 0x1f, 0x4d, 0x12, 0xd1, 0xce, 0x0b, 0xce, 0xd7, 0x25, 0x37, 0x37, 0x69,
1550 0xb2, 0x26, 0x2c, 0x6d, 0xaa, 0x97, 0xbe, 0x6a, 0x05, 0x88, 0xcf, 0xec, 0x8c, 0xe1, 0xa5,
1551 0xf0, 0xbd, 0x09, 0x2f, 0x56, 0xb5, 0x49, 0x2a, 0xdb, 0xfc, 0x57, 0x0b, 0x15, 0x64, 0x4c,
1552 0x74, 0xcc, 0x8a, 0x48, 0x74, 0xed, 0x20, 0xdf, 0xe4, 0x7e, 0x5d, 0xce, 0x2e, 0x08, 0x60,
1553 0x1d, 0x6f, 0x11, 0xf5, 0xa4,
1554 ];
1555
1556 const PUB_U_L: [u8; NBBY_PUBU] = [
1558 0x04, 0x66, 0x6b, 0xdf, 0x20, 0x25, 0xe3, 0x2f, 0x41, 0x08, 0x88, 0x99, 0xf2, 0xbc, 0xb4,
1559 0xbf, 0x69, 0x83, 0x18, 0x7f, 0x38, 0x0e, 0x72, 0xfc, 0x7d, 0xee, 0x11, 0x5b, 0x1f, 0x99,
1560 0x57, 0xcc, 0x72, 0x9d, 0xd9, 0x76, 0x13, 0x1c, 0x4c, 0x8e, 0x12, 0xab, 0x10, 0x83, 0xca,
1561 0x06, 0x54, 0xca, 0x5f, 0xdb, 0xca, 0xc8, 0xd3, 0x19, 0x8d, 0xaf, 0x90, 0xf5, 0x81, 0xb5,
1562 0x91, 0xd5, 0x63, 0x79, 0xca,
1563 ];
1564
1565 const SEGW_1: &str = "bc1ql3e9pgs3mmwuwrh95fecme0s0qtn2880lsvsd5";
1567
1568 const SEGW_A: &str = "bc1q8gudgnt2pjxshwzwqgevccet0eyvwtswt03nuy";
1570
1571 const SEGW_L: &str = "bc1qu7nqysur9dr49e4vd9xvguwh5ewzft597d8mc7";
1573
1574 const SEGW_DEC_1: [u8; 20] = [
1576 0xfc, 0x72, 0x50, 0xa2, 0x11, 0xde, 0xdd, 0xc7, 0x0e, 0xe5, 0xa2, 0x73, 0x8d, 0xe5, 0xf0,
1577 0x78, 0x17, 0x35, 0x1c, 0xef,
1578 ];
1579
1580 const SEGW_DEC_A: [u8; 20] = [
1582 0x3a, 0x38, 0xd4, 0x4d, 0x6a, 0x0c, 0x8d, 0x0b, 0xb8, 0x4e, 0x02, 0x32, 0xcc, 0x63, 0x2b,
1583 0x7e, 0x48, 0xc7, 0x2e, 0x0e,
1584 ];
1585
1586 const SEGW_DEC_L: [u8; 20] = [
1588 0xe7, 0xa6, 0x02, 0x43, 0x83, 0x2b, 0x47, 0x52, 0xe6, 0xac, 0x69, 0x4c, 0xc4, 0x71, 0xd7,
1589 0xa6, 0x5c, 0x24, 0xae, 0x85,
1590 ];
1591
1592 const TV_32_01_PATH: [&str; 6] = [
1594 "m",
1595 "m/0h",
1596 "m/0h/1",
1597 "m/0h/1/2h",
1598 "m/0h/1/2h/2",
1599 "m/0h/1/2h/2/1000000000",
1600 ];
1601
1602 const TV_32_02_PATH: [&str; 6] = [
1604 "m",
1605 "m/0",
1606 "m/0/2147483647h",
1607 "m/0/2147483647h/1",
1608 "m/0/2147483647h/1/2147483646h",
1609 "m/0/2147483647h/1/2147483646h/2",
1610 ];
1611
1612 const TV_32_03_PATH: [&str; 2] = ["m", "m/0h"];
1614
1615 const TV_32_01_XPRV: [[&str; 2]; 6] = [
1617 [
1618 "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kej",
1619 "MRNNU3TGtRBeJgk33yuGBxrMPHi",
1620 ],
1621 [
1622 "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT",
1623 "11eZG7XnxHrnYeSvkzY7d2bhkJ7",
1624 ],
1625 [
1626 "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg",
1627 "8MSY3H2EU4pWcQDnRnrVA1xe8fs",
1628 ],
1629 [
1630 "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewR",
1631 "iNMjANTtpgP4mLTj34bhnZX7UiM",
1632 ],
1633 [
1634 "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqs",
1635 "unu5Mm3wDvUAKRHSC34sJ7in334",
1636 ],
1637 [
1638 "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rF",
1639 "SruoUihUZREPSL39UNdE3BBDu76",
1640 ],
1641 ];
1642
1643 const TV_32_02_XPRV: [[&str; 2]; 6] = [
1645 [
1646 "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNq",
1647 "Pqm55Qn3LqFtT2emdEXVYsCzC2U",
1648 ],
1649 [
1650 "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1e",
1651 "x8G81dwSM1fwqWpWkeS3v86pgKt",
1652 ],
1653 [
1654 "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kR",
1655 "gVsFawNzmjuHc2YmYRmagcEPdU9",
1656 ],
1657 [
1658 "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXa",
1659 "jPPdbRCHuWS6T8XA2ECKADdw4Ef",
1660 ],
1661 [
1662 "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcx",
1663 "FLJ8HFsTjSyQbLYnMpCqE2VbFWc",
1664 ],
1665 [
1666 "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWT",
1667 "yefMLEcBYJUuekgW4BYPJcr9E7j",
1668 ],
1669 ];
1670
1671 const TV_32_03_XPRV: [[&str; 2]; 2] = [
1673 [
1674 "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9",
1675 "dGuVrtHHs7pXeTzjuxBrCmmhgC6",
1676 ],
1677 [
1678 "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJ",
1679 "CVVFceUvJFjaPdGZ2y9WACViL4L",
1680 ],
1681 ];
1682
1683 const TV_32_01_XPUB: [[&str; 2]; 6] = [
1685 [
1686 "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqs",
1687 "efD265TMg7usUDFdp6W1EGMcet8",
1688 ],
1689 [
1690 "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1",
1691 "bgwQ9xv5ski8PX9rL2dZXvgGDnw",
1692 ],
1693 [
1694 "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq",
1695 "527Hqck2AxYysAA7xmALppuCkwQ",
1696 ],
1697 [
1698 "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7",
1699 "n7epu4trkrX7x7DogT5Uv6fcLW5",
1700 ],
1701 [
1702 "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37",
1703 "sR62cfN7fe5JnJ7dh8zL4fiyLHV",
1704 ],
1705 [
1706 "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8",
1707 "yGasTvXEYBVPamhGW6cFJodrTHy",
1708 ],
1709 ];
1710
1711 const TV_32_02_XPUB: [[&str; 2]; 6] = [
1713 [
1714 "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6",
1715 "mr8BDzTJY47LJhkJ8UB7WEGuduB",
1716 ],
1717 [
1718 "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDzn",
1719 "ezpbZb7ap6r1D3tgFxHmwMkQTPH",
1720 ],
1721 [
1722 "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8",
1723 "RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
1724 ],
1725 [
1726 "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89",
1727 "LojfZ537wTfunKau47EL2dhHKon",
1728 ],
1729 [
1730 "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY",
1731 "2grBGRjaDMzQLcgJvLJuZZvRcEL",
1732 ],
1733 [
1734 "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2",
1735 "rnY5agb9rXpVGyy3bdW6EEgAtqt",
1736 ],
1737 ];
1738
1739 const TV_32_03_XPUB: [[&str; 2]; 2] = [
1741 [
1742 "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1",
1743 "cZAceL7SfJ1Z3GC8vBgp2epUt13",
1744 ],
1745 [
1746 "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9M",
1747 "Yo6oDaPPLPxSb7gwQN3ih19Zm4Y",
1748 ],
1749 ];
1750
1751 const WIF_1: &str = "5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh";
1753
1754 const WIF_A: &str = "5K6tjEYPunJtSHRbWLSWtYGXmeFW4UJStKb3RUo5VUqQtksHkze";
1756
1757 const WIF_L: &str = "5JciBbkdYdjKKE9rwZ7c1XscwwcLBbv9aJyeZeWQi2gZnHeiX57";
1759
1760 const WIC_1: &str = "KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp";
1762
1763 const WIC_A: &str = "L2u1KQma7xyx2bVZJUocvV1Yp3R1GKW1FX3Fh3gNphrgTDVqp1sG";
1765
1766 const WIC_L: &str = "KzkcmnPaJd7mqT47Rnk9XMGRfW2wfo7ar2M2o6Yoe6Rdgbg2bHM9";
1768
1769 const XPRV_A: [&str; 2] = [
1771 "xprv9s21ZrQH143K3t4UZrNgeA3w861fwjYLaGwmPtQyPMmzshV2owVpfBSd2Q7YsHZ9j6i6ddYjb5PLtUdMZn8L",
1772 "hvuCVhGcQntq5rn7JVMqnie",
1773 ];
1774
1775 const XPRV_R: [&str; 2] = [
1777 "xprv9s21ZrQH143K2maNNY6YGXJZ4yGBEae4Jc4s6pfR6haWQEjLbCa2gBzUyYJS5cQuxPNjTtfBqUC9DPPyXfJV",
1778 "UgMn6qqmUUDJBtTzqa6rY2w",
1779 ];
1780
1781 const XPRV_R_D: [&str; 2] = [
1783 "xprvAAVaDKt9qqGMFfrRPXWyL9SVkSsq7QozvfmVh1e9g1A9XZUuYwewdx84fw9iL8YkyzycjB4STWQf9bFuzATG",
1784 "yZTR7PUB1CLpGRaLUAiGgxH",
1785 ];
1786
1787 const XPRV_R_NZ: [&str; 2] = [
1789 "xprv9s21ZrQH143K2maNNY6YGXJZ4yGBEae4Jc4s6pfR6haWQEjLbCa2gBzV34QbbxYGS4PWd2gF2LN4N4MHgdxt",
1790 "jcqiixH56CSRZhAiexotiHQ",
1791 ];
1792
1793 const XPRV_Z: [&str; 2] = [
1795 "xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86",
1796 "QEC8w35uxmGoggxtQTPvfUu",
1797 ];
1798
1799 const XPUB_A: [&str; 2] = [
1801 "xpub6EdHrjLe1JdwRR6W5romAvmVzk7bfXQWV2N9SuTWP1ebszkLVQMev6KWTNtb2D9mQpocUfAsPQGkE6wtVe8K",
1802 "ug3dYyA9yCJTnHRPJAbgEAF",
1803 ];
1804
1805 const XPUB_R: [&str; 2] = [
1807 "xpub6EBARkwLtwz68GAfCSJ8AAqn6gxR2Lw6mJfK23rqDya64GvRT2LHYwDmBVdG5Cazs1Q59gPXj1MNmmL24Vi4",
1808 "Ce7nmjizMude8mGYqzSbMB8",
1809 ];
1810
1811 const XPUB_Z: [&str; 2] = [
1813 "xpub6ELHKXNimKbxMCytPh7EdC2QXx46T9qLDJWGnTraz1H9kMMFdcduoU69wh9cxP12wDxqAAfbaESWGYt5rREs",
1814 "X1J8iR2TEunvzvddduAPYcY",
1815 ];
1816
1817 const XPRV_A_B: [u8; NBBY_XKEY] = [
1819 0x04, 0x88, 0xad, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x0d,
1820 0x67, 0x53, 0x23, 0xc4, 0x0e, 0xc4, 0x61, 0xe0, 0xa6, 0xaf, 0x60, 0x3b, 0x1f, 0x13, 0x5f,
1821 0xb2, 0xaf, 0x9a, 0xe7, 0x53, 0xee, 0xff, 0x18, 0x92, 0x27, 0x32, 0xa7, 0x3b, 0x0f, 0x05,
1822 0x00, 0xb2, 0xa0, 0xd5, 0x76, 0xb8, 0x28, 0xb5, 0x37, 0x68, 0x8b, 0x56, 0x1f, 0x2c, 0xfa,
1823 0x8d, 0xac, 0x36, 0x02, 0xd5, 0x4c, 0x62, 0xbd, 0xe6, 0x19, 0xad, 0x53, 0x31, 0xe6, 0xc2,
1824 0x35, 0xee, 0x26,
1825 ];
1826
1827 const XPRV_R_B: [u8; NBBY_XKEY] = [
1829 0x04, 0x88, 0xad, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61,
1830 0x89, 0xa3, 0xed, 0x99, 0xca, 0xf4, 0x0f, 0x7c, 0x9b, 0x88, 0xf1, 0x6d, 0x80, 0x58, 0x92,
1831 0xc9, 0x26, 0xb7, 0xbf, 0x8e, 0xcf, 0x7b, 0xff, 0x63, 0x2d, 0x7d, 0x40, 0x42, 0xbd, 0x4d,
1832 0x00, 0xd1, 0x95, 0x7c, 0xc8, 0x92, 0xb0, 0xd4, 0xf0, 0x48, 0x35, 0x65, 0xc4, 0x5c, 0x8c,
1833 0x4f, 0x2a, 0xe9, 0x46, 0x1c, 0x65, 0xb6, 0x1e, 0x33, 0x76, 0xb5, 0x05, 0xbe, 0x15, 0x6e,
1834 0xce, 0x5e, 0x3c,
1835 ];
1836
1837 const XPRV_Z_B: [u8; NBBY_XKEY] = [
1839 0x04, 0x88, 0xad, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x23,
1840 0x40, 0x8d, 0xad, 0xd3, 0xc7, 0xb5, 0x6e, 0xed, 0x15, 0x56, 0x77, 0x07, 0xae, 0x5e, 0x5d,
1841 0xca, 0x08, 0x9d, 0xe9, 0x72, 0xe0, 0x7f, 0x3b, 0x86, 0x04, 0x50, 0xe2, 0xa3, 0xb7, 0x0e,
1842 0x00, 0x18, 0x37, 0xc1, 0xbe, 0x8e, 0x29, 0x95, 0xec, 0x11, 0xcd, 0xa2, 0xb0, 0x66, 0x15,
1843 0x1b, 0xe2, 0xcf, 0xb4, 0x8a, 0xdf, 0x9e, 0x47, 0xb1, 0x51, 0xd4, 0x6a, 0xda, 0xb3, 0xa2,
1844 0x1c, 0xdf, 0x67,
1845 ];
1846
1847 const XPUB_A_B: [u8; NBBY_XKEY] = [
1849 0x04, 0x88, 0xb2, 0x1e, 0x04, 0x94, 0xb0, 0x09, 0xed, 0x00, 0x00, 0x00, 0x00, 0xca, 0x1a,
1850 0xc2, 0x0b, 0x6c, 0xbf, 0x6e, 0x45, 0xc3, 0xcf, 0xc2, 0xf2, 0x39, 0x9a, 0x5f, 0xd8, 0x91,
1851 0xa9, 0x2f, 0xff, 0x52, 0x21, 0xcd, 0xe0, 0x8a, 0x73, 0x98, 0xb5, 0x2d, 0x58, 0x1f, 0xd0,
1852 0x03, 0x86, 0x36, 0x98, 0x82, 0x77, 0x1a, 0x91, 0xbe, 0xc8, 0xb1, 0xc9, 0xd5, 0x0c, 0x54,
1853 0x66, 0xfe, 0x04, 0x44, 0xff, 0x76, 0x3e, 0xe0, 0xf7, 0x3b, 0xa0, 0x60, 0xc4, 0x7c, 0x63,
1854 0x53, 0xbd, 0xf7,
1855 ];
1856
1857 const XPUB_R_B: [u8; NBBY_XKEY] = [
1859 0x04, 0x88, 0xb2, 0x1e, 0x04, 0x57, 0x66, 0x12, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x83, 0x59,
1860 0xda, 0xd5, 0x56, 0xc1, 0xf4, 0x3c, 0x23, 0x3f, 0xb4, 0xba, 0x56, 0x55, 0xc1, 0xd6, 0x89,
1861 0x3b, 0x1f, 0x9d, 0x6d, 0x42, 0x52, 0xdb, 0x18, 0xd3, 0x0f, 0xc7, 0xfe, 0x3c, 0x44, 0xd6,
1862 0x02, 0xbb, 0xb6, 0xd2, 0x7b, 0x71, 0xb2, 0x6b, 0xf9, 0x23, 0xf9, 0xce, 0xcb, 0x31, 0x3f,
1863 0x1c, 0xb3, 0x48, 0xda, 0x6a, 0x92, 0xe8, 0xba, 0x7c, 0xa1, 0x70, 0x25, 0x61, 0xb4, 0x62,
1864 0x00, 0xc0, 0x67,
1865 ];
1866
1867 const XPUB_Z_B: [u8; NBBY_XKEY] = [
1869 0x04, 0x88, 0xb2, 0x1e, 0x04, 0x6c, 0xc9, 0xf2, 0x52, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xe8,
1870 0x0d, 0xd5, 0x80, 0x79, 0x2c, 0xd1, 0x8a, 0xf5, 0x42, 0x79, 0x0e, 0x56, 0xaa, 0x81, 0x31,
1871 0x78, 0xdc, 0x28, 0x64, 0x4b, 0xb5, 0xf0, 0x3d, 0xbd, 0x44, 0xc8, 0x5f, 0x2d, 0x2e, 0x7a,
1872 0x03, 0x86, 0xb8, 0x65, 0xb5, 0x2b, 0x75, 0x3d, 0x0a, 0x84, 0xd0, 0x9b, 0xc2, 0x00, 0x63,
1873 0xfa, 0xb5, 0xd8, 0x45, 0x3e, 0xc3, 0x3c, 0x21, 0x5d, 0x40, 0x19, 0xa5, 0x80, 0x1c, 0x9c,
1874 0x64, 0x38, 0xb9,
1875 ];
1876
1877 #[test]
1878 fn test_as_bs58ck_prv() {
1879 assert_eq!(
1880 ExtPrvKey::from_bs58_prv(&XPRV_A.concat())
1881 .unwrap()
1882 .as_bs58ck_prv(),
1883 XPRV_A.concat()
1884 );
1885 assert_eq!(
1886 ExtPrvKey::from_bs58_prv(&XPRV_R.concat())
1887 .unwrap()
1888 .as_bs58ck_prv(),
1889 XPRV_R.concat()
1890 );
1891 assert_eq!(
1892 ExtPrvKey::from_bs58_prv(&XPRV_Z.concat())
1893 .unwrap()
1894 .as_bs58ck_prv(),
1895 XPRV_Z.concat()
1896 );
1897 assert_eq!(
1898 ExtPrvKey::from_bs58_prv(&XPRV_R.concat())
1899 .unwrap()
1900 .derive_prv(&"m/1h/2/3h/4/5h/6/7h/8/9h".decode_path(false).unwrap())
1901 .unwrap()
1902 .as_bs58ck_prv(),
1903 XPRV_R_D.concat()
1904 );
1905 assert_ne!(
1906 ExtPrvKey::from_bs58_prv(&XPRV_Z.concat())
1907 .unwrap()
1908 .as_bs58ck_prv(),
1909 "error"
1910 );
1911 }
1912
1913 #[test]
1914 fn test_as_bs58ck_pub() {
1915 assert_eq!(
1916 ExtPubKey::from_bs58_pub(&XPUB_A.concat())
1917 .unwrap()
1918 .as_bs58ck_pub(),
1919 XPUB_A.concat()
1920 );
1921 assert_eq!(
1922 ExtPubKey::from_bs58_pub(&XPUB_R.concat())
1923 .unwrap()
1924 .as_bs58ck_pub(),
1925 XPUB_R.concat()
1926 );
1927 assert_eq!(
1928 ExtPubKey::from_bs58_pub(&XPUB_Z.concat())
1929 .unwrap()
1930 .as_bs58ck_pub(),
1931 XPUB_Z.concat()
1932 );
1933 assert_ne!(
1934 ExtPubKey::from_bs58_pub(&XPUB_Z.concat())
1935 .unwrap()
1936 .as_bs58ck_pub(),
1937 "error"
1938 );
1939 }
1940
1941 #[test]
1942 fn test_bytes_prv() {
1943 assert_eq!(
1944 ExtPrvKey::from_bs58_prv(&XPRV_A.concat())
1945 .unwrap()
1946 .bytes_prv(),
1947 XPRV_A_B[..NBBY_XKEY]
1948 );
1949 assert_eq!(
1950 ExtPrvKey::from_bs58_prv(&XPRV_R.concat())
1951 .unwrap()
1952 .bytes_prv(),
1953 XPRV_R_B[..NBBY_XKEY]
1954 );
1955 assert_eq!(
1956 ExtPrvKey::from_bs58_prv(&XPRV_Z.concat())
1957 .unwrap()
1958 .bytes_prv(),
1959 XPRV_Z_B[..NBBY_XKEY]
1960 );
1961 }
1962
1963 #[test]
1964 fn test_bytes_pub() {
1965 assert_eq!(
1966 ExtPubKey::from_bs58_pub(&XPUB_A.concat())
1967 .unwrap()
1968 .bytes_pub(),
1969 XPUB_A_B[..NBBY_XKEY]
1970 );
1971 assert_eq!(
1972 ExtPubKey::from_bs58_pub(&XPUB_R.concat())
1973 .unwrap()
1974 .bytes_pub(),
1975 XPUB_R_B[..NBBY_XKEY]
1976 );
1977 assert_eq!(
1978 ExtPubKey::from_bs58_pub(&XPUB_Z.concat())
1979 .unwrap()
1980 .bytes_pub(),
1981 XPUB_Z_B[..NBBY_XKEY]
1982 );
1983 }
1984
1985 #[test]
1986 fn test_ckd_prv() {
1987 assert!(ExtPrvKey::from_bs58_prv(&XPRV_A.concat())
1988 .unwrap()
1989 .ckd_prv(&0)
1990 .is_ok());
1991 assert!(ExtPrvKey::from_bs58_prv(&XPRV_R.concat())
1992 .unwrap()
1993 .ckd_prv(&0)
1994 .is_ok());
1995 assert!(ExtPrvKey::from_bs58_prv(&XPRV_Z.concat())
1996 .unwrap()
1997 .ckd_prv(&0)
1998 .is_ok());
1999 let mut to_test = ExtPrvKey::from_bs58_prv(&XPRV_A.concat()).unwrap();
2000 to_test.prvdata = [0xff; 32];
2001 assert_eq!(to_test.ckd_prv(&0).unwrap_err(), Error::SecEnt);
2002 to_test.prvdata = [0x00; 32];
2003 assert_eq!(to_test.ckd_prv(&0).unwrap_err(), Error::SecEnt);
2004 }
2005
2006 #[test]
2007 fn test_ckd_pub() {
2008 assert!(ExtPubKey::from_bs58_pub(&XPUB_A.concat())
2009 .unwrap()
2010 .ckd_pub(&0)
2011 .is_ok());
2012 assert!(ExtPubKey::from_bs58_pub(&XPUB_R.concat())
2013 .unwrap()
2014 .ckd_pub(&0)
2015 .is_ok());
2016 assert!(ExtPubKey::from_bs58_pub(&XPUB_Z.concat())
2017 .unwrap()
2018 .ckd_pub(&0)
2019 .is_ok());
2020 let mut to_test = ExtPubKey::from_bs58_pub(&XPUB_A.concat()).unwrap();
2021 to_test.pubdata = [0xff; 33];
2022 assert_eq!(to_test.ckd_pub(&0).unwrap_err(), Error::PubData);
2023 to_test.pubdata = [0x00; 33];
2024 assert_eq!(to_test.ckd_pub(&0).unwrap_err(), Error::PubData);
2025 }
2026
2027 #[test]
2028 fn test_decode_address() {
2029 assert!(P2WPKH_C_1.decode_address().is_ok());
2030 assert!(P2WPKH_C_A.decode_address().is_ok());
2031 assert!(P2WPKH_C_L.decode_address().is_ok());
2032 assert!(P2WPKH_P2SH_1.decode_address().is_ok());
2033 assert!(P2WPKH_P2SH_L.decode_address().is_ok());
2034 assert!(P2WPKH_U_1.decode_address().is_ok());
2035 assert!(P2WPKH_U_A.decode_address().is_ok());
2036 assert!(P2WPKH_U_L.decode_address().is_ok());
2037 assert_eq!(SEGW_1.decode_address().unwrap(), SEGW_DEC_1);
2038 assert_eq!(SEGW_A.decode_address().unwrap(), SEGW_DEC_A);
2039 assert_eq!(SEGW_L.decode_address().unwrap(), SEGW_DEC_L);
2040 assert_eq!("invalid".decode_address().unwrap_err(), Error::Address);
2041 assert_eq!("1_invalid".decode_address().unwrap_err(), Error::Address);
2042 assert_eq!("3_invalid".decode_address().unwrap_err(), Error::Address);
2043 assert_eq!("bc_invalid".decode_address().unwrap_err(), Error::Address);
2044 assert_eq!(SEGW_1[..41].decode_address().unwrap_err(), Error::Address);
2045 }
2046
2047 #[test]
2048 fn test_decode_base58ck() {
2049 assert_eq!(XPRV_A.concat().decode_base58ck().unwrap(), XPRV_A_B);
2050 assert_eq!(XPRV_R.concat().decode_base58ck().unwrap(), XPRV_R_B);
2051 assert_eq!(XPRV_Z.concat().decode_base58ck().unwrap(), XPRV_Z_B);
2052 assert_eq!(
2053 ["!"; LEN_ARG_MIN].concat().decode_base58ck().unwrap_err(),
2054 Error::Base58
2055 );
2056 assert_eq!(
2057 ["a"; LEN_ARG_MIN - 1]
2058 .concat()
2059 .decode_base58ck()
2060 .unwrap_err(),
2061 Error::Argument(String::from(["a"; LEN_ARG_MIN - 1].concat()))
2062 );
2063 assert_eq!(
2064 XPRV_A
2065 .concat()
2066 .replace("a", "A")
2067 .decode_base58ck()
2068 .unwrap_err(),
2069 Error::Checksum
2070 );
2071 }
2072
2073 #[test]
2074 fn test_decode_path() {
2075 assert!(PATH_START.decode_path(false).is_ok());
2076 assert!("m/0h/0".decode_path(true).is_err());
2077 assert!("m/0/1h/9/2147483647h/0/32h/69/96/0h/1"
2078 .decode_path(false)
2079 .is_ok());
2080 assert!("m/0/1h/9/2147483647h/0/32h/69/96/0h/1/"
2081 .decode_path(false)
2082 .is_ok());
2083 assert!("m/0/1h/9/4294967295/0/32h/69/96/0h/1/"
2084 .decode_path(false)
2085 .is_err());
2086 assert!("M".decode_path(false).is_err());
2087 assert!("n".decode_path(false).is_err());
2088 assert!("/0h/mh".decode_path(false).is_err());
2089 assert!("0h/mh".decode_path(false).is_err());
2090 assert!("0/mh".decode_path(false).is_err());
2091 assert!("m/0h/ah".decode_path(false).is_err());
2092 assert_eq!(PATH_START.decode_path(false).unwrap(), []);
2093 assert_eq!("m/0h/1".decode_path(false).unwrap(), [HARD_NB, 1]);
2094 assert_eq!("m/1/10h".decode_path(false).unwrap(), [1, 0x8000000a]);
2095 assert_eq!("m/0/1/2/3/4/".decode_path(false).unwrap(), [0, 1, 2, 3, 4]);
2096 assert_eq!(
2097 "m/0/1h/9/2147483647h/m/32".decode_path(false).unwrap_err(),
2098 Error::Path(String::from("m"))
2099 );
2100 assert_eq!(
2101 "m/0/1h/9/2147483648/0/32".decode_path(false).unwrap_err(),
2102 Error::Path(String::from("2147483648"))
2103 );
2104 assert_eq!(
2105 "m/0/1h/9/2147483648/0/32".decode_path(false).unwrap_err(),
2106 Error::Path(String::from("2147483648"))
2107 );
2108 assert_eq!(
2109 "m/0/1h/9/4294967295/0/32".decode_path(false).unwrap_err(),
2110 Error::Path(String::from("4294967295"))
2111 );
2112 }
2113
2114 #[test]
2115 fn test_decode_range() {
2116 assert_eq!("1".decode_range().unwrap(), (1, 1));
2117 assert_eq!("1h".decode_range().unwrap(), (0x80000001, 0x80000001));
2118 assert_eq!("..1".decode_range().unwrap(), (0, 1));
2119 assert_eq!("..1h".decode_range().unwrap(), (0, 0x80000001));
2120 assert_eq!("1..".decode_range().unwrap(), (1, 0x7fffffff));
2121 assert_eq!("1h..".decode_range().unwrap(), (0x80000001, 0xffffffff));
2122 assert_eq!("0..9".decode_range().unwrap(), (0, 9));
2123 assert_eq!("0..9h".decode_range().unwrap(), (0, 0x80000009));
2124 assert_eq!("0h..9h".decode_range().unwrap(), (0x80000000, 0x80000009));
2125 assert_eq!("6232..6233".decode_range().unwrap(), (6232, 6233));
2126 assert_eq!(
2127 "1h..0".decode_range().unwrap_err(),
2128 Error::Range(String::from("0"))
2129 );
2130 assert_eq!(
2131 "0:9".decode_range().unwrap_err(),
2132 Error::Range(String::from("0:9"))
2133 );
2134 assert_eq!(
2135 "9..9".decode_range().unwrap_err(),
2136 Error::Range(String::from("9..9"))
2137 );
2138 assert_eq!(
2139 "9..0".decode_range().unwrap_err(),
2140 Error::Range(String::from("9..0"))
2141 );
2142 assert_eq!(
2143 "-9..0".decode_range().unwrap_err(),
2144 Error::Range(String::from("-9"))
2145 );
2146 assert_eq!(
2147 "-1..".decode_range().unwrap_err(),
2148 Error::Range(String::from("-1"))
2149 );
2150 assert_eq!(
2151 "..-1".decode_range().unwrap_err(),
2152 Error::Range(String::from("-1"))
2153 );
2154 assert_eq!(
2155 "0..2147483649".decode_range().unwrap_err(),
2156 Error::Range(String::from("2147483649"))
2157 );
2158 }
2159
2160 #[test]
2161 fn test_decode_wif() {
2162 assert_eq!(WIC_1.decode_wif().unwrap(), ([0x11; 32], true));
2163 assert_eq!(WIC_L.decode_wif().unwrap(), ([0x69; 32], true));
2164 assert_eq!(WIF_1.decode_wif().unwrap(), ([0x11; 32], false));
2165 assert_eq!(WIF_L.decode_wif().unwrap(), ([0x69; 32], false));
2166 assert_eq!(
2167 [WIF_L, "a"].concat().decode_wif().unwrap_err(),
2168 Error::WifKey
2169 );
2170 assert_eq!(
2171 WIC_L.replace("dgbg", "dgdg").decode_wif().unwrap_err(),
2172 Error::Checksum
2173 );
2174 assert_eq!(
2175 ["a"; LEN_WIF_U].concat().decode_wif().unwrap_err(),
2176 Error::WifKey
2177 );
2178 assert_eq!(
2179 ["a"; LEN_WIF_C].concat().decode_wif().unwrap_err(),
2180 Error::WifKey
2181 );
2182 }
2183
2184 #[test]
2185 fn test_derive_prv() {
2186 for (idx, xprv) in TV_32_01_XPRV.iter().enumerate() {
2187 assert_eq!(
2188 ExtPrvKey::from_bs58_prv(&TV_32_01_XPRV[0].concat())
2189 .unwrap()
2190 .derive_prv(&TV_32_01_PATH[idx].decode_path(false).unwrap())
2191 .unwrap()
2192 .as_bs58ck_prv(),
2193 xprv.concat()
2194 );
2195 }
2196 for (idx, xprv) in TV_32_02_XPRV.iter().enumerate() {
2197 assert_eq!(
2198 ExtPrvKey::from_bs58_prv(&TV_32_02_XPRV[0].concat())
2199 .unwrap()
2200 .derive_prv(&TV_32_02_PATH[idx].decode_path(false).unwrap())
2201 .unwrap()
2202 .as_bs58ck_prv(),
2203 xprv.concat()
2204 );
2205 }
2206 for (idx, xprv) in TV_32_03_XPRV.iter().enumerate() {
2207 assert_eq!(
2208 ExtPrvKey::from_bs58_prv(&TV_32_03_XPRV[0].concat())
2209 .unwrap()
2210 .derive_prv(&TV_32_03_PATH[idx].decode_path(false).unwrap())
2211 .unwrap()
2212 .as_bs58ck_prv(),
2213 xprv.concat()
2214 );
2215 }
2216 let to_test = ExtPrvKey::from_bs58_prv(&XPRV_R.concat()).unwrap();
2217 assert!(to_test.derive_prv(&"m".decode_path(false).unwrap()).is_ok());
2218 assert!(to_test
2219 .derive_prv(
2220 &"m/0/1h/9/2147483647h/0/32h/69/96/0h/1"
2221 .decode_path(false)
2222 .unwrap()
2223 )
2224 .is_ok());
2225 let pub_key = ExtPrvKey::from_bs58_prv(&XPRV_Z.concat())
2226 .unwrap()
2227 .derive_prv(&"m/44h/0h/0h/0/19".decode_path(false).unwrap())
2228 .unwrap()
2229 .prvdata
2230 .public_key(true)
2231 .unwrap();
2232 assert_eq!(pub_key.p2wpkh().unwrap(), P2WPKH_Z_19);
2233 }
2234
2235 #[test]
2236 fn test_derive_pub() {
2237 let to_test = ExtPubKey::from_bs58_pub(&XPUB_R.concat()).unwrap();
2238 assert!(to_test.derive_pub(&"m".decode_path(true).unwrap()).is_ok());
2239 assert!(to_test
2240 .derive_pub(&"m/0/9/2147483647/0/32/69/96/0/1".decode_path(true).unwrap())
2241 .is_ok());
2242 assert!(to_test
2243 .derive_pub(
2244 &"m/0/9/0h/0/32/69/96/0/1".decode_path(false).unwrap()
2246 )
2247 .is_err());
2248 assert_eq!(
2249 ExtPubKey::from_bs58_pub(&XPUB_Z.concat())
2250 .unwrap()
2251 .derive_pub(&"m/0".decode_path(true).unwrap())
2252 .unwrap()
2253 .pubdata
2254 .p2wpkh()
2255 .unwrap(),
2256 P2WPKH_Z_0
2257 );
2258 }
2259
2260 #[test]
2261 fn test_encode_base58ck() {
2262 assert_eq!("a".as_bytes().encode_base58ck(), "C2dGTwc");
2263 assert_eq!("abc".as_bytes().encode_base58ck(), "4h3c6RH52R");
2264 }
2265
2266 #[test]
2267 fn test_encode_path() {
2268 assert_eq!("m".decode_path(false).unwrap().encode_path(), "m");
2269 assert_eq!(
2270 "m/00000000h/1".decode_path(false).unwrap().encode_path(),
2271 "m/0h/1"
2272 );
2273 assert_eq!(
2274 "m/000001/10h".decode_path(false).unwrap().encode_path(),
2275 "m/1/10h"
2276 );
2277 assert_eq!([0u32; 0].encode_path(), "m");
2278 assert_eq!([1u32, 2, 3, 4, 5, HARD_NB].encode_path(), "m/1/2/3/4/5/0h");
2279 }
2280
2281 #[test]
2282 fn test_encode_wif() {
2283 assert_eq!(&[0x11; 32].encode_wif(true).unwrap(), WIC_1);
2284 assert_eq!(&P2WPKH_B.encode_wif(true).unwrap(), WIC_A);
2285 assert_eq!(&[0x69; 32].encode_wif(true).unwrap(), WIC_L);
2286 assert_eq!(&[0x11; 32].encode_wif(false).unwrap(), WIF_1);
2287 assert_eq!(&P2WPKH_B.encode_wif(false).unwrap(), WIF_A);
2288 assert_eq!(&[0x69; 32].encode_wif(false).unwrap(), WIF_L);
2289 }
2290
2291 #[test]
2292 fn test_from_bs58_prv() {
2293 assert_eq!(
2294 ExtPrvKey::from_bs58_prv(&XPRV_A.concat())
2295 .unwrap()
2296 .bytes_prv(),
2297 XPRV_A_B[..NBBY_XKEY]
2298 );
2299 assert_eq!(
2300 ExtPrvKey::from_bs58_prv(&XPRV_R.concat())
2301 .unwrap()
2302 .bytes_prv(),
2303 XPRV_R_B[..NBBY_XKEY]
2304 );
2305 assert_eq!(
2306 ExtPrvKey::from_bs58_prv(&XPRV_Z.concat())
2307 .unwrap()
2308 .bytes_prv(),
2309 XPRV_Z_B[..NBBY_XKEY]
2310 );
2311 assert_eq!(
2312 ExtPrvKey::from_bs58_prv(&XPUB_Z.concat()).unwrap_err(), Error::KeyVer
2314 );
2315 assert_eq!(
2316 ExtPrvKey::from_bs58_prv(&XPRV_Z.concat().replace("a", "A")).unwrap_err(),
2317 Error::Checksum
2318 );
2319 assert_eq!(
2320 ExtPrvKey::from_bs58_prv(&XPRV_Z.concat()[..100]).unwrap_err(),
2321 Error::KeyLen
2322 );
2323 assert_eq!(
2324 ExtPrvKey::from_bs58_prv(&[&XPRV_Z.concat(), "aaaaa"].concat()).unwrap_err(),
2325 Error::KeyLen
2326 );
2327 assert_eq!(
2328 ExtPrvKey::from_bs58_prv(&XPRV_R_NZ.concat()).unwrap_err(), Error::PrvData
2330 );
2331 }
2332
2333 #[test]
2334 fn test_from_bs58_pub() {
2335 assert_eq!(
2336 ExtPubKey::from_bs58_pub(&XPUB_A.concat())
2337 .unwrap()
2338 .bytes_pub(),
2339 XPUB_A_B[..NBBY_XKEY]
2340 );
2341 assert_eq!(
2342 ExtPubKey::from_bs58_pub(&XPUB_R.concat())
2343 .unwrap()
2344 .bytes_pub(),
2345 XPUB_R_B[..NBBY_XKEY]
2346 );
2347 assert_eq!(
2348 ExtPubKey::from_bs58_pub(&XPUB_Z.concat())
2349 .unwrap()
2350 .bytes_pub(),
2351 XPUB_Z_B[..NBBY_XKEY]
2352 );
2353 assert_eq!(
2354 ExtPubKey::from_bs58_pub(&XPRV_Z.concat()).unwrap_err(), Error::KeyVer
2356 );
2357 assert_eq!(
2358 ExtPubKey::from_bs58_pub(&XPUB_Z.concat()[..100]).unwrap_err(),
2359 Error::KeyLen
2360 );
2361 assert_eq!(
2362 ExtPubKey::from_bs58_pub(&[&XPUB_Z.concat(), "aaaaa"].concat()).unwrap_err(),
2363 Error::KeyLen
2364 );
2365 assert_eq!(
2366 ExtPubKey::from_bs58_pub(&XPUB_Z.concat().replace("a", "A")).unwrap_err(),
2367 Error::Checksum
2368 );
2369 }
2370
2371 #[test]
2372 fn test_from_prv() {
2373 for (idx, xpub) in TV_32_01_XPUB.iter().enumerate() {
2374 assert_eq!(
2375 ExtPubKey::from_prv(
2376 &ExtPrvKey::from_bs58_prv(&TV_32_01_XPRV[0].concat())
2377 .unwrap()
2378 .derive_prv(&TV_32_01_PATH[idx].decode_path(false).unwrap())
2379 .unwrap()
2380 )
2381 .unwrap()
2382 .as_bs58ck_pub(),
2383 xpub.concat()
2384 );
2385 }
2386 for (idx, xpub) in TV_32_02_XPUB.iter().enumerate() {
2387 assert_eq!(
2388 ExtPubKey::from_prv(
2389 &ExtPrvKey::from_bs58_prv(&TV_32_02_XPRV[0].concat())
2390 .unwrap()
2391 .derive_prv(&TV_32_02_PATH[idx].decode_path(false).unwrap())
2392 .unwrap()
2393 )
2394 .unwrap()
2395 .as_bs58ck_pub(),
2396 xpub.concat()
2397 );
2398 }
2399 for (idx, xpub) in TV_32_03_XPUB.iter().enumerate() {
2400 assert_eq!(
2401 ExtPubKey::from_prv(
2402 &ExtPrvKey::from_bs58_prv(&TV_32_03_XPRV[0].concat())
2403 .unwrap()
2404 .derive_prv(&TV_32_03_PATH[idx].decode_path(false).unwrap())
2405 .unwrap()
2406 )
2407 .unwrap()
2408 .as_bs58ck_pub(),
2409 xpub.concat()
2410 );
2411 }
2412 assert_eq!(
2413 ExtPubKey::from_prv(
2414 &ExtPrvKey::from_bs58_prv(&XPRV_A.concat())
2415 .unwrap()
2416 .derive_prv(&"m/44h/0h/0h/0".decode_path(false).unwrap())
2417 .unwrap()
2418 )
2419 .unwrap()
2420 .as_bs58ck_pub(),
2421 XPUB_A.concat()
2422 );
2423 assert_eq!(
2424 ExtPubKey::from_prv(
2425 &ExtPrvKey::from_bs58_prv(&XPRV_R.concat())
2426 .unwrap()
2427 .derive_prv(&"m/44h/0h/0h/0".decode_path(false).unwrap())
2428 .unwrap()
2429 )
2430 .unwrap()
2431 .as_bs58ck_pub(),
2432 XPUB_R.concat()
2433 );
2434 assert_eq!(
2435 ExtPubKey::from_prv(
2436 &ExtPrvKey::from_bs58_prv(&XPRV_Z.concat())
2437 .unwrap()
2438 .derive_prv(&"m/44h/0h/0h/0".decode_path(false).unwrap())
2439 .unwrap()
2440 )
2441 .unwrap()
2442 .as_bs58ck_pub(),
2443 XPUB_Z.concat()
2444 );
2445 }
2446
2447 #[test]
2448 fn test_handle_arguments() {
2449 let inputs = [
2450 &XPRV_A.concat(),
2451 &XPRV_R.concat(),
2452 &XPRV_Z.concat(),
2453 HEX_STR_1,
2454 HEX_STR_L,
2455 WIF_1,
2456 WIF_L,
2457 WIC_1,
2458 WIC_L,
2459 &P2WPKH_B.hex_string(),
2460 P2WPKH_C_1,
2461 P2WPKH_C_A,
2462 P2WPKH_C_L,
2463 P2WPKH_P2SH_1,
2464 P2WPKH_P2SH_L,
2465 P2WPKH_U_1,
2466 P2WPKH_U_A,
2467 P2WPKH_U_L,
2468 SEGW_1,
2469 SEGW_A,
2470 SEGW_L,
2471 ];
2472 for input in &inputs {
2473 assert!(handle_arguments(init_clap().get_matches_from(vec!["", input])).is_ok());
2474 }
2475 assert!(handle_arguments(init_clap().get_matches_from(vec![
2476 "",
2477 &XPRV_R.concat(),
2478 "-e",
2479 "バンドメイド",
2480 "-p",
2481 "m/0h",
2482 "-r",
2483 "0h..11h"
2484 ]))
2485 .is_ok());
2486 }
2487
2488 #[test]
2489 fn test_hash160() {
2490 assert_eq!([0x11; 33].hash160(), H160_33_1);
2491 assert_eq!([0x69; 33].hash160(), H160_33_L);
2492 }
2493
2494 #[test]
2495 fn test_hash256() {
2496 assert_eq!([0x00].hash256(), DS256_Z);
2498 assert_eq!([0x69; 32].hash256(), DS256_L);
2499 assert_eq!([0xff; 32].hash256(), DS256_F);
2500 }
2501
2502 #[test]
2503 fn test_hex_bytes() {
2504 assert_eq!("0488ade4".hex_bytes().unwrap(), XPRV);
2505 assert_eq!("BABACA".hex_bytes().unwrap(), [0xba, 0xba, 0xca]);
2506 }
2507
2508 #[test]
2509 fn test_hex_string() {
2510 assert_eq!(XPRV.hex_string(), String::from("0488ade4"));
2511 assert_eq!([0xba, 0xba, 0xca].hex_string(), String::from("babaca"));
2512 }
2513
2514 #[test]
2515 fn test_info_entropy() {
2516 assert!(HEX_STR_1.info_entropy("", DEF_SEP).is_ok());
2517 assert!(HEX_STR_L.info_entropy("", DEF_SEP).is_ok());
2518 assert!(HEX_STR_1.info_entropy("pass", DEF_SEP).is_ok());
2519 assert_eq!(
2520 HEX_STR_0.info_entropy("", DEF_SEP).unwrap_err(),
2521 Error::SecEnt
2522 );
2523 assert_eq!(
2524 HEX_STR_F.info_entropy("", DEF_SEP).unwrap_err(),
2525 Error::SecEnt
2526 );
2527 assert_eq!(
2528 ["a"; 63].concat().info_entropy("", DEF_SEP).unwrap_err(),
2529 Error::SecEnt
2530 );
2531 assert_eq!(
2532 ["?"; 64].concat().info_entropy("", DEF_SEP).unwrap_err(),
2533 Error::HexStr
2534 );
2535 }
2536
2537 #[test]
2538 fn test_info_wif() {
2539 assert!(WIF_1.info_wif("", DEF_SEP).is_ok());
2540 assert!(WIF_L.info_wif("", DEF_SEP).is_ok());
2541 assert!(WIF_1.info_wif("superpass", DEF_SEP).is_ok());
2542 assert!(WIC_1.info_wif("", DEF_SEP).is_ok());
2543 assert!(WIC_L.info_wif("", DEF_SEP).is_ok());
2544 assert!(WIC_1.info_wif("superduperpass", DEF_SEP).is_ok());
2545 assert_eq!(
2546 WIC_1.replace("H", "h").info_wif("", DEF_SEP).unwrap_err(),
2547 Error::Checksum
2548 );
2549 assert_eq!(
2550 WIF_1.replace("W", "w").info_wif("", DEF_SEP).unwrap_err(),
2551 Error::Checksum
2552 );
2553 assert_eq!(
2554 "something_wrong".info_wif("", DEF_SEP).unwrap_err(),
2555 Error::WifKey
2556 );
2557 }
2558
2559 #[test]
2560 fn test_init_clap() {
2561 let inputs = [
2562 &XPRV_A.concat(),
2563 &XPRV_R.concat(),
2564 &XPRV_Z.concat(),
2565 HEX_STR_1,
2566 HEX_STR_L,
2567 WIF_1,
2568 WIF_L,
2569 WIC_1,
2570 WIC_L,
2571 &P2WPKH_B.hex_string(),
2572 P2WPKH_C_1,
2573 P2WPKH_C_A,
2574 P2WPKH_C_L,
2575 P2WPKH_P2SH_1,
2576 P2WPKH_P2SH_L,
2577 P2WPKH_U_1,
2578 P2WPKH_U_A,
2579 P2WPKH_U_L,
2580 SEGW_1,
2581 SEGW_A,
2582 SEGW_L,
2583 ];
2584 for input in &inputs {
2585 assert!(init_clap().try_get_matches_from(vec!["", input]).is_ok());
2586 }
2587 assert!(init_clap()
2588 .try_get_matches_from(vec![
2589 "",
2590 &XPRV_A.concat(),
2591 "-e",
2592 "ultrasecretpass",
2593 "-p",
2594 "m/10h/20",
2595 "-r",
2596 "..7"
2597 ])
2598 .is_ok());
2599 assert!(init_clap()
2600 .try_get_matches_from(vec!["only_binary_name"])
2601 .is_err());
2602 assert!(init_clap()
2603 .try_get_matches_from(vec!["", &["a"; LEN_ARG_MIN - 1].concat()])
2604 .is_err());
2605 assert!(init_clap()
2606 .try_get_matches_from(vec!["", "wrong_data"])
2607 .is_err());
2608 assert!(init_clap()
2609 .try_get_matches_from(vec!["", &XPRV_A.concat(), "-e"])
2610 .is_err());
2611 assert!(init_clap()
2612 .try_get_matches_from(vec!["", &XPRV_A.concat(), "-p"])
2613 .is_err());
2614 assert!(init_clap()
2615 .try_get_matches_from(vec!["", &XPRV_A.concat(), "-r"])
2616 .is_err());
2617 assert!(init_clap()
2618 .try_get_matches_from(vec!["", &XPRV_A.concat(), "-x"])
2619 .is_err());
2620 assert!(init_clap()
2621 .try_get_matches_from(vec!["", "double", "data"])
2622 .is_err());
2623 }
2624
2625 #[test]
2626 fn test_is_hex() {
2627 assert!("0123456789abcdf".is_hex());
2628 assert!("ABCDEF".is_hex());
2629 assert!(!"ghijkl".is_hex());
2630 assert!(!"'!@#$%&*;:><?".is_hex());
2631 }
2632
2633 #[test]
2634 fn test_p2wpkh() {
2635 assert_eq!(PUB_C_1.p2wpkh().unwrap(), P2WPKH_C_1);
2636 assert_eq!(PUB_C_A.p2wpkh().unwrap(), P2WPKH_C_A);
2637 assert_eq!(PUB_C_L.p2wpkh().unwrap(), P2WPKH_C_L);
2638 assert_eq!(PUB_U_1.p2wpkh().unwrap(), P2WPKH_U_1);
2639 assert_eq!(PUB_U_A.p2wpkh().unwrap(), P2WPKH_U_A);
2640 assert_eq!(PUB_U_L.p2wpkh().unwrap(), P2WPKH_U_L);
2641 assert_eq!(PUB_C_L[1..].p2wpkh().unwrap_err(), Error::NbPubB(32));
2642 assert_eq!(PUB_U_L[1..].p2wpkh().unwrap_err(), Error::NbPubB(64));
2643 }
2644
2645 #[test]
2646 fn test_public_key() {
2647 assert_eq!(P2WPKH_B.public_key(true).unwrap(), PUB_C_A);
2648 assert_eq!([0x11; 32].public_key(true).unwrap(), PUB_C_1);
2649 assert_eq!([0x69; 32].public_key(true).unwrap(), PUB_C_L);
2650 assert_eq!(P2WPKH_B.public_key(false).unwrap(), PUB_U_A);
2651 assert_eq!([0x11; 32].public_key(false).unwrap(), PUB_U_1);
2652 assert_eq!([0x69; 32].public_key(false).unwrap(), PUB_U_L);
2653 }
2654
2655 #[test]
2656 fn test_segwit_p2wpkh() {
2657 assert_eq!(PUB_C_1.segwit_p2wpkh().unwrap(), SEGW_1);
2658 assert_eq!(PUB_C_A.segwit_p2wpkh().unwrap(), SEGW_A);
2659 assert_eq!(PUB_C_L.segwit_p2wpkh().unwrap(), SEGW_L);
2660 }
2661
2662 #[test]
2663 fn test_segwit_p2wpkh_p2sh() {
2664 assert_eq!(PUB_C_1.segwit_p2wpkh_p2sh().unwrap(), P2WPKH_P2SH_1);
2665 assert_eq!(PUB_C_A.segwit_p2wpkh_p2sh().unwrap(), P2WPKH_P2SH_A);
2666 assert_eq!(PUB_C_L.segwit_p2wpkh_p2sh().unwrap(), P2WPKH_P2SH_L);
2667 }
2668
2669 #[test]
2670 fn test_show_prv() {
2671 assert!(&ExtPrvKey::from_bs58_prv(&XPRV_A.concat())
2672 .unwrap()
2673 .show_prv(&vec![], (0, 1), "", DEF_SEP)
2674 .is_ok());
2675 assert!(ExtPrvKey::from_bs58_prv(&XPRV_R.concat())
2676 .unwrap()
2677 .show_prv(&vec![], (0, 1), "", DEF_SEP)
2678 .is_ok());
2679 assert!(ExtPrvKey::from_bs58_prv(&XPRV_Z.concat())
2680 .unwrap()
2681 .show_prv(&vec![], (0, 1), "", DEF_SEP)
2682 .is_ok());
2683 }
2684
2685 #[test]
2686 fn test_show_pub() {
2687 assert!(ExtPubKey::from_bs58_pub(&XPUB_A.concat())
2688 .unwrap()
2689 .show_pub(&vec![], (0, 1), DEF_SEP)
2690 .is_ok());
2691 assert!(ExtPubKey::from_bs58_pub(&XPUB_R.concat())
2692 .unwrap()
2693 .show_pub(&vec![], (0, 1), DEF_SEP)
2694 .is_ok());
2695 assert!(ExtPubKey::from_bs58_pub(&XPUB_Z.concat())
2696 .unwrap()
2697 .show_pub(&vec![], (0, 1), DEF_SEP)
2698 .is_ok());
2699 assert_eq!(
2700 ExtPubKey::from_bs58_pub(&XPUB_Z.concat())
2701 .unwrap()
2702 .show_pub(&vec![], (0x7fffffff, HARD_NB), DEF_SEP)
2703 .unwrap_err(),
2704 Error::FromHard
2705 );
2706 }
2707
2708 #[test]
2709 fn test_validate_data() {
2710 let inputs = [
2711 &XPRV_A.concat(),
2712 &XPRV_R.concat(),
2713 &XPRV_Z.concat(),
2714 HEX_STR_1,
2715 HEX_STR_L,
2716 WIF_1,
2717 WIF_L,
2718 WIC_1,
2719 WIC_L,
2720 &P2WPKH_B.hex_string(),
2721 P2WPKH_C_1,
2722 P2WPKH_C_A,
2723 P2WPKH_C_L,
2724 P2WPKH_P2SH_1,
2725 P2WPKH_P2SH_L,
2726 P2WPKH_U_1,
2727 P2WPKH_U_A,
2728 P2WPKH_U_L,
2729 SEGW_1,
2730 SEGW_A,
2731 SEGW_L,
2732 ];
2733 for input in &inputs {
2734 assert!(validate_data(OsString::from(*input)).is_ok());
2735 }
2736 assert!(validate_data(OsString::from(&XPRV_A.concat()[..LEN_XKEY - 1])).is_err());
2737 assert!(validate_data(OsString::from(format!("{}a", XPRV_A.concat()))).is_err());
2738 assert!(validate_data(OsString::from(&HEX_STR_1[1..])).is_err());
2739 assert!(validate_data(OsString::from(format!("{}a", HEX_STR_1))).is_err());
2740 assert!(validate_data(OsString::from(&WIF_L[..LEN_WIF_U - 1])).is_err());
2741 assert!(validate_data(OsString::from(format!("{}a", WIF_L))).is_err());
2742 assert!(validate_data(OsString::from(&WIC_L[..LEN_WIF_C - 1])).is_err());
2743 assert!(validate_data(OsString::from(format!("{}a", WIC_L))).is_err());
2744 assert!(validate_data(OsString::from(&P2WPKH_C_A[..LEN_LEG_MIN - 1])).is_err());
2745 assert!(validate_data(OsString::from(format!("{}ab", P2WPKH_C_A))).is_err());
2746 assert!(validate_data(OsString::from(&P2WPKH_P2SH_L[..LEN_LEG_MIN - 1])).is_err());
2747 assert!(validate_data(OsString::from(format!("{}ab", P2WPKH_P2SH_L))).is_err());
2748 assert!(validate_data(OsString::from(&SEGW_A[..LEN_SEGWIT - 1])).is_err());
2749 assert!(validate_data(OsString::from(format!("{}a", SEGW_A))).is_err());
2750 }
2751
2752 #[test]
2753 fn test_validate_path() {
2754 assert!(validate_path(OsString::from("m/0h/1")).is_ok());
2755 assert!(validate_path(OsString::from("m/h/1")).is_err());
2756 }
2758
2759 #[test]
2760 fn test_validate_range() {
2761 assert!(validate_range(OsString::from("1..9")).is_ok());
2762 assert!(validate_range(OsString::from("9..1")).is_err());
2763 }
2765}