@@ -25,11 +25,12 @@ use core::{fmt, str::FromStr, default::Default};
25
25
26
26
use hash_types:: XpubIdentifier ;
27
27
use hashes:: { sha512, Hash , HashEngine , Hmac , HmacEngine } ;
28
- use secp256k1:: { self , Secp256k1 } ;
28
+ use secp256k1:: { self , Secp256k1 , XOnlyPublicKey } ;
29
29
30
30
use network:: constants:: Network ;
31
- use util:: { base58, endian, key} ;
32
- use util:: ecdsa:: { PublicKey , PrivateKey } ;
31
+ use util:: { base58, endian} ;
32
+ use util:: { key, ecdsa, schnorr} ;
33
+ use io:: Write ;
33
34
34
35
/// A chain code
35
36
#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
@@ -44,7 +45,8 @@ impl_array_newtype!(Fingerprint, u8, 4);
44
45
impl_bytes_newtype ! ( Fingerprint , 4 ) ;
45
46
46
47
/// Extended private key
47
- #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
48
+ #[ derive( Copy , Clone , PartialEq , Eq ) ]
49
+ #[ cfg_attr( feature = "std" , derive( Debug ) ) ]
48
50
pub struct ExtendedPrivKey {
49
51
/// The network this key is to be used on
50
52
pub network : Network ,
@@ -55,12 +57,26 @@ pub struct ExtendedPrivKey {
55
57
/// Child number of the key used to derive from parent (0 for master)
56
58
pub child_number : ChildNumber ,
57
59
/// Private key
58
- pub private_key : PrivateKey ,
60
+ pub private_key : secp256k1 :: SecretKey ,
59
61
/// Chain code
60
62
pub chain_code : ChainCode
61
63
}
62
64
serde_string_impl ! ( ExtendedPrivKey , "a BIP-32 extended private key" ) ;
63
65
66
+ #[ cfg( not( feature = "std" ) ) ]
67
+ #[ cfg_attr( docsrs, doc( cfg( not( feature = "std" ) ) ) ) ]
68
+ impl fmt:: Debug for ExtendedPrivKey {
69
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
70
+ f. debug_struct ( "ExtendedPrivKey" )
71
+ . field ( "network" , & self . network )
72
+ . field ( "depth" , & self . depth )
73
+ . field ( "parent_fingerprint" , & self . parent_fingerprint )
74
+ . field ( "child_number" , & self . child_number )
75
+ . field ( "chain_code" , & self . chain_code )
76
+ . finish_non_exhaustive ( )
77
+ }
78
+ }
79
+
64
80
/// Extended public key
65
81
#[ derive( Copy , Clone , PartialEq , Eq , Debug , PartialOrd , Ord , Hash ) ]
66
82
pub struct ExtendedPubKey {
@@ -73,7 +89,7 @@ pub struct ExtendedPubKey {
73
89
/// Child number of the key used to derive from parent (0 for master)
74
90
pub child_number : ChildNumber ,
75
91
/// Public key
76
- pub public_key : PublicKey ,
92
+ pub public_key : secp256k1 :: PublicKey ,
77
93
/// Chain code
78
94
pub chain_code : ChainCode
79
95
}
@@ -506,11 +522,26 @@ impl ExtendedPrivKey {
506
522
depth : 0 ,
507
523
parent_fingerprint : Default :: default ( ) ,
508
524
child_number : ChildNumber :: from_normal_idx ( 0 ) ?,
509
- private_key : PrivateKey :: from_slice ( & hmac_result[ ..32 ] , network ) ?,
525
+ private_key : secp256k1 :: SecretKey :: from_slice ( & hmac_result[ ..32 ] ) ?,
510
526
chain_code : ChainCode :: from ( & hmac_result[ 32 ..] ) ,
511
527
} )
512
528
}
513
529
530
+ /// Constructs ECDSA compressed private key matching internal secret key representation.
531
+ pub fn to_priv ( & self ) -> ecdsa:: PrivateKey {
532
+ ecdsa:: PrivateKey {
533
+ compressed : true ,
534
+ network : self . network ,
535
+ key : self . private_key
536
+ }
537
+ }
538
+
539
+ /// Constructs BIP340 keypair for Schnorr signatures and Taproot use matching the internal
540
+ /// secret key representation.
541
+ pub fn to_keypair < C : secp256k1:: Signing > ( & self , secp : & Secp256k1 < C > ) -> schnorr:: KeyPair {
542
+ schnorr:: KeyPair :: from_seckey_slice ( secp, & self . private_key [ ..] ) . expect ( "BIP32 internal private key representation is broken" )
543
+ }
544
+
514
545
/// Attempts to derive an extended private key from a path.
515
546
///
516
547
/// The `path` argument can be both of type `DerivationPath` or `Vec<ChildNumber>`.
@@ -532,7 +563,7 @@ impl ExtendedPrivKey {
532
563
match i {
533
564
ChildNumber :: Normal { .. } => {
534
565
// Non-hardened key: compute public data and use that
535
- hmac_engine. input ( & PublicKey :: from_private_key ( secp, & self . private_key ) . key . serialize ( ) [ ..] ) ;
566
+ hmac_engine. input ( & secp256k1 :: PublicKey :: from_secret_key ( secp, & self . private_key ) . serialize ( ) [ ..] ) ;
536
567
}
537
568
ChildNumber :: Hardened { .. } => {
538
569
// Hardened key: use only secret data to prevent public derivation
@@ -543,8 +574,8 @@ impl ExtendedPrivKey {
543
574
544
575
hmac_engine. input ( & endian:: u32_to_array_be ( u32:: from ( i) ) ) ;
545
576
let hmac_result: Hmac < sha512:: Hash > = Hmac :: from_engine ( hmac_engine) ;
546
- let mut sk = PrivateKey :: from_slice ( & hmac_result[ ..32 ] , self . network ) ?;
547
- sk. key . add_assign ( & self . private_key [ ..] ) ?;
577
+ let mut sk = secp256k1 :: SecretKey :: from_slice ( & hmac_result[ ..32 ] ) ?;
578
+ sk. add_assign ( & self . private_key [ ..] ) ?;
548
579
549
580
Ok ( ExtendedPrivKey {
550
581
network : self . network ,
@@ -578,7 +609,7 @@ impl ExtendedPrivKey {
578
609
parent_fingerprint : Fingerprint :: from ( & data[ 5 ..9 ] ) ,
579
610
child_number : endian:: slice_to_u32_be ( & data[ 9 ..13 ] ) . into ( ) ,
580
611
chain_code : ChainCode :: from ( & data[ 13 ..45 ] ) ,
581
- private_key : PrivateKey :: from_slice ( & data[ 46 ..78 ] , network ) ?,
612
+ private_key : secp256k1 :: SecretKey :: from_slice ( & data[ 46 ..78 ] ) ?,
582
613
} )
583
614
}
584
615
@@ -600,7 +631,7 @@ impl ExtendedPrivKey {
600
631
601
632
/// Returns the HASH160 of the public key belonging to the xpriv
602
633
pub fn identifier < C : secp256k1:: Signing > ( & self , secp : & Secp256k1 < C > ) -> XpubIdentifier {
603
- ExtendedPubKey :: from_private ( secp, self ) . identifier ( )
634
+ ExtendedPubKey :: from_priv ( secp, self ) . identifier ( )
604
635
}
605
636
606
637
/// Returns the first four bytes of the identifier
@@ -611,17 +642,37 @@ impl ExtendedPrivKey {
611
642
612
643
impl ExtendedPubKey {
613
644
/// Derives a public key from a private key
645
+ #[ deprecated( since = "0.28.0" , note = "use ExtendedPubKey::from_priv" ) ]
614
646
pub fn from_private < C : secp256k1:: Signing > ( secp : & Secp256k1 < C > , sk : & ExtendedPrivKey ) -> ExtendedPubKey {
647
+ ExtendedPubKey :: from_priv ( secp, sk)
648
+ }
649
+
650
+ /// Derives a public key from a private key
651
+ pub fn from_priv < C : secp256k1:: Signing > ( secp : & Secp256k1 < C > , sk : & ExtendedPrivKey ) -> ExtendedPubKey {
615
652
ExtendedPubKey {
616
653
network : sk. network ,
617
654
depth : sk. depth ,
618
655
parent_fingerprint : sk. parent_fingerprint ,
619
656
child_number : sk. child_number ,
620
- public_key : PublicKey :: from_private_key ( secp, & sk. private_key ) ,
657
+ public_key : secp256k1 :: PublicKey :: from_secret_key ( secp, & sk. private_key ) ,
621
658
chain_code : sk. chain_code
622
659
}
623
660
}
624
661
662
+ /// Constructs ECDSA compressed public key matching internal public key representation.
663
+ pub fn to_pub ( & self ) -> ecdsa:: PublicKey {
664
+ ecdsa:: PublicKey {
665
+ compressed : true ,
666
+ key : self . public_key
667
+ }
668
+ }
669
+
670
+ /// Constructs BIP340 x-only public key for BIP-340 signatures and Taproot use matching
671
+ /// the internal public key representation.
672
+ pub fn to_x_only_pub ( & self ) -> XOnlyPublicKey {
673
+ XOnlyPublicKey :: from ( self . public_key )
674
+ }
675
+
625
676
/// Attempts to derive an extended public key from a path.
626
677
///
627
678
/// The `path` argument can be both of type `DerivationPath` or `Vec<ChildNumber>`.
@@ -638,19 +689,19 @@ impl ExtendedPubKey {
638
689
}
639
690
640
691
/// Compute the scalar tweak added to this key to get a child key
641
- pub fn ckd_pub_tweak ( & self , i : ChildNumber ) -> Result < ( PrivateKey , ChainCode ) , Error > {
692
+ pub fn ckd_pub_tweak ( & self , i : ChildNumber ) -> Result < ( secp256k1 :: SecretKey , ChainCode ) , Error > {
642
693
match i {
643
694
ChildNumber :: Hardened { .. } => {
644
695
Err ( Error :: CannotDeriveFromHardenedKey )
645
696
}
646
697
ChildNumber :: Normal { index : n } => {
647
698
let mut hmac_engine: HmacEngine < sha512:: Hash > = HmacEngine :: new ( & self . chain_code [ ..] ) ;
648
- hmac_engine. input ( & self . public_key . key . serialize ( ) [ ..] ) ;
699
+ hmac_engine. input ( & self . public_key . serialize ( ) [ ..] ) ;
649
700
hmac_engine. input ( & endian:: u32_to_array_be ( n) ) ;
650
701
651
702
let hmac_result: Hmac < sha512:: Hash > = Hmac :: from_engine ( hmac_engine) ;
652
703
653
- let private_key = PrivateKey :: from_slice ( & hmac_result[ ..32 ] , self . network ) ?;
704
+ let private_key = secp256k1 :: SecretKey :: from_slice ( & hmac_result[ ..32 ] ) ?;
654
705
let chain_code = ChainCode :: from ( & hmac_result[ 32 ..] ) ;
655
706
Ok ( ( private_key, chain_code) )
656
707
}
@@ -665,7 +716,7 @@ impl ExtendedPubKey {
665
716
) -> Result < ExtendedPubKey , Error > {
666
717
let ( sk, chain_code) = self . ckd_pub_tweak ( i) ?;
667
718
let mut pk = self . public_key ;
668
- pk. key . add_exp_assign ( secp, & sk[ ..] ) ?;
719
+ pk. add_exp_assign ( secp, & sk[ ..] ) ?;
669
720
670
721
Ok ( ExtendedPubKey {
671
722
network : self . network ,
@@ -697,7 +748,7 @@ impl ExtendedPubKey {
697
748
parent_fingerprint : Fingerprint :: from ( & data[ 5 ..9 ] ) ,
698
749
child_number : endian:: slice_to_u32_be ( & data[ 9 ..13 ] ) . into ( ) ,
699
750
chain_code : ChainCode :: from ( & data[ 13 ..45 ] ) ,
700
- public_key : PublicKey :: from_slice ( & data[ 45 ..78 ] ) ?,
751
+ public_key : secp256k1 :: PublicKey :: from_slice ( & data[ 45 ..78 ] ) ?,
701
752
} )
702
753
}
703
754
@@ -712,14 +763,14 @@ impl ExtendedPubKey {
712
763
ret[ 5 ..9 ] . copy_from_slice ( & self . parent_fingerprint [ ..] ) ;
713
764
ret[ 9 ..13 ] . copy_from_slice ( & endian:: u32_to_array_be ( u32:: from ( self . child_number ) ) ) ;
714
765
ret[ 13 ..45 ] . copy_from_slice ( & self . chain_code [ ..] ) ;
715
- ret[ 45 ..78 ] . copy_from_slice ( & self . public_key . key . serialize ( ) [ ..] ) ;
766
+ ret[ 45 ..78 ] . copy_from_slice ( & self . public_key . serialize ( ) [ ..] ) ;
716
767
ret
717
768
}
718
769
719
770
/// Returns the HASH160 of the chaincode
720
771
pub fn identifier ( & self ) -> XpubIdentifier {
721
772
let mut engine = XpubIdentifier :: engine ( ) ;
722
- self . public_key . write_into ( & mut engine ) . expect ( "engines don't error" ) ;
773
+ engine . write ( & self . public_key . serialize ( ) ) . expect ( "engines don't error" ) ;
723
774
XpubIdentifier :: from_engine ( engine)
724
775
}
725
776
@@ -853,7 +904,7 @@ mod tests {
853
904
expected_pk : & str ) {
854
905
855
906
let mut sk = ExtendedPrivKey :: new_master ( network, seed) . unwrap ( ) ;
856
- let mut pk = ExtendedPubKey :: from_private ( secp, & sk) ;
907
+ let mut pk = ExtendedPubKey :: from_priv ( secp, & sk) ;
857
908
858
909
// Check derivation convenience method for ExtendedPrivKey
859
910
assert_eq ! (
@@ -881,15 +932,15 @@ mod tests {
881
932
match num {
882
933
Normal { ..} => {
883
934
let pk2 = pk. ckd_pub ( secp, num) . unwrap ( ) ;
884
- pk = ExtendedPubKey :: from_private ( secp, & sk) ;
935
+ pk = ExtendedPubKey :: from_priv ( secp, & sk) ;
885
936
assert_eq ! ( pk, pk2) ;
886
937
}
887
938
Hardened { ..} => {
888
939
assert_eq ! (
889
940
pk. ckd_pub( secp, num) ,
890
941
Err ( Error :: CannotDeriveFromHardenedKey )
891
942
) ;
892
- pk = ExtendedPubKey :: from_private ( secp, & sk) ;
943
+ pk = ExtendedPubKey :: from_priv ( secp, & sk) ;
893
944
}
894
945
}
895
946
}
@@ -1080,5 +1131,42 @@ mod tests {
1080
1131
assert_eq ! ( "42" , & format!( "{}" , ChildNumber :: from_normal_idx( 42 ) . unwrap( ) ) ) ;
1081
1132
assert_eq ! ( "000042" , & format!( "{:06}" , ChildNumber :: from_normal_idx( 42 ) . unwrap( ) ) ) ;
1082
1133
}
1134
+
1135
+ #[ test]
1136
+ #[ should_panic( expected = "Secp256k1(InvalidSecretKey)" ) ]
1137
+ fn schnorr_broken_privkey_zeros ( ) {
1138
+ /* this is how we generate key:
1139
+ let mut sk = secp256k1::key::ONE_KEY;
1140
+
1141
+ let zeros = [0u8; 32];
1142
+ unsafe {
1143
+ sk.as_mut_ptr().copy_from(zeros.as_ptr(), 32);
1144
+ }
1145
+
1146
+ let xpriv = ExtendedPrivKey {
1147
+ network: Network::Bitcoin,
1148
+ depth: 0,
1149
+ parent_fingerprint: Default::default(),
1150
+ child_number: ChildNumber::Normal { index: 0 },
1151
+ private_key: sk,
1152
+ chain_code: ChainCode::from(&[0u8; 32][..])
1153
+ };
1154
+
1155
+ println!("{}", xpriv);
1156
+ */
1157
+
1158
+ // Xpriv having secret key set to all zeros
1159
+ let xpriv_str = "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx" ;
1160
+ ExtendedPrivKey :: from_str ( xpriv_str) . unwrap ( ) ;
1161
+ }
1162
+
1163
+
1164
+ #[ test]
1165
+ #[ should_panic( expected = "Secp256k1(InvalidSecretKey)" ) ]
1166
+ fn schnorr_broken_privkey_ffs ( ) {
1167
+ // Xpriv having secret key set to all 0xFF's
1168
+ let xpriv_str = "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fENZ3QzxW" ;
1169
+ ExtendedPrivKey :: from_str ( xpriv_str) . unwrap ( ) ;
1170
+ }
1083
1171
}
1084
1172
0 commit comments