Skip to content

Commit d0fa25e

Browse files
committed
Merge branch 'develop'
2 parents 75d5bff + e664153 commit d0fa25e

File tree

2 files changed

+117
-103
lines changed

2 files changed

+117
-103
lines changed

lib/eth/open_ssl.rb

Lines changed: 116 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class OpenSsl
88
if FFI::Platform.windows?
99
ffi_lib 'libeay32', 'ssleay32'
1010
else
11-
ffi_lib 'ssl'
11+
ffi_lib ['libssl.so.1.0.0', 'ssl']
1212
end
1313

1414
NID_secp256k1 = 714
@@ -53,130 +53,144 @@ class OpenSsl
5353
attach_function :EC_POINT_set_compressed_coordinates_GFp, [:pointer, :pointer, :pointer, :int, :pointer], :int
5454
attach_function :i2o_ECPublicKey, [:pointer, :pointer], :uint
5555

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
6860

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
7364

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())
7568

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)
8171

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)
8476

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)
9378

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)
9584

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") }
9887

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
10296

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)
10698

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
109101

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
111155

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
118158

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
121162

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)
126164
end
127165

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
155173
end
156174

157-
EC_KEY_free(eckey)
158175

159-
pub_hex
160-
end
176+
private
161177

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
164181

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
168189

169-
compressed = false
170-
pubkey = recover_public_key_from_signature(hash, signature, (version - v_base), compressed)
171-
end
190+
EC_KEY_free(eckey)
172191

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
180194
end
181195

182196
end

lib/eth/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Eth
2-
VERSION = "0.4.3"
2+
VERSION = "0.4.4"
33
end

0 commit comments

Comments
 (0)