@@ -8,7 +8,7 @@ class OpenSsl
8
8
if FFI ::Platform . windows?
9
9
ffi_lib 'libeay32' , 'ssleay32'
10
10
else
11
- ffi_lib ' ssl'
11
+ ffi_lib [ 'libssl.so.1.0.0' , ' ssl']
12
12
end
13
13
14
14
NID_secp256k1 = 714
@@ -53,130 +53,144 @@ class OpenSsl
53
53
attach_function :EC_POINT_set_compressed_coordinates_GFp , [ :pointer , :pointer , :pointer , :int , :pointer ] , :int
54
54
attach_function :i2o_ECPublicKey , [ :pointer , :pointer ] , :uint
55
55
56
- def self . BN_num_bytes ( ptr ) ; ( BN_num_bits ( ptr ) + 7 ) / 8 ; end
57
-
58
- def self . sign_compact ( hash , private_key , public_key_hex )
59
- private_key = [ private_key ] . pack ( "H*" ) if private_key . bytesize >= 64
60
- pubkey_compressed = false
61
-
62
- init_ffi_ssl
63
- eckey = EC_KEY_new_by_curve_name ( NID_secp256k1 )
64
- priv_key = BN_bin2bn ( private_key , private_key . bytesize , BN_new ( ) )
65
-
66
- group , order , ctx = EC_KEY_get0_group ( eckey ) , BN_new ( ) , BN_CTX_new ( )
67
- EC_GROUP_get_order ( group , order , ctx )
56
+ class << self
57
+ def BN_num_bytes ( ptr )
58
+ ( BN_num_bits ( ptr ) + 7 ) / 8
59
+ end
68
60
69
- pub_key = EC_POINT_new ( group )
70
- EC_POINT_mul ( group , pub_key , priv_key , nil , nil , ctx )
71
- EC_KEY_set_private_key ( eckey , priv_key )
72
- EC_KEY_set_public_key ( eckey , pub_key )
61
+ def sign_compact ( hash , private_key , public_key_hex )
62
+ private_key = [ private_key ] . pack ( "H*" ) if private_key . bytesize >= 64
63
+ pubkey_compressed = false
73
64
74
- signature = ECDSA_do_sign ( hash , hash . bytesize , eckey )
65
+ init_ffi_ssl
66
+ eckey = EC_KEY_new_by_curve_name ( NID_secp256k1 )
67
+ priv_key = BN_bin2bn ( private_key , private_key . bytesize , BN_new ( ) )
75
68
76
- BN_free ( order )
77
- BN_CTX_free ( ctx )
78
- EC_POINT_free ( pub_key )
79
- BN_free ( priv_key )
80
- EC_KEY_free ( eckey )
69
+ group , order , ctx = EC_KEY_get0_group ( eckey ) , BN_new ( ) , BN_CTX_new ( )
70
+ EC_GROUP_get_order ( group , order , ctx )
81
71
82
- buf , rec_id , head = FFI ::MemoryPointer . new ( :uint8 , 32 ) , nil , nil
83
- r , s = signature . get_array_of_pointer ( 0 , 2 ) . map { |i | BN_bn2bin ( i , buf ) ; buf . read_string ( BN_num_bytes ( i ) ) . rjust ( 32 , "\x00 " ) }
72
+ pub_key = EC_POINT_new ( group )
73
+ EC_POINT_mul ( group , pub_key , priv_key , nil , nil , ctx )
74
+ EC_KEY_set_private_key ( eckey , priv_key )
75
+ EC_KEY_set_public_key ( eckey , pub_key )
84
76
85
- if signature . get_array_of_pointer ( 0 , 2 ) . all? { |i | BN_num_bits ( i ) <= 256 }
86
- 4 . times { |i |
87
- head = [ Eth . v_base + i ] . pack ( "C" )
88
- if public_key_hex == recover_public_key_from_signature ( hash , [ head , r , s ] . join , i , pubkey_compressed )
89
- rec_id = i ; break
90
- end
91
- }
92
- end
77
+ signature = ECDSA_do_sign ( hash , hash . bytesize , eckey )
93
78
94
- ECDSA_SIG_free ( signature )
79
+ BN_free ( order )
80
+ BN_CTX_free ( ctx )
81
+ EC_POINT_free ( pub_key )
82
+ BN_free ( priv_key )
83
+ EC_KEY_free ( eckey )
95
84
96
- [ head , [ r , s ] ] . join if rec_id
97
- end
85
+ buf , rec_id , head = FFI :: MemoryPointer . new ( :uint8 , 32 ) , nil , nil
86
+ r , s = signature . get_array_of_pointer ( 0 , 2 ) . map { | i | BN_bn2bin ( i , buf ) ; buf . read_string ( BN_num_bytes ( i ) ) . rjust ( 32 , " \x00 " ) }
98
87
99
- def self . recover_public_key_from_signature ( message_hash , signature , rec_id , is_compressed )
100
- return nil if rec_id < 0 or signature . bytesize != 65
101
- init_ffi_ssl
88
+ if signature . get_array_of_pointer ( 0 , 2 ) . all? { |i | BN_num_bits ( i ) <= 256 }
89
+ 4 . times { |i |
90
+ head = [ Eth . v_base + i ] . pack ( "C" )
91
+ if public_key_hex == recover_public_key_from_signature ( hash , [ head , r , s ] . join , i , pubkey_compressed )
92
+ rec_id = i ; break
93
+ end
94
+ }
95
+ end
102
96
103
- signature = FFI ::MemoryPointer . from_string ( signature )
104
- r = BN_bin2bn ( signature [ 1 ] , 32 , BN_new ( ) )
105
- s = BN_bin2bn ( signature [ 33 ] , 32 , BN_new ( ) )
97
+ ECDSA_SIG_free ( signature )
106
98
107
- n , i = 0 , rec_id / 2
108
- eckey = EC_KEY_new_by_curve_name ( NID_secp256k1 )
99
+ [ head , [ r , s ] ] . join if rec_id
100
+ end
109
101
110
- EC_KEY_set_conv_form ( eckey , POINT_CONVERSION_COMPRESSED ) if is_compressed
102
+ def recover_public_key_from_signature ( message_hash , signature , rec_id , is_compressed )
103
+ return nil if rec_id < 0 or signature . bytesize != 65
104
+ init_ffi_ssl
105
+
106
+ signature = FFI ::MemoryPointer . from_string ( signature )
107
+ r = BN_bin2bn ( signature [ 1 ] , 32 , BN_new ( ) )
108
+ s = BN_bin2bn ( signature [ 33 ] , 32 , BN_new ( ) )
109
+
110
+ _n , i = 0 , rec_id / 2
111
+ eckey = EC_KEY_new_by_curve_name ( NID_secp256k1 )
112
+
113
+ EC_KEY_set_conv_form ( eckey , POINT_CONVERSION_COMPRESSED ) if is_compressed
114
+
115
+ group = EC_KEY_get0_group ( eckey )
116
+ order = BN_new ( )
117
+ EC_GROUP_get_order ( group , order , nil )
118
+ x = BN_dup ( order )
119
+ BN_mul_word ( x , i )
120
+ BN_add ( x , x , r )
121
+
122
+ field = BN_new ( )
123
+ EC_GROUP_get_curve_GFp ( group , field , nil , nil , nil )
124
+
125
+ if BN_cmp ( x , field ) >= 0
126
+ bn_free_each r , s , order , x , field
127
+ EC_KEY_free ( eckey )
128
+ return nil
129
+ end
130
+
131
+ big_r = EC_POINT_new ( group )
132
+ EC_POINT_set_compressed_coordinates_GFp ( group , big_r , x , rec_id % 2 , nil )
133
+
134
+ big_q = EC_POINT_new ( group )
135
+ n = EC_GROUP_get_degree ( group )
136
+ e = BN_bin2bn ( message_hash , message_hash . bytesize , BN_new ( ) )
137
+ BN_rshift ( e , e , 8 - ( n & 7 ) ) if 8 * message_hash . bytesize > n
138
+
139
+ ctx = BN_CTX_new ( )
140
+ zero , rr , sor , eor = BN_new ( ) , BN_new ( ) , BN_new ( ) , BN_new ( )
141
+ BN_set_word ( zero , 0 )
142
+ BN_mod_sub ( e , zero , e , order , ctx )
143
+ BN_mod_inverse ( rr , r , order , ctx )
144
+ BN_mod_mul ( sor , s , rr , order , ctx )
145
+ BN_mod_mul ( eor , e , rr , order , ctx )
146
+ EC_POINT_mul ( group , big_q , eor , big_r , sor , ctx )
147
+ EC_KEY_set_public_key ( eckey , big_q )
148
+ BN_CTX_free ( ctx )
149
+
150
+ bn_free_each r , s , order , x , field , e , zero , rr , sor , eor
151
+ [ big_r , big_q ] . each { |j | EC_POINT_free ( j ) }
152
+
153
+ recover_public_hex eckey
154
+ end
111
155
112
- group = EC_KEY_get0_group ( eckey )
113
- order = BN_new ( )
114
- EC_GROUP_get_order ( group , order , nil )
115
- x = BN_dup ( order )
116
- BN_mul_word ( x , i )
117
- BN_add ( x , x , r )
156
+ def recover_compact ( hash , signature )
157
+ return false if signature . bytesize != 65
118
158
119
- field = BN_new ( )
120
- EC_GROUP_get_curve_GFp ( group , field , nil , nil , nil )
159
+ version = signature . unpack ( 'C' ) [ 0 ]
160
+ v_base = Eth . replayable_v? ( version ) ? Eth . replayable_chain_id : Eth . v_base
161
+ return false if version < v_base
121
162
122
- if BN_cmp ( x , field ) >= 0
123
- [ r , s , order , x , field ] . each { |i | BN_free ( i ) }
124
- EC_KEY_free ( eckey )
125
- return nil
163
+ recover_public_key_from_signature ( hash , signature , ( version - v_base ) , false )
126
164
end
127
165
128
- big_r = EC_POINT_new ( group )
129
- EC_POINT_set_compressed_coordinates_GFp ( group , big_r , x , rec_id % 2 , nil )
130
-
131
- big_q = EC_POINT_new ( group )
132
- n = EC_GROUP_get_degree ( group )
133
- e = BN_bin2bn ( message_hash , message_hash . bytesize , BN_new ( ) )
134
- BN_rshift ( e , e , 8 - ( n & 7 ) ) if 8 * message_hash . bytesize > n
135
-
136
- ctx = BN_CTX_new ( )
137
- zero , rr , sor , eor = BN_new ( ) , BN_new ( ) , BN_new ( ) , BN_new ( )
138
- BN_set_word ( zero , 0 )
139
- BN_mod_sub ( e , zero , e , order , ctx )
140
- BN_mod_inverse ( rr , r , order , ctx )
141
- BN_mod_mul ( sor , s , rr , order , ctx )
142
- BN_mod_mul ( eor , e , rr , order , ctx )
143
- EC_POINT_mul ( group , big_q , eor , big_r , sor , ctx )
144
- EC_KEY_set_public_key ( eckey , big_q )
145
- BN_CTX_free ( ctx )
146
-
147
- [ r , s , order , x , field , e , zero , rr , sor , eor ] . each { |i | BN_free ( i ) }
148
- [ big_r , big_q ] . each { |i | EC_POINT_free ( i ) }
149
-
150
- length = i2o_ECPublicKey ( eckey , nil )
151
- buf = FFI ::MemoryPointer . new ( :uint8 , length )
152
- ptr = FFI ::MemoryPointer . new ( :pointer ) . put_pointer ( 0 , buf )
153
- pub_hex = if i2o_ECPublicKey ( eckey , ptr ) == length
154
- buf . read_string ( length ) . unpack ( "H*" ) [ 0 ]
166
+ def init_ffi_ssl
167
+ return if @ssl_loaded
168
+ SSL_library_init ( )
169
+ ERR_load_crypto_strings ( )
170
+ SSL_load_error_strings ( )
171
+ RAND_poll ( )
172
+ @ssl_loaded = true
155
173
end
156
174
157
- EC_KEY_free ( eckey )
158
175
159
- pub_hex
160
- end
176
+ private
161
177
162
- def self . recover_compact ( hash , signature )
163
- return false if signature . bytesize != 65
178
+ def bn_free_each ( *list )
179
+ list . each { |j | BN_free ( j ) }
180
+ end
164
181
165
- version = signature . unpack ( 'C' ) [ 0 ]
166
- v_base = Eth . replayable_v? ( version ) ? Eth . replayable_chain_id : Eth . v_base
167
- return false if version < v_base
182
+ def recover_public_hex ( eckey )
183
+ length = i2o_ECPublicKey ( eckey , nil )
184
+ buf = FFI ::MemoryPointer . new ( :uint8 , length )
185
+ ptr = FFI ::MemoryPointer . new ( :pointer ) . put_pointer ( 0 , buf )
186
+ pub_hex = if i2o_ECPublicKey ( eckey , ptr ) == length
187
+ buf . read_string ( length ) . unpack ( "H*" ) [ 0 ]
188
+ end
168
189
169
- compressed = false
170
- pubkey = recover_public_key_from_signature ( hash , signature , ( version - v_base ) , compressed )
171
- end
190
+ EC_KEY_free ( eckey )
172
191
173
- def self . init_ffi_ssl
174
- return if @ssl_loaded
175
- SSL_library_init ( )
176
- ERR_load_crypto_strings ( )
177
- SSL_load_error_strings ( )
178
- RAND_poll ( )
179
- @ssl_loaded = true
192
+ pub_hex
193
+ end
180
194
end
181
195
182
196
end
0 commit comments