@@ -29,118 +29,119 @@ use bitcoin::secp256k1::{Error, Message, PublicKey, Secp256k1, SecretKey};
2929static LN_MESSAGE_PREFIX : & [ u8 ] = b"Lightning Signed Message:" ;
3030
3131fn sigrec_encode ( sig_rec : RecoverableSignature ) -> Vec < u8 > {
32- let ( rid, rsig) = sig_rec. serialize_compact ( ) ;
33- let prefix = rid. to_i32 ( ) as u8 + 31 ;
32+ let ( rid, rsig) = sig_rec. serialize_compact ( ) ;
33+ let prefix = rid. to_i32 ( ) as u8 + 31 ;
3434
35- [ & [ prefix] , & rsig[ ..] ] . concat ( )
35+ [ & [ prefix] , & rsig[ ..] ] . concat ( )
3636}
3737
3838fn sigrec_decode ( sig_rec : Vec < u8 > ) -> Result < RecoverableSignature , Error > {
39- // Signature must be 64 + 1 bytes long (compact signature + recovery id)
40- if sig_rec. len ( ) != 65 {
41- return Err ( Error :: InvalidSignature ) ;
42- }
43-
44- let rsig = & sig_rec[ 1 ..] ;
45- let rid = sig_rec[ 0 ] as i32 - 31 ;
46-
47- match RecoveryId :: from_i32 ( rid) {
48- Ok ( x) => RecoverableSignature :: from_compact ( rsig, x) ,
49- Err ( e) => Err ( e)
50- }
39+ // Signature must be 64 + 1 bytes long (compact signature + recovery id)
40+ if sig_rec. len ( ) != 65 {
41+ return Err ( Error :: InvalidSignature ) ;
42+ }
43+
44+ let rsig = & sig_rec[ 1 ..] ;
45+ let rid = sig_rec[ 0 ] as i32 - 31 ;
46+
47+ match RecoveryId :: from_i32 ( rid) {
48+ Ok ( x) => RecoverableSignature :: from_compact ( rsig, x) ,
49+ Err ( e) => Err ( e)
50+ }
5151}
5252
5353/// Creates a digital signature of a message given a SecretKey, like the node's secret.
5454/// A receiver knowing the PublicKey (e.g. the node's id) and the message can be sure that the signature was generated by the caller.
5555/// Signatures are EC recoverable, meaning that given the message and the signature the PublicKey of the signer can be extracted.
5656pub fn sign ( msg : & [ u8 ] , sk : & SecretKey ) -> Result < String , Error > {
57- let secp_ctx = Secp256k1 :: signing_only ( ) ;
58- let msg_hash = sha256d:: Hash :: hash ( & [ LN_MESSAGE_PREFIX , msg] . concat ( ) ) ;
57+ let secp_ctx = Secp256k1 :: signing_only ( ) ;
58+ let msg_hash = sha256d:: Hash :: hash ( & [ LN_MESSAGE_PREFIX , msg] . concat ( ) ) ;
5959
60- let sig = secp_ctx. sign_ecdsa_recoverable ( & Message :: from_slice ( & msg_hash) ?, sk) ;
61- Ok ( base32:: Alphabet :: ZBase32 . encode ( & sigrec_encode ( sig) ) )
60+ let sig = secp_ctx. sign_ecdsa_recoverable ( & Message :: from_slice ( & msg_hash) ?, sk) ;
61+ Ok ( base32:: Alphabet :: ZBase32 . encode ( & sigrec_encode ( sig) ) )
6262}
6363
6464/// Recovers the PublicKey of the signer of the message given the message and the signature.
6565pub fn recover_pk ( msg : & [ u8 ] , sig : & str ) -> Result < PublicKey , Error > {
66- let secp_ctx = Secp256k1 :: verification_only ( ) ;
67- let msg_hash = sha256d:: Hash :: hash ( & [ LN_MESSAGE_PREFIX , msg] . concat ( ) ) ;
68-
69- match base32:: Alphabet :: ZBase32 . decode ( & sig) {
70- Ok ( sig_rec) => {
71- match sigrec_decode ( sig_rec) {
72- Ok ( sig) => secp_ctx. recover_ecdsa ( & Message :: from_slice ( & msg_hash) ?, & sig) ,
73- Err ( e) => Err ( e)
74- }
75- } ,
76- Err ( _) => Err ( Error :: InvalidSignature )
77- }
66+ let secp_ctx = Secp256k1 :: verification_only ( ) ;
67+ let msg_hash = sha256d:: Hash :: hash ( & [ LN_MESSAGE_PREFIX , msg] . concat ( ) ) ;
68+
69+ match base32:: Alphabet :: ZBase32 . decode ( & sig) {
70+ Ok ( sig_rec) => {
71+ match sigrec_decode ( sig_rec) {
72+ Ok ( sig) => secp_ctx. recover_ecdsa ( & Message :: from_slice ( & msg_hash) ?, & sig) ,
73+ Err ( e) => Err ( e)
74+ }
75+ } ,
76+ Err ( _) => Err ( Error :: InvalidSignature )
77+ }
7878}
7979
8080/// Verifies a message was signed by a PrivateKey that derives to a given PublicKey, given a message, a signature,
8181/// and the PublicKey.
8282pub fn verify ( msg : & [ u8 ] , sig : & str , pk : & PublicKey ) -> bool {
83- match recover_pk ( msg, sig) {
84- Ok ( x) => x == * pk,
85- Err ( _) => false
86- }
83+ match recover_pk ( msg, sig) {
84+ Ok ( x) => x == * pk,
85+ Err ( _) => false
86+ }
8787}
8888
8989#[ cfg( test) ]
9090mod test {
91- use core:: str:: FromStr ;
92- use crate :: util:: message_signing:: { sign, recover_pk, verify} ;
93- use bitcoin:: secp256k1:: ONE_KEY ;
94- use bitcoin:: secp256k1:: { PublicKey , Secp256k1 } ;
95-
96- #[ test]
97- fn test_sign ( ) {
98- let message = "test message" ;
99- let zbase32_sig = sign ( message. as_bytes ( ) , & ONE_KEY ) ;
100-
101- assert_eq ! ( zbase32_sig. unwrap( ) , "d9tibmnic9t5y41hg7hkakdcra94akas9ku3rmmj4ag9mritc8ok4p5qzefs78c9pqfhpuftqqzhydbdwfg7u6w6wdxcqpqn4sj4e73e" )
102- }
103-
104- #[ test]
105- fn test_recover_pk ( ) {
106- let message = "test message" ;
107- let sig = "d9tibmnic9t5y41hg7hkakdcra94akas9ku3rmmj4ag9mritc8ok4p5qzefs78c9pqfhpuftqqzhydbdwfg7u6w6wdxcqpqn4sj4e73e" ;
108- let pk = recover_pk ( message. as_bytes ( ) , sig) ;
109-
110- assert_eq ! ( pk. unwrap( ) , PublicKey :: from_secret_key( & Secp256k1 :: signing_only( ) , & ONE_KEY ) )
111- }
112-
113- #[ test]
114- fn test_verify ( ) {
115- let message = "another message" ;
116- let sig = sign ( message. as_bytes ( ) , & ONE_KEY ) . unwrap ( ) ;
117- let pk = PublicKey :: from_secret_key ( & Secp256k1 :: signing_only ( ) , & ONE_KEY ) ;
118-
119- assert ! ( verify( message. as_bytes( ) , & sig, & pk) )
120- }
121-
122- #[ test]
123- fn test_verify_ground_truth_ish ( ) {
124- // There are no standard tests vectors for Sign/Verify, using the same tests vectors as c-lightning to see if they are compatible.
125- // Taken from https://github.com/ElementsProject/lightning/blob/1275af6fbb02460c8eb2f00990bb0ef9179ce8f3/tests/test_misc.py#L1925-L1938
126-
127- let corpus = [
128- [ "@bitconner" ,
129- "is this compatible?" ,
130- "rbgfioj114mh48d8egqx8o9qxqw4fmhe8jbeeabdioxnjk8z3t1ma1hu1fiswpakgucwwzwo6ofycffbsqusqdimugbh41n1g698hr9t" ,
131- "02b80cabdf82638aac86948e4c06e82064f547768dcef977677b9ea931ea75bab5" ] ,
132- [ "@duck1123" ,
133- "hi" ,
134- "rnrphcjswusbacjnmmmrynh9pqip7sy5cx695h6mfu64iac6qmcmsd8xnsyczwmpqp9shqkth3h4jmkgyqu5z47jfn1q7gpxtaqpx4xg" ,
135- "02de60d194e1ca5947b59fe8e2efd6aadeabfb67f2e89e13ae1a799c1e08e4a43b" ] ,
136- [ "@jochemin" ,
137- "hi" ,
138- "ry8bbsopmduhxy3dr5d9ekfeabdpimfx95kagdem7914wtca79jwamtbw4rxh69hg7n6x9ty8cqk33knbxaqftgxsfsaeprxkn1k48p3" ,
139- "022b8ece90ee891cbcdac0c1cc6af46b73c47212d8defbce80265ac81a6b794931" ] ,
140- ] ;
141-
142- for c in & corpus {
143- assert ! ( verify( c[ 1 ] . as_bytes( ) , c[ 2 ] , & PublicKey :: from_str( c[ 3 ] ) . unwrap( ) ) )
144- }
145- }
146- }
91+ use core:: str:: FromStr ;
92+ use crate :: util:: message_signing:: { sign, recover_pk, verify} ;
93+ use bitcoin:: secp256k1:: ONE_KEY ;
94+ use bitcoin:: secp256k1:: { PublicKey , Secp256k1 } ;
95+
96+ #[ test]
97+ fn test_sign ( ) {
98+ let message = "test message" ;
99+ let zbase32_sig = sign ( message. as_bytes ( ) , & ONE_KEY ) ;
100+
101+ assert_eq ! ( zbase32_sig. unwrap( ) , "d9tibmnic9t5y41hg7hkakdcra94akas9ku3rmmj4ag9mritc8ok4p5qzefs78c9pqfhpuftqqzhydbdwfg7u6w6wdxcqpqn4sj4e73e" )
102+ }
103+
104+ #[ test]
105+ fn test_recover_pk ( ) {
106+ let message = "test message" ;
107+ let sig = "d9tibmnic9t5y41hg7hkakdcra94akas9ku3rmmj4ag9mritc8ok4p5qzefs78c9pqfhpuftqqzhydbdwfg7u6w6wdxcqpqn4sj4e73e" ;
108+ let pk = recover_pk ( message. as_bytes ( ) , sig) ;
109+
110+ assert_eq ! ( pk. unwrap( ) , PublicKey :: from_secret_key( & Secp256k1 :: signing_only( ) , & ONE_KEY ) )
111+ }
112+
113+ #[ test]
114+ fn test_verify ( ) {
115+ let message = "another message" ;
116+ let sig = sign ( message. as_bytes ( ) , & ONE_KEY ) . unwrap ( ) ;
117+ let pk = PublicKey :: from_secret_key ( & Secp256k1 :: signing_only ( ) , & ONE_KEY ) ;
118+
119+ assert ! ( verify( message. as_bytes( ) , & sig, & pk) )
120+ }
121+
122+ #[ test]
123+ fn test_verify_ground_truth_ish ( ) {
124+ // There are no standard tests vectors for Sign/Verify, using the same tests vectors as c-lightning to see if they are compatible.
125+ // Taken from https://github.com/ElementsProject/lightning/blob/1275af6fbb02460c8eb2f00990bb0ef9179ce8f3/tests/test_misc.py#L1925-L1938
126+
127+ let corpus = [
128+ [ "@bitconner" ,
129+ "is this compatible?" ,
130+ "rbgfioj114mh48d8egqx8o9qxqw4fmhe8jbeeabdioxnjk8z3t1ma1hu1fiswpakgucwwzwo6ofycffbsqusqdimugbh41n1g698hr9t" ,
131+ "02b80cabdf82638aac86948e4c06e82064f547768dcef977677b9ea931ea75bab5" ] ,
132+ [ "@duck1123" ,
133+ "hi" ,
134+ "rnrphcjswusbacjnmmmrynh9pqip7sy5cx695h6mfu64iac6qmcmsd8xnsyczwmpqp9shqkth3h4jmkgyqu5z47jfn1q7gpxtaqpx4xg" ,
135+ "02de60d194e1ca5947b59fe8e2efd6aadeabfb67f2e89e13ae1a799c1e08e4a43b" ] ,
136+ [ "@jochemin" ,
137+ "hi" ,
138+ "ry8bbsopmduhxy3dr5d9ekfeabdpimfx95kagdem7914wtca79jwamtbw4rxh69hg7n6x9ty8cqk33knbxaqftgxsfsaeprxkn1k48p3" ,
139+ "022b8ece90ee891cbcdac0c1cc6af46b73c47212d8defbce80265ac81a6b794931" ] ,
140+ ] ;
141+
142+ for c in & corpus {
143+ assert ! ( verify( c[ 1 ] . as_bytes( ) , c[ 2 ] , & PublicKey :: from_str( c[ 3 ] ) . unwrap( ) ) )
144+ }
145+ }
146+ }
147+
0 commit comments