@@ -29,118 +29,119 @@ use bitcoin::secp256k1::{Error, Message, PublicKey, Secp256k1, SecretKey};
29
29
static LN_MESSAGE_PREFIX : & [ u8 ] = b"Lightning Signed Message:" ;
30
30
31
31
fn 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 ;
34
34
35
- [ & [ prefix] , & rsig[ ..] ] . concat ( )
35
+ [ & [ prefix] , & rsig[ ..] ] . concat ( )
36
36
}
37
37
38
38
fn 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
+ }
51
51
}
52
52
53
53
/// Creates a digital signature of a message given a SecretKey, like the node's secret.
54
54
/// 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.
55
55
/// Signatures are EC recoverable, meaning that given the message and the signature the PublicKey of the signer can be extracted.
56
56
pub 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 ( ) ) ;
59
59
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) ) )
62
62
}
63
63
64
64
/// Recovers the PublicKey of the signer of the message given the message and the signature.
65
65
pub 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
+ }
78
78
}
79
79
80
80
/// Verifies a message was signed by a PrivateKey that derives to a given PublicKey, given a message, a signature,
81
81
/// and the PublicKey.
82
82
pub 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
+ }
87
87
}
88
88
89
89
#[ cfg( test) ]
90
90
mod 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