eth-patched 0.4.13

Sign up to get free protection for your applications and to get access to all the features.
data/lib/eth/key.rb ADDED
@@ -0,0 +1,79 @@
1
+ module Eth
2
+ class Key
3
+ autoload :Decrypter, 'eth/key/decrypter'
4
+ autoload :Encrypter, 'eth/key/encrypter'
5
+
6
+ attr_reader :private_key, :public_key
7
+
8
+ def self.encrypt(key, password)
9
+ key = new(priv: key) unless key.is_a?(Key)
10
+
11
+ Encrypter.perform key.private_hex, password
12
+ end
13
+
14
+ def self.decrypt(data, password)
15
+ priv = Decrypter.perform data, password
16
+ new priv: priv
17
+ end
18
+
19
+ def self.personal_recover(message, signature)
20
+ bin_signature = Utils.hex_to_bin(signature).bytes.rotate(-1).pack('c*')
21
+ OpenSsl.recover_compact(Utils.keccak256(Utils.prefix_message(message)), bin_signature)
22
+ end
23
+
24
+ def initialize(priv: nil)
25
+ @private_key = MoneyTree::PrivateKey.new key: priv
26
+ @public_key = MoneyTree::PublicKey.new private_key, compressed: false
27
+ end
28
+
29
+ def private_hex
30
+ private_key.to_hex
31
+ end
32
+
33
+ def public_bytes
34
+ public_key.to_bytes
35
+ end
36
+
37
+ def public_hex
38
+ public_key.to_hex
39
+ end
40
+
41
+ def address
42
+ Utils.public_key_to_address public_hex
43
+ end
44
+ alias_method :to_address, :address
45
+
46
+ def sign(message)
47
+ sign_hash message_hash(message)
48
+ end
49
+
50
+ def sign_hash(hash)
51
+ loop do
52
+ signature = OpenSsl.sign_compact hash, private_hex, public_hex
53
+ return signature if valid_s? signature
54
+ end
55
+ end
56
+
57
+ def verify_signature(message, signature)
58
+ hash = message_hash(message)
59
+ public_hex == OpenSsl.recover_compact(hash, signature)
60
+ end
61
+
62
+ def personal_sign(message)
63
+ Utils.bin_to_hex(sign(Utils.prefix_message(message)).bytes.rotate(1).pack('c*'))
64
+ end
65
+
66
+
67
+ private
68
+
69
+ def message_hash(message)
70
+ Utils.keccak256 message
71
+ end
72
+
73
+ def valid_s?(signature)
74
+ s_value = Utils.v_r_s_for(signature).last
75
+ s_value <= Secp256k1::N/2 && s_value != 0
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,264 @@
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
@@ -0,0 +1,7 @@
1
+ module Eth
2
+ class Secp256k1
3
+
4
+ N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
5
+
6
+ end
7
+ end
data/lib/eth/sedes.rb ADDED
@@ -0,0 +1,40 @@
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/tx.rb ADDED
@@ -0,0 +1,197 @@
1
+ module Eth
2
+ class Tx
3
+
4
+ include RLP::Sedes::Serializable
5
+ extend Sedes
6
+
7
+ set_serializable_fields({
8
+ nonce: big_endian_int,
9
+ gas_price: big_endian_int,
10
+ gas_limit: big_endian_int,
11
+ to: address,
12
+ value: big_endian_int,
13
+ data_bin: binary,
14
+ v: big_endian_int,
15
+ r: big_endian_int,
16
+ s: big_endian_int
17
+ })
18
+
19
+ attr_writer :signature
20
+
21
+ def self.decode(data)
22
+ data = Utils.hex_to_bin(data) if data.match(/\A(?:0x)?\h+\Z/)
23
+ txh = deserialize(RLP.decode data).to_h
24
+
25
+ txh[:chain_id] = Eth.chain_id_from_signature(txh)
26
+
27
+ self.new txh
28
+ end
29
+
30
+ def initialize(params)
31
+ fields = {v: 0, r: 0, s: 0}.merge params
32
+ fields[:to] = Utils.normalize_address(fields[:to])
33
+
34
+ self.chain_id = (params[:chain_id]) ? params.delete(:chain_id) : Eth.chain_id
35
+
36
+ if params[:data]
37
+ self.data = params.delete(:data)
38
+ fields[:data_bin] = data_bin
39
+ end
40
+ serializable_initialize fields
41
+
42
+ check_transaction_validity
43
+ end
44
+
45
+ def unsigned_encoded
46
+ us = unsigned
47
+ RLP.encode(us, sedes: us.sedes)
48
+ end
49
+
50
+ def signing_data
51
+ Utils.bin_to_prefixed_hex unsigned_encoded
52
+ end
53
+
54
+ def encoded
55
+ RLP.encode self
56
+ end
57
+
58
+ def hex
59
+ Utils.bin_to_prefixed_hex encoded
60
+ end
61
+
62
+ def sign(key)
63
+ sig = key.sign(unsigned_encoded)
64
+ vrs = Utils.v_r_s_for sig
65
+ self.v = (self.chain_id) ? ((self.chain_id * 2) + vrs[0] + 8) : vrs[0]
66
+ self.r = vrs[1]
67
+ self.s = vrs[2]
68
+
69
+ clear_signature
70
+ self
71
+ end
72
+
73
+ def to_h
74
+ hash_keys.inject({}) do |hash, field|
75
+ hash[field] = send field
76
+ hash
77
+ end
78
+ end
79
+
80
+ def from
81
+ if ecdsa_signature
82
+ public_key = OpenSsl.recover_compact(signature_hash, ecdsa_signature)
83
+ Utils.public_key_to_address(public_key) if public_key
84
+ end
85
+ end
86
+
87
+ def signature
88
+ return @signature if @signature
89
+ @signature = { v: v, r: r, s: s } if [v, r, s].all? && (v > 0)
90
+ end
91
+
92
+ def ecdsa_signature
93
+ return @ecdsa_signature if @ecdsa_signature
94
+
95
+ if [v, r, s].all? && (v > 0)
96
+ s_v = (self.chain_id) ? (v - (self.chain_id * 2) - 8) : v
97
+ @ecdsa_signature = [
98
+ Utils.int_to_base256(s_v),
99
+ Utils.zpad_int(r),
100
+ Utils.zpad_int(s),
101
+ ].join
102
+ end
103
+ end
104
+
105
+ def hash
106
+ "0x#{Utils.bin_to_hex Utils.keccak256_rlp(self)}"
107
+ end
108
+ alias_method :id, :hash
109
+
110
+ def data_hex
111
+ Utils.bin_to_prefixed_hex data_bin
112
+ end
113
+
114
+ def data_hex=(hex)
115
+ self.data_bin = Utils.hex_to_bin(hex)
116
+ end
117
+
118
+ def data
119
+ Eth.tx_data_hex? ? data_hex : data_bin
120
+ end
121
+
122
+ def data=(string)
123
+ Eth.tx_data_hex? ? self.data_hex=(string) : self.data_bin=(string)
124
+ end
125
+
126
+ def chain_id
127
+ @chain_id
128
+ end
129
+
130
+ def chain_id=(cid)
131
+ if cid != @chain_id
132
+ self.v = 0
133
+ self.r = 0
134
+ self.s = 0
135
+
136
+ clear_signature
137
+ end
138
+
139
+ @chain_id = (cid == 0) ? nil : cid
140
+ end
141
+
142
+ def prevent_replays?
143
+ !self.chain_id.nil?
144
+ end
145
+
146
+ private
147
+
148
+ def clear_signature
149
+ @signature = nil
150
+ @ecdsa_signature = nil
151
+ end
152
+
153
+ def hash_keys
154
+ keys = self.class.serializable_fields.keys
155
+ keys.delete(:data_bin)
156
+ keys + [:data, :chain_id]
157
+ end
158
+
159
+ def check_transaction_validity
160
+ if [gas_price, gas_limit, value, nonce].max > UINT_MAX
161
+ raise InvalidTransaction, "Values way too high!"
162
+ elsif gas_limit < intrinsic_gas_used
163
+ raise InvalidTransaction, "Gas limit too low"
164
+ end
165
+ end
166
+
167
+ def intrinsic_gas_used
168
+ num_zero_bytes = data_bin.count(BYTE_ZERO)
169
+ num_non_zero_bytes = data_bin.size - num_zero_bytes
170
+
171
+ Gas::GTXCOST +
172
+ Gas::GTXDATAZERO * num_zero_bytes +
173
+ Gas::GTXDATANONZERO * num_non_zero_bytes
174
+ end
175
+
176
+ def signature_hash
177
+ Utils.keccak256 unsigned_encoded
178
+ end
179
+
180
+ def unsigned
181
+ Tx.new to_h.merge(v: (self.chain_id) ? self.chain_id : 0, r: 0, s: 0)
182
+ end
183
+
184
+ protected
185
+
186
+ def sedes
187
+ if self.prevent_replays? && !(Eth.replayable_v? v)
188
+ self.class
189
+ else
190
+ UnsignedTx
191
+ end
192
+ end
193
+
194
+ end
195
+
196
+ UnsignedTx = Tx.exclude([:v, :r, :s])
197
+ end
data/lib/eth/utils.rb ADDED
@@ -0,0 +1,130 @@
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