eth 0.4.12 → 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.
- checksums.yaml +5 -5
- data/.github/workflows/codeql.yml +44 -0
- data/.github/workflows/docs.yml +26 -0
- data/.github/workflows/spec.yml +41 -0
- data/.gitignore +42 -9
- data/.gitmodules +3 -3
- data/AUTHORS.txt +16 -0
- data/CHANGELOG.md +18 -13
- data/Gemfile +15 -2
- data/LICENSE.txt +202 -21
- data/README.md +157 -81
- data/bin/console +4 -5
- data/bin/setup +4 -2
- data/eth.gemspec +46 -24
- data/lib/eth/abi/constant.rb +63 -0
- data/lib/eth/abi/type.rb +177 -0
- data/lib/eth/abi.rb +390 -0
- data/lib/eth/address.rb +48 -11
- data/lib/eth/chain.rb +148 -0
- data/lib/eth/eip712.rb +184 -0
- data/lib/eth/key/decrypter.rb +118 -88
- data/lib/eth/key/encrypter.rb +176 -99
- data/lib/eth/key.rb +131 -48
- data/lib/eth/signature.rb +160 -0
- data/lib/eth/tx/eip1559.rb +329 -0
- data/lib/eth/tx/eip2930.rb +321 -0
- data/lib/eth/tx/legacy.rb +293 -0
- data/lib/eth/tx.rb +274 -143
- data/lib/eth/unit.rb +49 -0
- data/lib/eth/util.rb +178 -0
- data/lib/eth/version.rb +18 -1
- data/lib/eth.rb +27 -67
- metadata +50 -61
- data/.travis.yml +0 -10
- data/lib/eth/gas.rb +0 -9
- data/lib/eth/open_ssl.rb +0 -264
- data/lib/eth/secp256k1.rb +0 -7
- data/lib/eth/sedes.rb +0 -40
- data/lib/eth/utils.rb +0 -130
data/lib/eth/open_ssl.rb
DELETED
@@ -1,264 +0,0 @@
|
|
1
|
-
# originally lifted from https://github.com/lian/bitcoin-ruby
|
2
|
-
# thanks to everyone there for figuring this out
|
3
|
-
|
4
|
-
module Eth
|
5
|
-
class OpenSsl
|
6
|
-
extend FFI::Library
|
7
|
-
|
8
|
-
if FFI::Platform.windows?
|
9
|
-
ffi_lib 'libeay32', 'ssleay32'
|
10
|
-
else
|
11
|
-
ffi_lib [
|
12
|
-
'libssl.so.1.1.0', 'libssl.so.1.1',
|
13
|
-
'libssl.so.1.0.0', 'libssl.so.10',
|
14
|
-
'ssl'
|
15
|
-
]
|
16
|
-
end
|
17
|
-
|
18
|
-
NID_secp256k1 = 714
|
19
|
-
POINT_CONVERSION_COMPRESSED = 2
|
20
|
-
POINT_CONVERSION_UNCOMPRESSED = 4
|
21
|
-
|
22
|
-
# OpenSSL 1.1.0 version as a numerical version value as defined in:
|
23
|
-
# https://www.openssl.org/docs/man1.1.0/man3/OpenSSL_version.html
|
24
|
-
VERSION_1_1_0_NUM = 0x10100000
|
25
|
-
|
26
|
-
# OpenSSL 1.1.0 engine constants, taken from:
|
27
|
-
# https://github.com/openssl/openssl/blob/2be8c56a39b0ec2ec5af6ceaf729df154d784a43/include/openssl/crypto.h
|
28
|
-
OPENSSL_INIT_ENGINE_RDRAND = 0x00000200
|
29
|
-
OPENSSL_INIT_ENGINE_DYNAMIC = 0x00000400
|
30
|
-
OPENSSL_INIT_ENGINE_CRYPTODEV = 0x00001000
|
31
|
-
OPENSSL_INIT_ENGINE_CAPI = 0x00002000
|
32
|
-
OPENSSL_INIT_ENGINE_PADLOCK = 0x00004000
|
33
|
-
OPENSSL_INIT_ENGINE_ALL_BUILTIN = (
|
34
|
-
OPENSSL_INIT_ENGINE_RDRAND |
|
35
|
-
OPENSSL_INIT_ENGINE_DYNAMIC |
|
36
|
-
OPENSSL_INIT_ENGINE_CRYPTODEV |
|
37
|
-
OPENSSL_INIT_ENGINE_CAPI |
|
38
|
-
OPENSSL_INIT_ENGINE_PADLOCK
|
39
|
-
)
|
40
|
-
|
41
|
-
# OpenSSL 1.1.0 load strings constant, taken from:
|
42
|
-
# https://github.com/openssl/openssl/blob/c162c126be342b8cd97996346598ecf7db56130f/include/openssl/ssl.h
|
43
|
-
OPENSSL_INIT_LOAD_SSL_STRINGS = 0x00200000
|
44
|
-
|
45
|
-
# This is the very first function we need to use to determine what version
|
46
|
-
# of OpenSSL we are interacting with.
|
47
|
-
begin
|
48
|
-
attach_function :OpenSSL_version_num, [], :ulong
|
49
|
-
rescue FFI::NotFoundError
|
50
|
-
attach_function :SSLeay, [], :long
|
51
|
-
end
|
52
|
-
|
53
|
-
# Returns the version of SSL present.
|
54
|
-
#
|
55
|
-
# @return [Integer] version number as an integer.
|
56
|
-
def self.version
|
57
|
-
if self.respond_to?(:OpenSSL_version_num)
|
58
|
-
OpenSSL_version_num()
|
59
|
-
else
|
60
|
-
SSLeay()
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
if version >= VERSION_1_1_0_NUM
|
65
|
-
# Initialization procedure for the library was changed in OpenSSL 1.1.0
|
66
|
-
attach_function :OPENSSL_init_ssl, [:uint64, :pointer], :int
|
67
|
-
else
|
68
|
-
attach_function :SSL_library_init, [], :int
|
69
|
-
attach_function :ERR_load_crypto_strings, [], :void
|
70
|
-
attach_function :SSL_load_error_strings, [], :void
|
71
|
-
end
|
72
|
-
|
73
|
-
attach_function :RAND_poll, [], :int
|
74
|
-
attach_function :BN_CTX_free, [:pointer], :int
|
75
|
-
attach_function :BN_CTX_new, [], :pointer
|
76
|
-
attach_function :BN_add, [:pointer, :pointer, :pointer], :int
|
77
|
-
attach_function :BN_bin2bn, [:pointer, :int, :pointer], :pointer
|
78
|
-
attach_function :BN_bn2bin, [:pointer, :pointer], :int
|
79
|
-
attach_function :BN_cmp, [:pointer, :pointer], :int
|
80
|
-
attach_function :BN_dup, [:pointer], :pointer
|
81
|
-
attach_function :BN_free, [:pointer], :int
|
82
|
-
attach_function :BN_mod_inverse, [:pointer, :pointer, :pointer, :pointer], :pointer
|
83
|
-
attach_function :BN_mod_mul, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
|
84
|
-
attach_function :BN_mod_sub, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
|
85
|
-
attach_function :BN_mul_word, [:pointer, :int], :int
|
86
|
-
attach_function :BN_new, [], :pointer
|
87
|
-
attach_function :BN_num_bits, [:pointer], :int
|
88
|
-
attach_function :BN_rshift, [:pointer, :pointer, :int], :int
|
89
|
-
attach_function :BN_set_word, [:pointer, :int], :int
|
90
|
-
attach_function :ECDSA_SIG_free, [:pointer], :void
|
91
|
-
attach_function :ECDSA_do_sign, [:pointer, :uint, :pointer], :pointer
|
92
|
-
attach_function :EC_GROUP_get_curve_GFp, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
|
93
|
-
attach_function :EC_GROUP_get_degree, [:pointer], :int
|
94
|
-
attach_function :EC_GROUP_get_order, [:pointer, :pointer, :pointer], :int
|
95
|
-
attach_function :EC_KEY_free, [:pointer], :int
|
96
|
-
attach_function :EC_KEY_get0_group, [:pointer], :pointer
|
97
|
-
attach_function :EC_KEY_new_by_curve_name, [:int], :pointer
|
98
|
-
attach_function :EC_KEY_set_conv_form, [:pointer, :int], :void
|
99
|
-
attach_function :EC_KEY_set_private_key, [:pointer, :pointer], :int
|
100
|
-
attach_function :EC_KEY_set_public_key, [:pointer, :pointer], :int
|
101
|
-
attach_function :EC_POINT_free, [:pointer], :int
|
102
|
-
attach_function :EC_POINT_mul, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
|
103
|
-
attach_function :EC_POINT_new, [:pointer], :pointer
|
104
|
-
attach_function :EC_POINT_set_compressed_coordinates_GFp, [:pointer, :pointer, :pointer, :int, :pointer], :int
|
105
|
-
attach_function :i2o_ECPublicKey, [:pointer, :pointer], :uint
|
106
|
-
|
107
|
-
class << self
|
108
|
-
def BN_num_bytes(ptr)
|
109
|
-
(BN_num_bits(ptr) + 7) / 8
|
110
|
-
end
|
111
|
-
|
112
|
-
def sign_compact(hash, private_key, public_key_hex)
|
113
|
-
private_key = [private_key].pack("H*") if private_key.bytesize >= 64
|
114
|
-
pubkey_compressed = false
|
115
|
-
|
116
|
-
init_ffi_ssl
|
117
|
-
eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
|
118
|
-
priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new())
|
119
|
-
|
120
|
-
group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new()
|
121
|
-
EC_GROUP_get_order(group, order, ctx)
|
122
|
-
|
123
|
-
pub_key = EC_POINT_new(group)
|
124
|
-
EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
|
125
|
-
EC_KEY_set_private_key(eckey, priv_key)
|
126
|
-
EC_KEY_set_public_key(eckey, pub_key)
|
127
|
-
|
128
|
-
signature = ECDSA_do_sign(hash, hash.bytesize, eckey)
|
129
|
-
|
130
|
-
BN_free(order)
|
131
|
-
BN_CTX_free(ctx)
|
132
|
-
EC_POINT_free(pub_key)
|
133
|
-
BN_free(priv_key)
|
134
|
-
EC_KEY_free(eckey)
|
135
|
-
|
136
|
-
buf, rec_id, head = FFI::MemoryPointer.new(:uint8, 32), nil, nil
|
137
|
-
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") }
|
138
|
-
|
139
|
-
if signature.get_array_of_pointer(0, 2).all?{|i| BN_num_bits(i) <= 256 }
|
140
|
-
4.times{|i|
|
141
|
-
head = [ Eth.v_base + i ].pack("C")
|
142
|
-
if public_key_hex == recover_public_key_from_signature(hash, [head, r, s].join, i, pubkey_compressed)
|
143
|
-
rec_id = i; break
|
144
|
-
end
|
145
|
-
}
|
146
|
-
end
|
147
|
-
|
148
|
-
ECDSA_SIG_free(signature)
|
149
|
-
|
150
|
-
[ head, [r,s] ].join if rec_id
|
151
|
-
end
|
152
|
-
|
153
|
-
def recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed)
|
154
|
-
return nil if rec_id < 0 or signature.bytesize != 65
|
155
|
-
init_ffi_ssl
|
156
|
-
|
157
|
-
signature = FFI::MemoryPointer.from_string(signature)
|
158
|
-
r = BN_bin2bn(signature[1], 32, BN_new())
|
159
|
-
s = BN_bin2bn(signature[33], 32, BN_new())
|
160
|
-
|
161
|
-
_n, i = 0, rec_id / 2
|
162
|
-
eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
|
163
|
-
|
164
|
-
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
|
165
|
-
|
166
|
-
group = EC_KEY_get0_group(eckey)
|
167
|
-
order = BN_new()
|
168
|
-
EC_GROUP_get_order(group, order, nil)
|
169
|
-
x = BN_dup(order)
|
170
|
-
BN_mul_word(x, i)
|
171
|
-
BN_add(x, x, r)
|
172
|
-
|
173
|
-
field = BN_new()
|
174
|
-
EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
|
175
|
-
|
176
|
-
if BN_cmp(x, field) >= 0
|
177
|
-
bn_free_each r, s, order, x, field
|
178
|
-
EC_KEY_free(eckey)
|
179
|
-
return nil
|
180
|
-
end
|
181
|
-
|
182
|
-
big_r = EC_POINT_new(group)
|
183
|
-
EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil)
|
184
|
-
|
185
|
-
big_q = EC_POINT_new(group)
|
186
|
-
n = EC_GROUP_get_degree(group)
|
187
|
-
e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new())
|
188
|
-
BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n
|
189
|
-
|
190
|
-
ctx = BN_CTX_new()
|
191
|
-
zero, rr, sor, eor = BN_new(), BN_new(), BN_new(), BN_new()
|
192
|
-
BN_set_word(zero, 0)
|
193
|
-
BN_mod_sub(e, zero, e, order, ctx)
|
194
|
-
BN_mod_inverse(rr, r, order, ctx)
|
195
|
-
BN_mod_mul(sor, s, rr, order, ctx)
|
196
|
-
BN_mod_mul(eor, e, rr, order, ctx)
|
197
|
-
EC_POINT_mul(group, big_q, eor, big_r, sor, ctx)
|
198
|
-
EC_KEY_set_public_key(eckey, big_q)
|
199
|
-
BN_CTX_free(ctx)
|
200
|
-
|
201
|
-
bn_free_each r, s, order, x, field, e, zero, rr, sor, eor
|
202
|
-
[big_r, big_q].each{|j| EC_POINT_free(j) }
|
203
|
-
|
204
|
-
recover_public_hex eckey
|
205
|
-
end
|
206
|
-
|
207
|
-
def recover_compact(hash, signature)
|
208
|
-
return false if signature.bytesize != 65
|
209
|
-
|
210
|
-
version = signature.unpack('C')[0]
|
211
|
-
|
212
|
-
# Version of signature should be 27 or 28, but 0 and 1 are also possible versions
|
213
|
-
# which can show up in Ledger hardwallet signings
|
214
|
-
if version < 27
|
215
|
-
version += 27
|
216
|
-
end
|
217
|
-
|
218
|
-
v_base = Eth.replayable_v?(version) ? Eth.replayable_chain_id : Eth.v_base
|
219
|
-
|
220
|
-
return false if version < v_base
|
221
|
-
|
222
|
-
recover_public_key_from_signature(hash, signature, (version - v_base), false)
|
223
|
-
end
|
224
|
-
|
225
|
-
def init_ffi_ssl
|
226
|
-
return if @ssl_loaded
|
227
|
-
if version >= VERSION_1_1_0_NUM
|
228
|
-
OPENSSL_init_ssl(
|
229
|
-
OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_ENGINE_ALL_BUILTIN,
|
230
|
-
nil
|
231
|
-
)
|
232
|
-
else
|
233
|
-
SSL_library_init()
|
234
|
-
ERR_load_crypto_strings()
|
235
|
-
SSL_load_error_strings()
|
236
|
-
end
|
237
|
-
|
238
|
-
RAND_poll()
|
239
|
-
@ssl_loaded = true
|
240
|
-
end
|
241
|
-
|
242
|
-
|
243
|
-
private
|
244
|
-
|
245
|
-
def bn_free_each(*list)
|
246
|
-
list.each{|j| BN_free(j) }
|
247
|
-
end
|
248
|
-
|
249
|
-
def recover_public_hex(eckey)
|
250
|
-
length = i2o_ECPublicKey(eckey, nil)
|
251
|
-
buf = FFI::MemoryPointer.new(:uint8, length)
|
252
|
-
ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
|
253
|
-
pub_hex = if i2o_ECPublicKey(eckey, ptr) == length
|
254
|
-
buf.read_string(length).unpack("H*")[0]
|
255
|
-
end
|
256
|
-
|
257
|
-
EC_KEY_free(eckey)
|
258
|
-
|
259
|
-
pub_hex
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
end
|
264
|
-
end
|
data/lib/eth/secp256k1.rb
DELETED
data/lib/eth/sedes.rb
DELETED
@@ -1,40 +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
|
-
|
39
|
-
end
|
40
|
-
end
|
data/lib/eth/utils.rb
DELETED
@@ -1,130 +0,0 @@
|
|
1
|
-
module Eth
|
2
|
-
module Utils
|
3
|
-
|
4
|
-
extend self
|
5
|
-
|
6
|
-
def normalize_address(address)
|
7
|
-
if address.nil? || address == ''
|
8
|
-
''
|
9
|
-
elsif address.size == 40
|
10
|
-
hex_to_bin address
|
11
|
-
elsif address.size == 42 && address[0..1] == '0x'
|
12
|
-
hex_to_bin address[2..-1]
|
13
|
-
else
|
14
|
-
address
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def bin_to_hex(string)
|
19
|
-
RLP::Utils.encode_hex string
|
20
|
-
end
|
21
|
-
|
22
|
-
def hex_to_bin(string)
|
23
|
-
RLP::Utils.decode_hex remove_hex_prefix(string)
|
24
|
-
end
|
25
|
-
|
26
|
-
def base256_to_int(str)
|
27
|
-
RLP::Sedes.big_endian_int.deserialize str.sub(/\A(\x00)+/, '')
|
28
|
-
end
|
29
|
-
|
30
|
-
def int_to_base256(int)
|
31
|
-
RLP::Sedes.big_endian_int.serialize int
|
32
|
-
end
|
33
|
-
|
34
|
-
def v_r_s_for(signature)
|
35
|
-
[
|
36
|
-
signature[0].bytes[0],
|
37
|
-
Utils.base256_to_int(signature[1..32]),
|
38
|
-
Utils.base256_to_int(signature[33..65]),
|
39
|
-
]
|
40
|
-
end
|
41
|
-
|
42
|
-
def prefix_hex(hex)
|
43
|
-
hex.match(/\A0x/) ? hex : "0x#{hex}"
|
44
|
-
end
|
45
|
-
|
46
|
-
def remove_hex_prefix(s)
|
47
|
-
s[0,2] == '0x' ? s[2..-1] : s
|
48
|
-
end
|
49
|
-
|
50
|
-
def bin_to_prefixed_hex(binary)
|
51
|
-
prefix_hex bin_to_hex(binary)
|
52
|
-
end
|
53
|
-
|
54
|
-
def prefix_message(message)
|
55
|
-
"\x19Ethereum Signed Message:\n#{message.length}#{message}"
|
56
|
-
end
|
57
|
-
|
58
|
-
def public_key_to_address(hex)
|
59
|
-
bytes = hex_to_bin(hex)
|
60
|
-
address_bytes = Utils.keccak256(bytes[1..-1])[-20..-1]
|
61
|
-
format_address bin_to_prefixed_hex(address_bytes)
|
62
|
-
end
|
63
|
-
|
64
|
-
def sha256(x)
|
65
|
-
Digest::SHA256.digest x
|
66
|
-
end
|
67
|
-
|
68
|
-
def keccak256(x)
|
69
|
-
Digest::SHA3.new(256).digest(x)
|
70
|
-
end
|
71
|
-
|
72
|
-
def keccak512(x)
|
73
|
-
Digest::SHA3.new(512).digest(x)
|
74
|
-
end
|
75
|
-
|
76
|
-
def keccak256_rlp(x)
|
77
|
-
keccak256 RLP.encode(x)
|
78
|
-
end
|
79
|
-
|
80
|
-
def ripemd160(x)
|
81
|
-
Digest::RMD160.digest x
|
82
|
-
end
|
83
|
-
|
84
|
-
def hash160(x)
|
85
|
-
ripemd160 sha256(x)
|
86
|
-
end
|
87
|
-
|
88
|
-
def zpad(x, l)
|
89
|
-
lpad x, BYTE_ZERO, l
|
90
|
-
end
|
91
|
-
|
92
|
-
def zunpad(x)
|
93
|
-
x.sub(/\A\x00+/, '')
|
94
|
-
end
|
95
|
-
|
96
|
-
def zpad_int(n, l=32)
|
97
|
-
zpad encode_int(n), l
|
98
|
-
end
|
99
|
-
|
100
|
-
def zpad_hex(s, l=32)
|
101
|
-
zpad decode_hex(s), l
|
102
|
-
end
|
103
|
-
|
104
|
-
def valid_address?(address)
|
105
|
-
Address.new(address).valid?
|
106
|
-
end
|
107
|
-
|
108
|
-
def format_address(address)
|
109
|
-
Address.new(address).checksummed
|
110
|
-
end
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
private
|
115
|
-
|
116
|
-
def lpad(x, symbol, l)
|
117
|
-
return x if x.size >= l
|
118
|
-
symbol * (l - x.size) + x
|
119
|
-
end
|
120
|
-
|
121
|
-
def encode_int(n)
|
122
|
-
unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
|
123
|
-
raise ArgumentError, "Integer invalid or out of range: #{n}"
|
124
|
-
end
|
125
|
-
|
126
|
-
int_to_base256 n
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
130
|
-
end
|