eth 0.4.16 → 0.5.1
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 +4 -4
- data/.github/workflows/codeql.yml +15 -5
- data/.github/workflows/docs.yml +26 -0
- data/.github/workflows/spec.yml +52 -0
- data/.gitignore +24 -24
- data/.gitmodules +3 -3
- data/.yardopts +1 -0
- data/AUTHORS.txt +21 -0
- data/CHANGELOG.md +65 -10
- data/Gemfile +13 -2
- data/LICENSE.txt +202 -22
- data/README.md +199 -74
- data/bin/console +4 -4
- data/bin/setup +5 -4
- data/eth.gemspec +34 -29
- data/lib/eth/abi/type.rb +178 -0
- data/lib/eth/abi.rb +396 -0
- data/lib/eth/address.rb +55 -11
- data/lib/eth/api.rb +223 -0
- data/lib/eth/chain.rb +151 -0
- data/lib/eth/client/http.rb +63 -0
- data/lib/eth/client/ipc.rb +47 -0
- data/lib/eth/client.rb +232 -0
- data/lib/eth/constant.rb +71 -0
- data/lib/eth/eip712.rb +184 -0
- data/lib/eth/key/decrypter.rb +121 -88
- data/lib/eth/key/encrypter.rb +178 -99
- data/lib/eth/key.rb +136 -48
- data/lib/eth/rlp/decoder.rb +109 -0
- data/lib/eth/rlp/encoder.rb +78 -0
- data/lib/eth/rlp/sedes/big_endian_int.rb +66 -0
- data/lib/eth/rlp/sedes/binary.rb +97 -0
- data/lib/eth/rlp/sedes/list.rb +84 -0
- data/lib/eth/rlp/sedes.rb +74 -0
- data/lib/eth/rlp.rb +63 -0
- data/lib/eth/signature.rb +163 -0
- data/lib/eth/tx/eip1559.rb +336 -0
- data/lib/eth/tx/eip2930.rb +328 -0
- data/lib/eth/tx/legacy.rb +296 -0
- data/lib/eth/tx.rb +273 -143
- data/lib/eth/unit.rb +49 -0
- data/lib/eth/util.rb +235 -0
- data/lib/eth/version.rb +18 -1
- data/lib/eth.rb +33 -67
- metadata +50 -85
- data/.github/workflows/build.yml +0 -26
- 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/key/decrypter.rb
CHANGED
@@ -1,113 +1,146 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# Provides the {Eth} module.
|
16
|
+
module Eth
|
17
|
+
|
18
|
+
# The {Eth::Key::Decrypter} class to handle PBKDF2-SHA-256 decryption.
|
19
|
+
class Key::Decrypter
|
20
|
+
|
21
|
+
# Provides a specific decrypter error if decryption fails.
|
22
|
+
class DecrypterError < StandardError; end
|
23
|
+
|
24
|
+
# Class method {Eth::Key::Decrypter.perform} to perform an keystore
|
25
|
+
# decryption.
|
26
|
+
#
|
27
|
+
# @param data [JSON] encryption data including cypherkey.
|
28
|
+
# @param password [String] password to decrypt the key.
|
29
|
+
# @return [Eth::Key] decrypted key-pair.
|
30
|
+
def self.perform(data, password)
|
31
|
+
new(data, password).perform
|
32
|
+
end
|
22
33
|
|
23
|
-
|
34
|
+
# Constructor of the {Eth::Key::Decrypter} class for secret key
|
35
|
+
# decryption. Should not be used; use {Eth::Key::Decrypter.perform}
|
36
|
+
# instead.
|
37
|
+
#
|
38
|
+
# @param data [JSON] encryption data including cypherkey.
|
39
|
+
# @param password [String] password to decrypt the key.
|
40
|
+
def initialize(data, password)
|
41
|
+
data = JSON.parse(data) if data.is_a? String
|
42
|
+
@data = data
|
43
|
+
@password = password
|
44
|
+
end
|
24
45
|
|
25
|
-
|
46
|
+
# Method to decrypt key using password.
|
47
|
+
#
|
48
|
+
# @return [Eth::Key] decrypted key.
|
49
|
+
def perform
|
50
|
+
derive_key password
|
51
|
+
check_macs
|
52
|
+
private_key = Util.bin_to_hex decrypted_data
|
53
|
+
Eth::Key.new priv: private_key
|
54
|
+
end
|
26
55
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
56
|
+
private
|
57
|
+
|
58
|
+
attr_reader :data
|
59
|
+
attr_reader :key
|
60
|
+
attr_reader :password
|
61
|
+
|
62
|
+
def derive_key(password)
|
63
|
+
case kdf
|
64
|
+
when "pbkdf2"
|
65
|
+
@key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
|
66
|
+
when "scrypt"
|
67
|
+
@key = SCrypt::Engine.scrypt(password, salt, n, r, p, key_length)
|
68
|
+
else
|
69
|
+
raise DecrypterError, "Unsupported key derivation function: #{kdf}!"
|
70
|
+
end
|
36
71
|
end
|
37
|
-
end
|
38
72
|
|
39
|
-
|
40
|
-
|
41
|
-
|
73
|
+
def check_macs
|
74
|
+
mac1 = Util.keccak256(key[(key_length / 2), key_length] + ciphertext)
|
75
|
+
mac2 = Util.hex_to_bin crypto_data["mac"]
|
42
76
|
|
43
|
-
|
44
|
-
|
77
|
+
if mac1 != mac2
|
78
|
+
raise DecrypterError, "Message Authentications Codes do not match!"
|
79
|
+
end
|
45
80
|
end
|
46
|
-
end
|
47
81
|
|
48
|
-
|
49
|
-
|
50
|
-
|
82
|
+
def decrypted_data
|
83
|
+
@decrypted_data ||= cipher.update(ciphertext) + cipher.final
|
84
|
+
end
|
51
85
|
|
52
|
-
|
53
|
-
|
54
|
-
|
86
|
+
def crypto_data
|
87
|
+
@crypto_data ||= data["crypto"] || data["Crypto"]
|
88
|
+
end
|
55
89
|
|
56
|
-
|
57
|
-
|
58
|
-
|
90
|
+
def ciphertext
|
91
|
+
Util.hex_to_bin crypto_data["ciphertext"]
|
92
|
+
end
|
59
93
|
|
60
|
-
|
61
|
-
|
62
|
-
|
94
|
+
def cipher_name
|
95
|
+
"aes-128-ctr"
|
96
|
+
end
|
63
97
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
98
|
+
def cipher
|
99
|
+
@cipher ||= OpenSSL::Cipher.new(cipher_name).tap do |cipher|
|
100
|
+
cipher.decrypt
|
101
|
+
cipher.key = key[0, (key_length / 2)]
|
102
|
+
cipher.iv = iv
|
103
|
+
end
|
69
104
|
end
|
70
|
-
end
|
71
105
|
|
72
|
-
|
73
|
-
|
74
|
-
|
106
|
+
def iv
|
107
|
+
Util.hex_to_bin crypto_data["cipherparams"]["iv"]
|
108
|
+
end
|
75
109
|
|
76
|
-
|
77
|
-
|
78
|
-
|
110
|
+
def salt
|
111
|
+
Util.hex_to_bin crypto_data["kdfparams"]["salt"]
|
112
|
+
end
|
79
113
|
|
80
|
-
|
81
|
-
|
82
|
-
|
114
|
+
def iterations
|
115
|
+
crypto_data["kdfparams"]["c"].to_i
|
116
|
+
end
|
83
117
|
|
84
|
-
|
85
|
-
|
86
|
-
|
118
|
+
def kdf
|
119
|
+
crypto_data["kdf"]
|
120
|
+
end
|
87
121
|
|
88
|
-
|
89
|
-
|
90
|
-
|
122
|
+
def key_length
|
123
|
+
crypto_data["kdfparams"]["dklen"].to_i
|
124
|
+
end
|
91
125
|
|
92
|
-
|
93
|
-
|
94
|
-
|
126
|
+
def n
|
127
|
+
crypto_data["kdfparams"]["n"].to_i
|
128
|
+
end
|
95
129
|
|
96
|
-
|
97
|
-
|
98
|
-
|
130
|
+
def r
|
131
|
+
crypto_data["kdfparams"]["r"].to_i
|
132
|
+
end
|
99
133
|
|
100
|
-
|
101
|
-
|
102
|
-
|
134
|
+
def p
|
135
|
+
crypto_data["kdfparams"]["p"].to_i
|
136
|
+
end
|
103
137
|
|
104
|
-
|
105
|
-
|
106
|
-
|
138
|
+
def digest
|
139
|
+
OpenSSL::Digest.new digest_name
|
140
|
+
end
|
107
141
|
|
108
|
-
|
109
|
-
|
142
|
+
def digest_name
|
143
|
+
"sha256"
|
144
|
+
end
|
110
145
|
end
|
111
|
-
|
112
|
-
|
113
146
|
end
|
data/lib/eth/key/encrypter.rb
CHANGED
@@ -1,128 +1,207 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# Provides the {Eth} module.
|
16
|
+
module Eth
|
17
|
+
|
18
|
+
# The {Eth::Key::Encrypter} class to handle PBKDF2-SHA-256 encryption.
|
19
|
+
class Key::Encrypter
|
20
|
+
|
21
|
+
# Provides a specific encrypter error if decryption fails.
|
22
|
+
class EncrypterError < StandardError; end
|
23
|
+
|
24
|
+
# Class method {Eth::Key::Encrypter.perform} to performa an key-store
|
25
|
+
# encryption.
|
26
|
+
#
|
27
|
+
# @param key [Eth::Key] representing a secret key-pair used for encryption.
|
28
|
+
# @param options [Hash] the options to encrypt with.
|
29
|
+
# @option options [String] :kdf key derivation function defaults to pbkdf2.
|
30
|
+
# @option options [String] :id uuid given to the secret key.
|
31
|
+
# @option options [String] :iterations number of iterations for the hash function.
|
32
|
+
# @option options [String] :salt passed to PBKDF.
|
33
|
+
# @option options [String] :iv 128-bit initialisation vector for the cipher.
|
34
|
+
# @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8.
|
35
|
+
# @option options [Integer] :block_size for scrypt, defaults to 1.
|
36
|
+
# @return [JSON] formatted with encrypted key (cyphertext) and [other identifying data](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition#pbkdf2-sha-256).
|
37
|
+
def self.perform(key, password, options = {})
|
38
|
+
new(key, options).perform(password)
|
39
|
+
end
|
15
40
|
|
16
|
-
|
17
|
-
|
18
|
-
|
41
|
+
# Constructor of the {Eth::Key::Encrypter} class for secret key
|
42
|
+
# encryption. Should not be used; use {Eth::Key::Encrypter.perform}
|
43
|
+
# instead.
|
44
|
+
#
|
45
|
+
# @param key [Eth::Key] representing a secret key-pair used for encryption.
|
46
|
+
# @param options [Hash] the options to encrypt with.
|
47
|
+
# @option options [String] :kdf key derivation function defaults to pbkdf2.
|
48
|
+
# @option options [String] :id uuid given to the secret key.
|
49
|
+
# @option options [String] :iterations number of iterations for the hash function.
|
50
|
+
# @option options [String] :salt passed to PBKDF.
|
51
|
+
# @option options [String] :iv 128-bit initialisation vector for the cipher.
|
52
|
+
# @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8.
|
53
|
+
# @option options [Integer] :block_size for scrypt, defaults to 1.
|
54
|
+
def initialize(key, options = {})
|
55
|
+
key = Key.new(priv: key) if key.is_a? String
|
56
|
+
@key = key
|
57
|
+
@options = options
|
58
|
+
|
59
|
+
# the key derivation functions default to pbkdf2 if no option is specified
|
60
|
+
# however, if an option is given then it must be either pbkdf2 or scrypt
|
61
|
+
if kdf != "scrypt" && kdf != "pbkdf2"
|
62
|
+
raise EncrypterError, "Unsupported key derivation function: #{kdf}!"
|
63
|
+
end
|
64
|
+
end
|
19
65
|
|
20
|
-
|
21
|
-
|
66
|
+
# Encrypt the key with a given password.
|
67
|
+
#
|
68
|
+
# @param password [String] a secret key used for encryption
|
69
|
+
# @return [String] a JSON-formatted keystore string.
|
70
|
+
def perform(password)
|
71
|
+
derive_key password
|
72
|
+
encrypt
|
73
|
+
data.to_json
|
74
|
+
end
|
22
75
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
76
|
+
# Output containing the encrypted key and
|
77
|
+
# [other identifying data](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition#pbkdf2-sha-256)
|
78
|
+
#
|
79
|
+
# @return [Hash] the encrypted keystore data.
|
80
|
+
def data
|
81
|
+
# default to pbkdf2
|
82
|
+
kdfparams = if kdf == "scrypt"
|
83
|
+
{
|
84
|
+
dklen: 32,
|
85
|
+
n: iterations,
|
86
|
+
p: parallelization,
|
87
|
+
r: block_size,
|
88
|
+
salt: Util.bin_to_hex(salt),
|
89
|
+
}
|
90
|
+
else
|
91
|
+
{
|
92
|
+
c: iterations,
|
93
|
+
dklen: 32,
|
94
|
+
prf: prf,
|
95
|
+
salt: Util.bin_to_hex(salt),
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
{
|
100
|
+
crypto: {
|
101
|
+
cipher: cipher_name,
|
102
|
+
cipherparams: {
|
103
|
+
iv: Util.bin_to_hex(iv),
|
104
|
+
},
|
105
|
+
ciphertext: Util.bin_to_hex(encrypted_key),
|
106
|
+
kdf: kdf,
|
107
|
+
kdfparams: kdfparams,
|
108
|
+
mac: Util.bin_to_hex(mac),
|
29
109
|
},
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
c: iterations,
|
34
|
-
dklen: 32,
|
35
|
-
prf: prf,
|
36
|
-
salt: bin_to_hex(salt),
|
37
|
-
},
|
38
|
-
mac: bin_to_hex(mac),
|
39
|
-
},
|
40
|
-
id: id,
|
41
|
-
version: 3,
|
42
|
-
}.tap do |data|
|
43
|
-
data[:address] = address unless options[:skip_address]
|
110
|
+
id: id,
|
111
|
+
version: 3,
|
112
|
+
}
|
44
113
|
end
|
45
|
-
end
|
46
114
|
|
47
|
-
|
48
|
-
@id ||= options[:id] || SecureRandom.uuid
|
49
|
-
end
|
115
|
+
private
|
50
116
|
|
117
|
+
attr_reader :derived_key, :encrypted_key, :key, :options
|
51
118
|
|
52
|
-
|
119
|
+
def cipher
|
120
|
+
@cipher ||= OpenSSL::Cipher.new(cipher_name).tap do |cipher|
|
121
|
+
cipher.encrypt
|
122
|
+
cipher.iv = iv
|
123
|
+
cipher.key = derived_key[0, (key_length / 2)]
|
124
|
+
end
|
125
|
+
end
|
53
126
|
|
54
|
-
|
127
|
+
def digest
|
128
|
+
@digest ||= OpenSSL::Digest.new digest_name
|
129
|
+
end
|
55
130
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
131
|
+
def derive_key(password)
|
132
|
+
if kdf == "scrypt"
|
133
|
+
@derived_key = SCrypt::Engine.scrypt(password, salt, iterations, block_size, parallelization, key_length)
|
134
|
+
else
|
135
|
+
@derived_key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
|
136
|
+
end
|
61
137
|
end
|
62
|
-
end
|
63
138
|
|
64
|
-
|
65
|
-
|
66
|
-
|
139
|
+
def encrypt
|
140
|
+
@encrypted_key = cipher.update(Util.hex_to_bin key.private_hex) + cipher.final
|
141
|
+
end
|
67
142
|
|
68
|
-
|
69
|
-
|
70
|
-
|
143
|
+
def mac
|
144
|
+
Util.keccak256(derived_key[(key_length / 2), key_length] + encrypted_key)
|
145
|
+
end
|
71
146
|
|
72
|
-
|
73
|
-
|
74
|
-
|
147
|
+
def kdf
|
148
|
+
options[:kdf] || "pbkdf2"
|
149
|
+
end
|
75
150
|
|
76
|
-
|
77
|
-
|
78
|
-
|
151
|
+
def cipher_name
|
152
|
+
"aes-128-ctr"
|
153
|
+
end
|
79
154
|
|
80
|
-
|
81
|
-
|
82
|
-
|
155
|
+
def digest_name
|
156
|
+
"sha256"
|
157
|
+
end
|
83
158
|
|
84
|
-
|
85
|
-
|
86
|
-
|
159
|
+
def prf
|
160
|
+
"hmac-#{digest_name}"
|
161
|
+
end
|
87
162
|
|
88
|
-
|
89
|
-
|
90
|
-
|
163
|
+
def key_length
|
164
|
+
32
|
165
|
+
end
|
91
166
|
|
92
|
-
|
93
|
-
|
94
|
-
|
167
|
+
def salt_length
|
168
|
+
32
|
169
|
+
end
|
95
170
|
|
96
|
-
|
97
|
-
|
98
|
-
|
171
|
+
def iv_length
|
172
|
+
16
|
173
|
+
end
|
99
174
|
|
100
|
-
|
101
|
-
|
102
|
-
|
175
|
+
def id
|
176
|
+
@id ||= options[:id] || SecureRandom.uuid
|
177
|
+
end
|
103
178
|
|
104
|
-
|
105
|
-
|
106
|
-
|
179
|
+
def iterations
|
180
|
+
options[:iterations] || 262_144
|
181
|
+
end
|
107
182
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
183
|
+
def salt
|
184
|
+
@salt ||= if options[:salt]
|
185
|
+
Util.hex_to_bin options[:salt]
|
186
|
+
else
|
187
|
+
SecureRandom.random_bytes(salt_length)
|
188
|
+
end
|
113
189
|
end
|
114
|
-
end
|
115
190
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
191
|
+
def iv
|
192
|
+
@iv ||= if options[:iv]
|
193
|
+
Util.hex_to_bin options[:iv]
|
194
|
+
else
|
195
|
+
SecureRandom.random_bytes(iv_length)
|
196
|
+
end
|
121
197
|
end
|
122
|
-
end
|
123
198
|
|
124
|
-
|
125
|
-
|
126
|
-
|
199
|
+
def parallelization
|
200
|
+
options[:parallelization] || 8
|
201
|
+
end
|
127
202
|
|
203
|
+
def block_size
|
204
|
+
options[:block_size] || 1
|
205
|
+
end
|
206
|
+
end
|
128
207
|
end
|