33//!
44
55use kaspa_hashes:: { Hash , PersonalMessageSigningHash } ;
6- use secp256k1:: { Error , XOnlyPublicKey } ;
6+ use rand:: RngCore ;
7+ use secp256k1:: { Error , PublicKey , XOnlyPublicKey } ;
78
89/// A personal message (text) that can be signed.
910#[ derive( Clone ) ]
@@ -15,6 +16,12 @@ impl AsRef<[u8]> for PersonalMessage<'_> {
1516 }
1617}
1718
19+ #[ derive( Clone , Debug , PartialEq ) ]
20+ pub enum SignatureType {
21+ Schnorr ,
22+ ECDSA ,
23+ }
24+
1825#[ derive( Clone ) ]
1926pub struct SignMessageOptions {
2027 /// The auxiliary randomness exists only to mitigate specific kinds of power analysis
@@ -23,25 +30,41 @@ pub struct SignMessageOptions {
2330 /// mitigations against such attacks. To read more about the relevant discussions that
2431 /// arose in adding this randomness please see: <https://github.com/sipa/bips/issues/195>
2532 pub no_aux_rand : bool ,
33+ /// Signature type to use for signing
34+ pub signature_type : SignatureType ,
2635}
2736
2837/// Sign a message with the given private key
2938pub fn sign_message ( msg : & PersonalMessage , privkey : & [ u8 ; 32 ] , options : & SignMessageOptions ) -> Result < Vec < u8 > , Error > {
3039 let hash = calc_personal_message_hash ( msg) ;
31-
3240 let msg = secp256k1:: Message :: from_digest_slice ( hash. as_bytes ( ) . as_slice ( ) ) ?;
33- let schnorr_key = secp256k1:: Keypair :: from_seckey_slice ( secp256k1:: SECP256K1 , privkey) ?;
34-
35- let sig: [ u8 ; 64 ] = if options. no_aux_rand {
36- * secp256k1:: SECP256K1 . sign_schnorr_no_aux_rand ( & msg, & schnorr_key) . as_ref ( )
37- } else {
38- * schnorr_key. sign_schnorr ( msg) . as_ref ( )
39- } ;
4041
41- Ok ( sig. to_vec ( ) )
42+ match options. signature_type {
43+ SignatureType :: Schnorr => {
44+ let schnorr_key = secp256k1:: Keypair :: from_seckey_slice ( secp256k1:: SECP256K1 , privkey) ?;
45+ let sig: [ u8 ; 64 ] = if options. no_aux_rand {
46+ * secp256k1:: SECP256K1 . sign_schnorr_no_aux_rand ( & msg, & schnorr_key) . as_ref ( )
47+ } else {
48+ * schnorr_key. sign_schnorr ( msg) . as_ref ( )
49+ } ;
50+ Ok ( sig. to_vec ( ) )
51+ }
52+ SignatureType :: ECDSA => {
53+ let secret_key = secp256k1:: SecretKey :: from_slice ( privkey) ?;
54+ let sig = if options. no_aux_rand {
55+ secp256k1:: SECP256K1 . sign_ecdsa ( & msg, & secret_key)
56+ } else {
57+ // TODO: Use sign_ecdsa_with_noncedata with random noncedata to add auxiliary randomness
58+ let mut nonce_data = [ 0u8 ; 32 ] ;
59+ rand:: thread_rng ( ) . fill_bytes ( & mut nonce_data) ;
60+ secp256k1:: SECP256K1 . sign_ecdsa_with_noncedata ( & msg, & secret_key, & nonce_data)
61+ } ;
62+ Ok ( sig. serialize_compact ( ) . to_vec ( ) )
63+ }
64+ }
4265}
4366
44- /// Verifies signed message.
67+ /// Verifies Schnorr signed message.
4568///
4669/// Produces `Ok(())` if the signature matches the given message and [`secp256k1::Error`]
4770/// if any of the inputs are incorrect, or the signature is invalid.
@@ -53,6 +76,18 @@ pub fn verify_message(msg: &PersonalMessage, signature: &Vec<u8>, pubkey: &XOnly
5376 sig. verify ( & msg, pubkey)
5477}
5578
79+ /// Verifies ECDSA signed message.
80+ ///
81+ /// Produces `Ok(())` if the signature matches the given message and [`secp256k1::Error`]
82+ /// if any of the inputs are incorrect, or the signature is invalid.
83+ ///
84+ pub fn verify_message_ecdsa ( msg : & PersonalMessage , signature : & Vec < u8 > , pubkey : & PublicKey ) -> Result < ( ) , Error > {
85+ let hash = calc_personal_message_hash ( msg) ;
86+ let msg = secp256k1:: Message :: from_digest_slice ( hash. as_bytes ( ) . as_slice ( ) ) ?;
87+ let sig = secp256k1:: ecdsa:: Signature :: from_compact ( signature. as_slice ( ) ) ?;
88+ sig. verify ( & msg, pubkey)
89+ }
90+
5691fn calc_personal_message_hash ( msg : & PersonalMessage ) -> Hash {
5792 let mut hasher = PersonalMessageSigningHash :: new ( ) ;
5893 hasher. write ( msg) ;
@@ -89,8 +124,8 @@ mod tests {
89124 ] )
90125 . unwrap ( ) ;
91126
92- let sign_with_aux_rand = SignMessageOptions { no_aux_rand : false } ;
93- let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand : true } ;
127+ let sign_with_aux_rand = SignMessageOptions { no_aux_rand : false , signature_type : SignatureType :: Schnorr } ;
128+ let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand : true , signature_type : SignatureType :: Schnorr } ;
94129 verify_message ( & pm, & sign_message ( & pm, & privkey, & sign_with_aux_rand) . expect ( "sign_message failed" ) , & pubkey)
95130 . expect ( "verify_message failed" ) ;
96131 verify_message ( & pm, & sign_message ( & pm, & privkey, & sign_with_no_aux_rand) . expect ( "sign_message failed" ) , & pubkey)
@@ -105,7 +140,7 @@ mod tests {
105140 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x03 ,
106141 ] ;
107142
108- let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand : true } ;
143+ let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand : true , signature_type : SignatureType :: Schnorr } ;
109144 let signature = sign_message ( & pm, & privkey, & sign_with_no_aux_rand) . expect ( "sign_message failed" ) ;
110145 let signature_twice = sign_message ( & pm, & privkey, & sign_with_no_aux_rand) . expect ( "sign_message failed" ) ;
111146 assert_eq ! ( signature, signature_twice) ;
@@ -124,8 +159,8 @@ mod tests {
124159 ] )
125160 . unwrap ( ) ;
126161
127- let sign_with_aux_rand = SignMessageOptions { no_aux_rand : false } ;
128- let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand : true } ;
162+ let sign_with_aux_rand = SignMessageOptions { no_aux_rand : false , signature_type : SignatureType :: Schnorr } ;
163+ let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand : true , signature_type : SignatureType :: Schnorr } ;
129164 verify_message ( & pm, & sign_message ( & pm, & privkey, & sign_with_aux_rand) . expect ( "sign_message failed" ) , & pubkey)
130165 . expect ( "verify_message failed" ) ;
131166 verify_message ( & pm, & sign_message ( & pm, & privkey, & sign_with_no_aux_rand) . expect ( "sign_message failed" ) , & pubkey)
@@ -149,8 +184,8 @@ Ut omnis magnam et accusamus earum rem impedit provident eum commodi repellat qu
149184 ] )
150185 . unwrap ( ) ;
151186
152- let sign_with_aux_rand = SignMessageOptions { no_aux_rand : false } ;
153- let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand : true } ;
187+ let sign_with_aux_rand = SignMessageOptions { no_aux_rand : false , signature_type : SignatureType :: Schnorr } ;
188+ let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand : true , signature_type : SignatureType :: Schnorr } ;
154189 verify_message ( & pm, & sign_message ( & pm, & privkey, & sign_with_aux_rand) . expect ( "sign_message failed" ) , & pubkey)
155190 . expect ( "verify_message failed" ) ;
156191 verify_message ( & pm, & sign_message ( & pm, & privkey, & sign_with_no_aux_rand) . expect ( "sign_message failed" ) , & pubkey)
0 commit comments