digix-eth 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,26 @@
1
+ module Eth
2
+ class RpcSigner
3
+
4
+ attr_accessor :key
5
+
6
+ def initialize(key)
7
+ @key = key
8
+ end
9
+
10
+ def sign_message(message)
11
+ payload = Eth::Signature.new(message)
12
+ payload.prefixed_message = Eth::Utils.prefix_message(message)
13
+ payload.hash = Eth::Utils.keccak256(payload.prefixed_message)
14
+ payload.hash_hex = Eth::Utils.bin_to_prefixed_hex(payload.hash)
15
+ payload.signature = @key.sign(payload.prefixed_message)
16
+ payload.signature_hex = Eth::Utils.bin_to_prefixed_hex(payload.signature)
17
+ payload.v, payload.r, payload.s = Eth::Utils.v_r_s_for(payload.signature)
18
+ payload.rpc = Eth::Utils.zpad_int(payload.r, 32) + Eth::Utils.zpad_int(payload.s, 32) + [(payload.v - 27)].pack('C')
19
+ payload.rpc_hex = Eth::Utils.bin_to_prefixed_hex(payload.rpc)
20
+ return payload
21
+ end
22
+
23
+ end
24
+
25
+
26
+ end
@@ -0,0 +1,7 @@
1
+ module Eth
2
+ class Secp256k1
3
+
4
+ N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
5
+
6
+ end
7
+ end
@@ -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
@@ -0,0 +1,11 @@
1
+ module Eth
2
+ class Signature
3
+
4
+ attr_accessor :message, :signer, :prefixed_message, :hash, :hash_hex, :signature, :signature_hex, :rpc, :rpc_hex, :v, :r, :s
5
+
6
+ def initialize(message)
7
+ @message = message
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,154 @@
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
+ deserialize(RLP.decode data)
24
+ end
25
+
26
+ def initialize(params)
27
+ fields = {v: 0, r: 0, s: 0}.merge params
28
+ fields[:to] = Utils.normalize_address(fields[:to])
29
+
30
+ if params[:data]
31
+ self.data = params.delete(:data)
32
+ fields[:data_bin] = data_bin
33
+ end
34
+ serializable_initialize fields
35
+
36
+ check_transaction_validity
37
+ end
38
+
39
+ def unsigned_encoded
40
+ RLP.encode(unsigned, sedes: sedes)
41
+ end
42
+
43
+ def signing_data
44
+ Utils.bin_to_prefixed_hex unsigned_encoded
45
+ end
46
+
47
+ def encoded
48
+ RLP.encode self
49
+ end
50
+
51
+ def hex
52
+ Utils.bin_to_prefixed_hex encoded
53
+ end
54
+
55
+ def sign(key)
56
+ self.signature = key.sign(unsigned_encoded)
57
+ vrs = Utils.v_r_s_for signature
58
+ self.v = vrs[0]
59
+ self.r = vrs[1]
60
+ self.s = vrs[2]
61
+
62
+ self
63
+ end
64
+
65
+ def to_h
66
+ hash_keys.inject({}) do |hash, field|
67
+ hash[field] = send field
68
+ hash
69
+ end
70
+ end
71
+
72
+ def from
73
+ if signature
74
+ public_key = OpenSsl.recover_compact(signature_hash, signature)
75
+ Utils.public_key_to_address(public_key) if public_key
76
+ end
77
+ end
78
+
79
+ def signature
80
+ return @signature if @signature
81
+ self.signature = [
82
+ Utils.int_to_base256(v),
83
+ Utils.zpad_int(r),
84
+ Utils.zpad_int(s),
85
+ ].join if [v, r, s].all?
86
+ end
87
+
88
+ def hash
89
+ "0x#{Utils.bin_to_hex Utils.keccak256_rlp(self)}"
90
+ end
91
+ alias_method :id, :hash
92
+
93
+ def data_hex
94
+ Utils.bin_to_prefixed_hex data_bin
95
+ end
96
+
97
+ def data_hex=(hex)
98
+ self.data_bin = Utils.hex_to_bin(hex)
99
+ end
100
+
101
+ def data
102
+ Eth.tx_data_hex? ? data_hex : data_bin
103
+ end
104
+
105
+ def data=(string)
106
+ Eth.tx_data_hex? ? self.data_hex=(string) : self.data_bin=(string)
107
+ end
108
+
109
+
110
+ private
111
+
112
+ def hash_keys
113
+ keys = self.class.serializable_fields.keys
114
+ keys.delete(:data_bin)
115
+ keys + [:data]
116
+ end
117
+
118
+ def check_transaction_validity
119
+ if [gas_price, gas_limit, value, nonce].max > UINT_MAX
120
+ raise InvalidTransaction, "Values way too high!"
121
+ elsif gas_limit < intrinsic_gas_used
122
+ raise InvalidTransaction, "Gas limit too low"
123
+ end
124
+ end
125
+
126
+ def intrinsic_gas_used
127
+ num_zero_bytes = data_bin.count(BYTE_ZERO)
128
+ num_non_zero_bytes = data_bin.size - num_zero_bytes
129
+
130
+ Gas::GTXCOST +
131
+ Gas::GTXDATAZERO * num_zero_bytes +
132
+ Gas::GTXDATANONZERO * num_non_zero_bytes
133
+ end
134
+
135
+ def signature_hash
136
+ Utils.keccak256 unsigned_encoded
137
+ end
138
+
139
+ def unsigned
140
+ Tx.new to_h.merge(v: Eth.chain_id, r: 0, s: 0)
141
+ end
142
+
143
+ def sedes
144
+ if Eth.prevent_replays? && !(Eth.replayable_v? v)
145
+ self.class
146
+ else
147
+ UnsignedTx
148
+ end
149
+ end
150
+
151
+ end
152
+
153
+ UnsignedTx = Tx.exclude([:v, :r, :s])
154
+ end
@@ -0,0 +1,147 @@
1
+ module Eth
2
+ module Utils
3
+
4
+ extend self
5
+
6
+ def prefix_message(message)
7
+ prefix = "\u0019Ethereum Signed Message:\n#{message.length}"
8
+ return "#{prefix}#{message}"
9
+ end
10
+
11
+
12
+ def normalize_address(address)
13
+ if address.nil? || address == ''
14
+ ''
15
+ elsif address.size == 40
16
+ hex_to_bin address
17
+ elsif address.size == 42 && address[0..1] == '0x'
18
+ hex_to_bin address[2..-1]
19
+ else
20
+ address
21
+ end
22
+ end
23
+
24
+ def bin_to_hex(string)
25
+ RLP::Utils.encode_hex string
26
+ end
27
+
28
+ def hex_to_bin(string)
29
+ RLP::Utils.decode_hex remove_hex_prefix(string)
30
+ end
31
+
32
+ def base256_to_int(str)
33
+ RLP::Sedes.big_endian_int.deserialize str.sub(/\A(\x00)+/, '')
34
+ end
35
+
36
+ def int_to_base256(int)
37
+ RLP::Sedes.big_endian_int.serialize int
38
+ end
39
+
40
+ def from_rpc_signature_hex(signature)
41
+ buffer = Eth::Utils.hex_to_bin(signature).bytes
42
+ if buffer.length != 65
43
+ raise ArgumentError.new('Invalid signature length')
44
+ end
45
+ v = buffer[64]
46
+ v += 27 if v < 27
47
+ r = buffer[0..32]
48
+ s = buffer[33..64]
49
+ signature = [v, r, s].flatten.pack('C*')
50
+ signature_hex = Eth::Util.bin_to_prefixed_hex(signature)
51
+ payload = {v: v, r: r, s: s, signature: signature, signature_hex: signature_hex}
52
+ return payload
53
+ end
54
+
55
+ def v_r_s_for(signature)
56
+ [
57
+ signature[0].bytes[0],
58
+ Utils.base256_to_int(signature[1..32]),
59
+ Utils.base256_to_int(signature[33..65]),
60
+ ]
61
+ end
62
+
63
+ def prefix_hex(hex)
64
+ hex.match(/\A0x/) ? hex : "0x#{hex}"
65
+ end
66
+
67
+ def remove_hex_prefix(s)
68
+ s[0,2] == '0x' ? s[2..-1] : s
69
+ end
70
+
71
+ def bin_to_prefixed_hex(binary)
72
+ prefix_hex bin_to_hex(binary)
73
+ end
74
+
75
+ def public_key_to_address(hex)
76
+ bytes = hex_to_bin(hex)
77
+ address_bytes = Utils.keccak256(bytes[1..-1])[-20..-1]
78
+ format_address bin_to_prefixed_hex(address_bytes)
79
+ end
80
+
81
+ def sha256(x)
82
+ Digest::SHA256.digest x
83
+ end
84
+
85
+ def keccak256(x)
86
+ Digest::SHA3.new(256).digest(x)
87
+ end
88
+
89
+ def keccak512(x)
90
+ Digest::SHA3.new(512).digest(x)
91
+ end
92
+
93
+ def keccak256_rlp(x)
94
+ keccak256 RLP.encode(x)
95
+ end
96
+
97
+ def ripemd160(x)
98
+ Digest::RMD160.digest x
99
+ end
100
+
101
+ def hash160(x)
102
+ ripemd160 sha256(x)
103
+ end
104
+
105
+ def zpad(x, l)
106
+ lpad x, BYTE_ZERO, l
107
+ end
108
+
109
+ def zunpad(x)
110
+ x.sub(/\A\x00+/, '')
111
+ end
112
+
113
+ def zpad_int(n, l=32)
114
+ zpad encode_int(n), l
115
+ end
116
+
117
+ def zpad_hex(s, l=32)
118
+ zpad decode_hex(s), l
119
+ end
120
+
121
+ def valid_address?(address)
122
+ Address.new(address).valid?
123
+ end
124
+
125
+ def format_address(address)
126
+ Address.new(address).checksummed
127
+ end
128
+
129
+
130
+
131
+ private
132
+
133
+ def lpad(x, symbol, l)
134
+ return x if x.size >= l
135
+ symbol * (l - x.size) + x
136
+ end
137
+
138
+ def encode_int(n)
139
+ unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
140
+ raise ArgumentError, "Integer invalid or out of range: #{n}"
141
+ end
142
+
143
+ int_to_base256 n
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,45 @@
1
+ module Eth
2
+ class Vault
3
+
4
+ attr_accessor :hd_path_string, :master, :mnemonic
5
+
6
+ class << self
7
+
8
+ def pad_mnemonic(mnemonic)
9
+ mnemonic.rjust(180, ' ')
10
+ end
11
+
12
+ def unpad_mnemonic(mnemonic)
13
+ mnemonic.strip!
14
+ end
15
+ end
16
+
17
+ def initialize(opts = {secret_seed_phrase: nil}, hd_path_string = "m/0'/0'/0'")
18
+ if opts[:secret_seed_phrase]
19
+ secret_seed_phrase = self.class.pad_mnemonic(opts[:secret_seed_phrase])
20
+ seed_hex = Bitcoin::Trezor::Mnemonic.to_seed(secret_seed_phrase)
21
+ else
22
+ secret_seed_phrase = self.class.pad_mnemonic(Bitcoin::Trezor::Mnemonic.to_mnemonic(RbNaCl::Random.random_bytes(32)))
23
+ seed_hex = Bitcoin::Trezor::Mnemonic.to_seed(secret_seed_phrase)
24
+ end
25
+ @mnemonic = self.class.unpad_mnemonic(secret_seed_phrase)
26
+ @hd_path_string = hd_path_string
27
+ @master = MoneyTree::Master.new(seed_hex: seed_hex)
28
+ end
29
+
30
+ def get_node(index = 0)
31
+ if index == 0
32
+ hd_path = @hd_path_string
33
+ else
34
+ hd_path = "#{@hd_path_string}/#{index}'"
35
+ end
36
+ return @master.node_for_path(hd_path)
37
+ end
38
+
39
+ def get_key(index = 0)
40
+ node = get_node(index)
41
+ return Eth::Key.from_node(node)
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module Eth
2
+ VERSION = "0.5.2"
3
+ end
metadata ADDED
@@ -0,0 +1,229 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: digix-eth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.2
5
+ platform: ruby
6
+ authors:
7
+ - Steve Ellis
8
+ - DigixGlobal
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2017-07-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: digest-sha3
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.1'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: ffi
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: money-tree
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '0.9'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0.9'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rlp
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 0.7.3
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 0.7.3
70
+ - !ruby/object:Gem::Dependency
71
+ name: activesupport
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '5.1'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '5.1'
84
+ - !ruby/object:Gem::Dependency
85
+ name: bitcoin-ruby
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '='
89
+ - !ruby/object:Gem::Version
90
+ version: 0.0.11
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '='
96
+ - !ruby/object:Gem::Version
97
+ version: 0.0.11
98
+ - !ruby/object:Gem::Dependency
99
+ name: rbnacl
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '5.0'
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '5.0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: bundler
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '1.12'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '1.12'
126
+ - !ruby/object:Gem::Dependency
127
+ name: pry
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: '0.1'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '0.1'
140
+ - !ruby/object:Gem::Dependency
141
+ name: rake
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - "~>"
145
+ - !ruby/object:Gem::Version
146
+ version: '10.0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '10.0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: rspec
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '3.0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: '3.0'
168
+ description: 'Forked from: github.com/se3000/ruby-eth. Library to build, parse, and
169
+ sign Ethereum transactions. This forked gem adds additional support for Trezor style
170
+ mnemonic and RPC signing'
171
+ email:
172
+ - email@steveell.is
173
+ - support@digix.io
174
+ executables: []
175
+ extensions: []
176
+ extra_rdoc_files: []
177
+ files:
178
+ - ".gitignore"
179
+ - ".gitmodules"
180
+ - ".rspec"
181
+ - ".travis.yml"
182
+ - CHANGELOG.md
183
+ - Gemfile
184
+ - LICENSE.txt
185
+ - README.md
186
+ - Rakefile
187
+ - bin/console
188
+ - bin/setup
189
+ - eth.gemspec
190
+ - lib/eth.rb
191
+ - lib/eth/address.rb
192
+ - lib/eth/gas.rb
193
+ - lib/eth/key.rb
194
+ - lib/eth/key/decrypter.rb
195
+ - lib/eth/key/encrypter.rb
196
+ - lib/eth/open_ssl.rb
197
+ - lib/eth/rpc_signer.rb
198
+ - lib/eth/secp256k1.rb
199
+ - lib/eth/sedes.rb
200
+ - lib/eth/signature.rb
201
+ - lib/eth/tx.rb
202
+ - lib/eth/utils.rb
203
+ - lib/eth/vault.rb
204
+ - lib/eth/version.rb
205
+ homepage: https://github.com/digixglobal/ruby-eth
206
+ licenses:
207
+ - MIT
208
+ metadata: {}
209
+ post_install_message:
210
+ rdoc_options: []
211
+ require_paths:
212
+ - lib
213
+ required_ruby_version: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ required_rubygems_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ requirements: []
224
+ rubyforge_project:
225
+ rubygems_version: 2.6.12
226
+ signing_key:
227
+ specification_version: 4
228
+ summary: Simple API to sign Ethereum transactions.
229
+ test_files: []