eth 0.4.18 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/eth/open_ssl.rb DELETED
@@ -1,395 +0,0 @@
1
- # originally lifted from https://github.com/lian/bitcoin-ruby
2
- # thanks to everyone there for figuring this out
3
-
4
- # encoding: ascii-8bit
5
-
6
- require "openssl"
7
- require "ffi"
8
-
9
- module Eth
10
- class OpenSsl
11
- extend FFI::Library
12
-
13
- # Use the library loaded by the extension require above.
14
- ffi_lib FFI::CURRENT_PROCESS
15
-
16
- NID_secp256k1 = 714
17
- POINT_CONVERSION_COMPRESSED = 2
18
- POINT_CONVERSION_UNCOMPRESSED = 4
19
-
20
- # OpenSSL 1.1.0 engine constants, taken from:
21
- # https://github.com/openssl/openssl/blob/2be8c56a39b0ec2ec5af6ceaf729df154d784a43/include/openssl/crypto.h
22
- OPENSSL_INIT_ENGINE_RDRAND = 0x00000200
23
- OPENSSL_INIT_ENGINE_DYNAMIC = 0x00000400
24
- OPENSSL_INIT_ENGINE_CRYPTODEV = 0x00001000
25
- OPENSSL_INIT_ENGINE_CAPI = 0x00002000
26
- OPENSSL_INIT_ENGINE_PADLOCK = 0x00004000
27
- OPENSSL_INIT_ENGINE_ALL_BUILTIN = (OPENSSL_INIT_ENGINE_RDRAND |
28
- OPENSSL_INIT_ENGINE_DYNAMIC |
29
- OPENSSL_INIT_ENGINE_CRYPTODEV |
30
- OPENSSL_INIT_ENGINE_CAPI |
31
- OPENSSL_INIT_ENGINE_PADLOCK)
32
-
33
- # OpenSSL 1.1.0 load strings constant, taken from:
34
- # https://github.com/openssl/openssl/blob/c162c126be342b8cd97996346598ecf7db56130f/include/openssl/ssl.h
35
- OPENSSL_INIT_LOAD_SSL_STRINGS = 0x00200000
36
-
37
- # This is the very first function we need to use to determine what version
38
- # of OpenSSL we are interacting with.
39
- begin
40
- attach_function :OpenSSL_version_num, [], :ulong
41
- rescue FFI::NotFoundError
42
- attach_function :SSLeay, [], :long
43
- end
44
-
45
- begin
46
- # Initialization procedure for the library was changed in OpenSSL 1.1.0
47
- attach_function :OPENSSL_init_ssl, [:uint64, :pointer], :int
48
- rescue FFI::NotFoundError
49
- attach_function :SSL_library_init, [], :int
50
- attach_function :ERR_load_crypto_strings, [], :void
51
- attach_function :SSL_load_error_strings, [], :void
52
- end
53
-
54
- attach_function :RAND_poll, [], :int
55
-
56
- attach_function :BN_CTX_free, [:pointer], :int
57
- attach_function :BN_CTX_new, [], :pointer
58
- attach_function :BN_add, %i[pointer pointer pointer], :int
59
- attach_function :BN_bin2bn, %i[pointer int pointer], :pointer
60
- attach_function :BN_bn2bin, %i[pointer pointer], :int
61
- attach_function :BN_cmp, %i[pointer pointer], :int
62
- attach_function :BN_dup, [:pointer], :pointer
63
- attach_function :BN_free, [:pointer], :int
64
- attach_function :BN_mod_inverse, %i[pointer pointer pointer pointer], :pointer
65
- attach_function :BN_mod_mul, %i[pointer pointer pointer pointer pointer], :int
66
- attach_function :BN_mod_sub, %i[pointer pointer pointer pointer pointer], :int
67
- attach_function :BN_mul_word, %i[pointer int], :int
68
- attach_function :BN_new, [], :pointer
69
- attach_function :BN_rshift, %i[pointer pointer int], :int
70
- attach_function :BN_rshift1, %i[pointer pointer], :int
71
- attach_function :BN_set_word, %i[pointer int], :int
72
- attach_function :BN_sub, %i[pointer pointer pointer], :int
73
- attach_function :EC_GROUP_get_curve_GFp, %i[pointer pointer pointer pointer pointer], :int
74
- attach_function :EC_GROUP_get_degree, [:pointer], :int
75
- attach_function :EC_GROUP_get_order, %i[pointer pointer pointer], :int
76
- attach_function :EC_KEY_free, [:pointer], :int
77
- attach_function :EC_KEY_get0_group, [:pointer], :pointer
78
- attach_function :EC_KEY_get0_private_key, [:pointer], :pointer
79
- attach_function :EC_KEY_new_by_curve_name, [:int], :pointer
80
- attach_function :EC_KEY_set_conv_form, %i[pointer int], :void
81
- attach_function :EC_KEY_set_private_key, %i[pointer pointer], :int
82
- attach_function :EC_KEY_set_public_key, %i[pointer pointer], :int
83
- attach_function :EC_POINT_free, [:pointer], :int
84
- attach_function :EC_POINT_mul, %i[pointer pointer pointer pointer pointer pointer], :int
85
- attach_function :EC_POINT_new, [:pointer], :pointer
86
- attach_function :EC_POINT_set_compressed_coordinates_GFp,
87
- %i[pointer pointer pointer int pointer], :int
88
- attach_function :i2o_ECPublicKey, %i[pointer pointer], :uint
89
- attach_function :ECDSA_do_sign, %i[pointer uint pointer], :pointer
90
- attach_function :BN_num_bits, [:pointer], :int
91
- attach_function :ECDSA_SIG_free, [:pointer], :void
92
- attach_function :EC_POINT_add, %i[pointer pointer pointer pointer pointer], :int
93
- attach_function :EC_POINT_point2hex, %i[pointer pointer int pointer], :string
94
- attach_function :EC_POINT_hex2point, %i[pointer string pointer pointer], :pointer
95
- attach_function :d2i_ECDSA_SIG, %i[pointer pointer long], :pointer
96
- attach_function :i2d_ECDSA_SIG, %i[pointer pointer], :int
97
- attach_function :OPENSSL_free, :CRYPTO_free, [:pointer], :void
98
-
99
- def self.BN_num_bytes(ptr) # rubocop:disable Naming/MethodName
100
- (BN_num_bits(ptr) + 7) / 8
101
- end
102
-
103
- # resolve public from private key, using ffi and libssl.so
104
- # example:
105
- # keypair = Bitcoin.generate_key; Bitcoin::OpenSSL_EC.regenerate_key(keypair.first) == keypair
106
- def self.regenerate_key(private_key)
107
- private_key = [private_key].pack("H*") if private_key.bytesize >= (32 * 2)
108
- private_key_hex = private_key.unpack("H*")[0]
109
-
110
- group = OpenSSL::PKey::EC::Group.new("secp256k1")
111
- key = OpenSSL::PKey::EC.new(group)
112
- key.private_key = OpenSSL::BN.new(private_key_hex, 16)
113
- key.public_key = group.generator.mul(key.private_key)
114
-
115
- priv_hex = key.private_key.to_bn.to_s(16).downcase.rjust(64, "0")
116
- if priv_hex != private_key_hex
117
- raise "regenerated wrong private_key, raise here before generating a faulty public_key too!"
118
- end
119
-
120
- [priv_hex, key.public_key.to_bn.to_s(16).downcase]
121
- end
122
-
123
- # Given the components of a signature and a selector value, recover and
124
- # return the public key that generated the signature according to the
125
- # algorithm in SEC1v2 section 4.1.6.
126
- #
127
- # rec_id is an index from 0 to 3 that indicates which of the 4 possible
128
- # keys is the correct one. Because the key recovery operation yields
129
- # multiple potential keys, the correct key must either be stored alongside
130
- # the signature, or you must be willing to try each rec_id in turn until
131
- # you find one that outputs the key you are expecting.
132
- #
133
- # If this method returns nil, it means recovery was not possible and rec_id
134
- # should be iterated.
135
- #
136
- # Given the above two points, a correct usage of this method is inside a
137
- # for loop from 0 to 3, and if the output is nil OR a key that is not the
138
- # one you expect, you try again with the next rec_id.
139
- #
140
- # message_hash = hash of the signed message.
141
- # signature = the R and S components of the signature, wrapped.
142
- # rec_id = which possible key to recover.
143
- # is_compressed = whether or not the original pubkey was compressed.
144
- def self.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed)
145
- return nil if rec_id < 0 || signature.bytesize != 65
146
- init_ffi_ssl
147
-
148
- signature = FFI::MemoryPointer.from_string(signature)
149
- # signature_bn = BN_bin2bn(signature, 65, BN_new())
150
- r = BN_bin2bn(signature[1], 32, BN_new())
151
- s = BN_bin2bn(signature[33], 32, BN_new())
152
-
153
- i = rec_id / 2
154
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
155
-
156
- EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
157
-
158
- group = EC_KEY_get0_group(eckey)
159
- order = BN_new()
160
- EC_GROUP_get_order(group, order, nil)
161
- x = BN_dup(order)
162
- BN_mul_word(x, i)
163
- BN_add(x, x, r)
164
-
165
- field = BN_new()
166
- EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
167
-
168
- if BN_cmp(x, field) >= 0
169
- [r, s, order, x, field].each { |item| BN_free(item) }
170
- EC_KEY_free(eckey)
171
- return nil
172
- end
173
-
174
- big_r = EC_POINT_new(group)
175
- EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil)
176
-
177
- big_q = EC_POINT_new(group)
178
- n = EC_GROUP_get_degree(group)
179
- e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new())
180
- BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n
181
-
182
- ctx = BN_CTX_new()
183
- zero = BN_new()
184
- rr = BN_new()
185
- sor = BN_new()
186
- eor = BN_new()
187
- BN_set_word(zero, 0)
188
- BN_mod_sub(e, zero, e, order, ctx)
189
- BN_mod_inverse(rr, r, order, ctx)
190
- BN_mod_mul(sor, s, rr, order, ctx)
191
- BN_mod_mul(eor, e, rr, order, ctx)
192
- EC_POINT_mul(group, big_q, eor, big_r, sor, ctx)
193
- EC_KEY_set_public_key(eckey, big_q)
194
- BN_CTX_free(ctx)
195
-
196
- [r, s, order, x, field, e, zero, rr, sor, eor].each { |item| BN_free(item) }
197
- [big_r, big_q].each { |item| EC_POINT_free(item) }
198
-
199
- length = i2o_ECPublicKey(eckey, nil)
200
- buf = FFI::MemoryPointer.new(:uint8, length)
201
- ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
202
- pub_hex = buf.read_string(length).unpack("H*")[0] if i2o_ECPublicKey(eckey, ptr) == length
203
-
204
- EC_KEY_free(eckey)
205
-
206
- pub_hex
207
- end
208
-
209
- # Regenerate a DER-encoded signature such that the S-value complies with the BIP62
210
- # specification.
211
- #
212
- def self.signature_to_low_s(signature)
213
- init_ffi_ssl
214
-
215
- buf = FFI::MemoryPointer.new(:uint8, 34)
216
- temp = signature.unpack("C*")
217
- length_r = temp[3]
218
- length_s = temp[5 + length_r]
219
- sig = FFI::MemoryPointer.from_string(signature)
220
-
221
- # Calculate the lower s value
222
- s = BN_bin2bn(sig[6 + length_r], length_s, BN_new())
223
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
224
- group = EC_KEY_get0_group(eckey)
225
- order = BN_new()
226
- halforder = BN_new()
227
- ctx = BN_CTX_new()
228
-
229
- EC_GROUP_get_order(group, order, ctx)
230
- BN_rshift1(halforder, order)
231
- BN_sub(s, order, s) if BN_cmp(s, halforder) > 0
232
-
233
- BN_free(halforder)
234
- BN_free(order)
235
- BN_CTX_free(ctx)
236
-
237
- length_s = BN_bn2bin(s, buf)
238
- # p buf.read_string(length_s).unpack("H*")
239
-
240
- # Re-encode the signature in DER format
241
- sig = [0x30, 0, 0x02, length_r]
242
- sig.concat(temp.slice(4, length_r))
243
- sig << 0x02
244
- sig << length_s
245
- sig.concat(buf.read_string(length_s).unpack("C*"))
246
- sig[1] = sig.size - 2
247
-
248
- BN_free(s)
249
- EC_KEY_free(eckey)
250
-
251
- sig.pack("C*")
252
- end
253
-
254
- def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil)
255
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
256
-
257
- private_key = [private_key].pack("H*") if private_key.bytesize >= 64
258
- private_key_hex = private_key.unpack("H*")[0]
259
-
260
- public_key_hex ||= regenerate_key(private_key_hex).last
261
- pubkey_compressed ||= public_key_hex[0..1] != "04"
262
-
263
- init_ffi_ssl
264
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
265
- priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new())
266
-
267
- group = EC_KEY_get0_group(eckey)
268
- order = BN_new()
269
- ctx = BN_CTX_new()
270
- EC_GROUP_get_order(group, order, ctx)
271
-
272
- pub_key = EC_POINT_new(group)
273
- EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
274
- EC_KEY_set_private_key(eckey, priv_key)
275
- EC_KEY_set_public_key(eckey, pub_key)
276
-
277
- signature = ECDSA_do_sign(msg32, msg32.size, eckey)
278
-
279
- BN_free(order)
280
- BN_CTX_free(ctx)
281
- EC_POINT_free(pub_key)
282
- BN_free(priv_key)
283
- EC_KEY_free(eckey)
284
-
285
- buf = FFI::MemoryPointer.new(:uint8, 32)
286
- head = nil
287
- r, s = signature.get_array_of_pointer(0, 2).map do |i|
288
- BN_bn2bin(i, buf)
289
- buf.read_string(BN_num_bytes(i)).rjust(32, "\x00")
290
- end
291
-
292
- rec_id = nil
293
- if signature.get_array_of_pointer(0, 2).all? { |i| BN_num_bits(i) <= 256 }
294
- 4.times do |i|
295
- head = [27 + i + (pubkey_compressed ? 4 : 0)].pack("C")
296
- recovered_key = recover_public_key_from_signature(
297
- msg32.read_string(32), [head, r, s].join, i, pubkey_compressed
298
- )
299
- if public_key_hex == recovered_key
300
- rec_id = i
301
- break
302
- end
303
- end
304
- end
305
-
306
- ECDSA_SIG_free(signature)
307
-
308
- [head, [r, s]].join if rec_id
309
- end
310
-
311
- def self.recover_compact(hash, signature)
312
- return false if signature.bytesize != 65
313
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
314
-
315
- version = signature.unpack("C")[0]
316
-
317
- # Version of signature should be 27 or 28, but 0 and 1 are also possible versions
318
- # which can show up in Ledger hardwallet signings
319
- if version < 27
320
- version += 27
321
- end
322
-
323
- return false if version < 27 || version > 34
324
-
325
- compressed = version >= 31
326
- version -= 4 if compressed
327
-
328
- recover_public_key_from_signature(msg32.read_string(32), signature, version - 27, compressed)
329
- end
330
-
331
- # lifted from https://github.com/GemHQ/money-tree
332
- def self.ec_add(point0, point1)
333
- init_ffi_ssl
334
-
335
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
336
- group = EC_KEY_get0_group(eckey)
337
-
338
- point_0_hex = point0.to_bn.to_s(16)
339
- point_0_pt = EC_POINT_hex2point(group, point_0_hex, nil, nil)
340
- point_1_hex = point1.to_bn.to_s(16)
341
- point_1_pt = EC_POINT_hex2point(group, point_1_hex, nil, nil)
342
-
343
- sum_point = EC_POINT_new(group)
344
- EC_POINT_add(group, sum_point, point_0_pt, point_1_pt, nil)
345
- hex = EC_POINT_point2hex(group, sum_point, POINT_CONVERSION_UNCOMPRESSED, nil)
346
- EC_KEY_free(eckey)
347
- EC_POINT_free(sum_point)
348
- hex
349
- end
350
-
351
- # repack signature for OpenSSL 1.0.1k handling of DER signatures
352
- # https://github.com/bitcoin/bitcoin/pull/5634/files
353
- def self.repack_der_signature(signature)
354
- init_ffi_ssl
355
-
356
- return false if signature.empty?
357
-
358
- # New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
359
- norm_der = FFI::MemoryPointer.new(:pointer)
360
- sig_ptr = FFI::MemoryPointer.new(:pointer).put_pointer(
361
- 0, FFI::MemoryPointer.from_string(signature)
362
- )
363
-
364
- norm_sig = d2i_ECDSA_SIG(nil, sig_ptr, signature.bytesize)
365
-
366
- derlen = i2d_ECDSA_SIG(norm_sig, norm_der)
367
- ECDSA_SIG_free(norm_sig)
368
- return false if derlen <= 0
369
-
370
- ret = norm_der.read_pointer.read_string(derlen)
371
- OPENSSL_free(norm_der.read_pointer)
372
-
373
- ret
374
- end
375
-
376
- def self.init_ffi_ssl
377
- @ssl_loaded ||= false
378
- return if @ssl_loaded
379
-
380
- if self.method_defined?(:OPENSSL_init_ssl)
381
- OPENSSL_init_ssl(
382
- OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_ENGINE_ALL_BUILTIN,
383
- nil
384
- )
385
- else
386
- SSL_library_init()
387
- ERR_load_crypto_strings()
388
- SSL_load_error_strings()
389
- end
390
-
391
- RAND_poll()
392
- @ssl_loaded = true
393
- end
394
- end
395
- end
data/lib/eth/secp256k1.rb DELETED
@@ -1,5 +0,0 @@
1
- module Eth
2
- class Secp256k1
3
- N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
4
- end
5
- end
data/lib/eth/sedes.rb DELETED
@@ -1,39 +0,0 @@
1
- module Eth
2
- module Sedes
3
- include RLP::Sedes
4
-
5
- extend self
6
-
7
- def address
8
- Binary.fixed_length(20, allow_empty: true)
9
- end
10
-
11
- def int20
12
- BigEndianInt.new(20)
13
- end
14
-
15
- def int32
16
- BigEndianInt.new(32)
17
- end
18
-
19
- def int256
20
- BigEndianInt.new(256)
21
- end
22
-
23
- def hash32
24
- Binary.fixed_length(32)
25
- end
26
-
27
- def trie_root
28
- Binary.fixed_length(32, allow_empty: true)
29
- end
30
-
31
- def big_endian_int
32
- RLP::Sedes.big_endian_int
33
- end
34
-
35
- def binary
36
- RLP::Sedes.binary
37
- end
38
- end
39
- end
data/lib/eth/utils.rb DELETED
@@ -1,126 +0,0 @@
1
- module Eth
2
- module Utils
3
- extend self
4
-
5
- def normalize_address(address)
6
- if address.nil? || address == ""
7
- ""
8
- elsif address.size == 40
9
- hex_to_bin address
10
- elsif address.size == 42 && address[0..1] == "0x"
11
- hex_to_bin address[2..-1]
12
- else
13
- address
14
- end
15
- end
16
-
17
- def bin_to_hex(string)
18
- RLP::Utils.encode_hex string
19
- end
20
-
21
- def hex_to_bin(string)
22
- RLP::Utils.decode_hex remove_hex_prefix(string)
23
- end
24
-
25
- def base256_to_int(str)
26
- RLP::Sedes.big_endian_int.deserialize str.sub(/\A(\x00)+/, "")
27
- end
28
-
29
- def int_to_base256(int)
30
- RLP::Sedes.big_endian_int.serialize int
31
- end
32
-
33
- def v_r_s_for(signature)
34
- [
35
- signature[0].bytes[0],
36
- Utils.base256_to_int(signature[1..32]),
37
- Utils.base256_to_int(signature[33..65]),
38
- ]
39
- end
40
-
41
- def prefix_hex(hex)
42
- hex.match(/\A0x/) ? hex : "0x#{hex}"
43
- end
44
-
45
- def remove_hex_prefix(s)
46
- s[0, 2] == "0x" ? s[2..-1] : s
47
- end
48
-
49
- def bin_to_prefixed_hex(binary)
50
- prefix_hex bin_to_hex(binary)
51
- end
52
-
53
- def prefix_message(message)
54
- "\x19Ethereum Signed Message:\n#{message.length}#{message}"
55
- end
56
-
57
- def public_key_to_address(hex)
58
- bytes = hex_to_bin(hex)
59
- address_bytes = Utils.keccak256(bytes[1..-1])[-20..-1]
60
- format_address bin_to_prefixed_hex(address_bytes)
61
- end
62
-
63
- def sha256(x)
64
- Digest::SHA256.digest x
65
- end
66
-
67
- def keccak256(x)
68
- Digest::Keccak.new(256).digest(x)
69
- end
70
-
71
- def keccak512(x)
72
- Digest::Keccak.new(512).digest(x)
73
- end
74
-
75
- def keccak256_rlp(x)
76
- keccak256 RLP.encode(x)
77
- end
78
-
79
- def ripemd160(x)
80
- Digest::RMD160.digest x
81
- end
82
-
83
- def hash160(x)
84
- ripemd160 sha256(x)
85
- end
86
-
87
- def zpad(x, l)
88
- lpad x, BYTE_ZERO, l
89
- end
90
-
91
- def zunpad(x)
92
- x.sub(/\A\x00+/, "")
93
- end
94
-
95
- def zpad_int(n, l = 32)
96
- zpad encode_int(n), l
97
- end
98
-
99
- def zpad_hex(s, l = 32)
100
- zpad decode_hex(s), l
101
- end
102
-
103
- def valid_address?(address)
104
- Address.new(address).valid?
105
- end
106
-
107
- def format_address(address)
108
- Address.new(address).checksummed
109
- end
110
-
111
- private
112
-
113
- def lpad(x, symbol, l)
114
- return x if x.size >= l
115
- symbol * (l - x.size) + x
116
- end
117
-
118
- def encode_int(n)
119
- unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
120
- raise ArgumentError, "Integer invalid or out of range: #{n}"
121
- end
122
-
123
- int_to_base256 n
124
- end
125
- end
126
- end