eth 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1e66df112e63648f3f2d9c0aaeda96f69d0d080e
4
+ data.tar.gz: 592b07bd1c4de2d7d0ca45fcdd9af89dcd016352
5
+ SHA512:
6
+ metadata.gz: 79b7fde0612955430559fdb38087ebd04bb9eab172250ea90a20d00e927b8b3ade6b1f34c8dff979564a72db5f2532ec96e427ba6e9c116d0d7c6d9e6ee9ee4e
7
+ data.tar.gz: ba31aabf2af13fb361eaeae8c145954f8a7fe45587ca823ab8fafb3ea9779fd05b2ab7defdc847cd1960c028d4f97115f04b01f3111ea749bc0925df47706778
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --require pry
2
+ --require spec_helper
3
+ --format documentation
4
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.12.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ethereum-tx.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Steve Ellis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,66 @@
1
+ # Ethereum::Tx
2
+
3
+ A simple, light weight, library to build and sign Ethereum transactions.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'ethereum-tx'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install ethereum-tx
20
+
21
+ ## Usage
22
+
23
+ ### Keys
24
+ Create a new key:
25
+ ```
26
+ key = Ethereum::Key.new
27
+ ```
28
+ Or import and existing one:
29
+ ```
30
+ old_key = Ethereum::Key.new private_key
31
+ ```
32
+
33
+ ### Transactions
34
+
35
+ Build a transaction from scratch:
36
+ ```
37
+ tx = Ethereum::Tx.new to: key.address, gas_price: 25_000, gas_limit: 25_000
38
+ tx.data = 'abcdef' #optional
39
+ tx.value = 1_000_000_000_000 #optional
40
+ ```
41
+ Or decode an encoded raw transaction:
42
+ ```
43
+ tx = Ethereum::Tx.decode hex
44
+ ```
45
+
46
+ Then sign the transaction:
47
+ ```
48
+ tx.sign key
49
+ ```
50
+ Finally you can broadcast the raw transaction, `tx.encoded`, to your Ethereum node.
51
+
52
+
53
+ ## Contributing
54
+
55
+ Bug reports and pull requests are welcome on GitHub at https://github.com/se3000/ethereum-tx.
56
+
57
+
58
+ ## License
59
+
60
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
61
+
62
+ ## TODO
63
+ - Better test suite.
64
+ - Expose API for HD keys.
65
+ - Separate out code pulled from [bitcoin-ruby](https://github.com/lian/bitcoin-ruby) and [ruby-ethereum](github.com/janx/ruby-ethereum) into their own gems to eliminate duplication.
66
+ - Support signing with [libsecp256k1](https://github.com/bitcoin-core/secp256k1).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ethereum-tx"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ require "pry"
10
+ Pry.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'eth/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "eth"
8
+ spec.version = Eth::VERSION
9
+ spec.authors = ["Steve Ellis"]
10
+ spec.email = ["email@steveell.is"]
11
+
12
+ spec.summary = %q{Simple API to sign Ethereum transactions.}
13
+ spec.description = %q{Library to build, parse, and sign Ethereum transactions.}
14
+ spec.homepage = "https://github.com/se3000/ruby-eth"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "digest-sha3", "~> 1.1"
23
+ spec.add_dependency "ethereum-base", "0.1.2"
24
+ spec.add_dependency "ffi", "~> 1.0"
25
+ spec.add_dependency "money-tree", "~> 0.9"
26
+ spec.add_dependency "rlp", "~> 0.7"
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.12"
29
+ spec.add_development_dependency "pry", "~> 0.1"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rspec", "~> 3.0"
32
+ end
@@ -0,0 +1,25 @@
1
+ require 'digest/sha3'
2
+ require 'ethereum/base'
3
+ require 'ffi'
4
+ require 'money-tree'
5
+ require 'rlp'
6
+
7
+ module Eth
8
+
9
+ BYTE_ZERO = "\x00".freeze
10
+ GTXCOST = 21000 # TX BASE GAS COST
11
+ GTXDATANONZERO = 68 # TX DATA NON ZERO BYTE GAS COST
12
+ GTXDATAZERO = 4 # TX DATA ZERO BYTE GAS COST
13
+ SECP256K1_N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
14
+ UINT_MAX = 2**256 - 1
15
+
16
+ autoload :Key, 'eth/key'
17
+ autoload :OpenSsl, 'eth/open_ssl'
18
+ autoload :Sedes, 'eth/sedes'
19
+ autoload :Tx, 'eth/tx'
20
+ autoload :Utils, 'eth/utils'
21
+
22
+ class ValidationError < StandardError; end
23
+ class InvalidTransaction < ValidationError; end
24
+
25
+ end
@@ -0,0 +1,53 @@
1
+ module Eth
2
+ class Key
3
+
4
+ attr_reader :private_key, :public_key
5
+
6
+ def initialize(priv: nil)
7
+ @private_key = MoneyTree::PrivateKey.new key: priv
8
+ @public_key = MoneyTree::PublicKey.new private_key, compressed: false
9
+ end
10
+
11
+ def private_hex
12
+ private_key.to_hex
13
+ end
14
+
15
+ def public_bytes
16
+ public_key.to_bytes
17
+ end
18
+
19
+ def public_hex
20
+ public_key.to_hex
21
+ end
22
+
23
+ def to_address
24
+ Utils.bin_to_hex(Utils.keccak256(public_bytes[1..-1])[-20..-1])
25
+ end
26
+
27
+ def sign(message)
28
+ hash = message_hash(message)
29
+ loop do
30
+ signature = OpenSsl.sign_compact hash, private_hex, public_hex
31
+ return signature if valid_s? signature
32
+ end
33
+ end
34
+
35
+ def verify_signature(message, signature)
36
+ hash = message_hash(message)
37
+ public_hex == OpenSsl.recover_compact(hash, signature)
38
+ end
39
+
40
+
41
+ private
42
+
43
+ def message_hash(message)
44
+ Utils.keccak256 message
45
+ end
46
+
47
+ def valid_s?(signature)
48
+ s_value = Utils.v_r_s_for(signature).last
49
+ s_value <= SECP256K1_N/2 && s_value != 0
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,191 @@
1
+ # lifted from https://github.com/lian/bitcoin-ruby
2
+ # thanks to everyone there for figuring this out
3
+ # TODO: Pull shared code out into a separate library
4
+
5
+ module Eth
6
+ class OpenSsl
7
+ extend FFI::Library
8
+
9
+ if FFI::Platform.windows?
10
+ ffi_lib 'libeay32', 'ssleay32'
11
+ else
12
+ ffi_lib 'ssl'
13
+ end
14
+
15
+ NID_secp256k1 = 714
16
+ POINT_CONVERSION_COMPRESSED = 2
17
+ POINT_CONVERSION_UNCOMPRESSED = 4
18
+
19
+ attach_function :SSL_library_init, [], :int
20
+ attach_function :ERR_load_crypto_strings, [], :void
21
+ attach_function :SSL_load_error_strings, [], :void
22
+ attach_function :RAND_poll, [], :int
23
+
24
+ attach_function :BN_CTX_free, [:pointer], :int
25
+ attach_function :BN_CTX_new, [], :pointer
26
+ attach_function :BN_add, [:pointer, :pointer, :pointer], :int
27
+ attach_function :BN_bin2bn, [:pointer, :int, :pointer], :pointer
28
+ attach_function :BN_bn2bin, [:pointer, :pointer], :int
29
+ attach_function :BN_cmp, [:pointer, :pointer], :int
30
+ attach_function :BN_dup, [:pointer], :pointer
31
+ attach_function :BN_free, [:pointer], :int
32
+ attach_function :BN_mod_inverse, [:pointer, :pointer, :pointer, :pointer], :pointer
33
+ attach_function :BN_mod_mul, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
34
+ attach_function :BN_mod_sub, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
35
+ attach_function :BN_mul_word, [:pointer, :int], :int
36
+ attach_function :BN_new, [], :pointer
37
+ attach_function :BN_num_bits, [:pointer], :int
38
+ attach_function :BN_rshift, [:pointer, :pointer, :int], :int
39
+ attach_function :BN_set_word, [:pointer, :int], :int
40
+ attach_function :ECDSA_SIG_free, [:pointer], :void
41
+ attach_function :ECDSA_do_sign, [:pointer, :uint, :pointer], :pointer
42
+ attach_function :EC_GROUP_get_curve_GFp, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
43
+ attach_function :EC_GROUP_get_degree, [:pointer], :int
44
+ attach_function :EC_GROUP_get_order, [:pointer, :pointer, :pointer], :int
45
+ attach_function :EC_KEY_free, [:pointer], :int
46
+ attach_function :EC_KEY_get0_group, [:pointer], :pointer
47
+ attach_function :EC_KEY_new_by_curve_name, [:int], :pointer
48
+ attach_function :EC_KEY_set_conv_form, [:pointer, :int], :void
49
+ attach_function :EC_KEY_set_private_key, [:pointer, :pointer], :int
50
+ attach_function :EC_KEY_set_public_key, [:pointer, :pointer], :int
51
+ attach_function :EC_POINT_free, [:pointer], :int
52
+ attach_function :EC_POINT_mul, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
53
+ attach_function :EC_POINT_new, [:pointer], :pointer
54
+ attach_function :EC_POINT_set_compressed_coordinates_GFp, [:pointer, :pointer, :pointer, :int, :pointer], :int
55
+ attach_function :i2o_ECPublicKey, [:pointer, :pointer], :uint
56
+
57
+ def self.BN_num_bytes(ptr); (BN_num_bits(ptr) + 7) / 8; end
58
+
59
+ # def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil)
60
+ def self.sign_compact(hash, private_key, public_key_hex)
61
+ private_key = [private_key].pack("H*") if private_key.bytesize >= 64
62
+ private_key_hex = private_key.unpack("H*")[0]
63
+
64
+ # public_key_hex = regenerate_key(private_key_hex).last unless public_key_hex
65
+ # pubkey_compressed = (public_key_hex[0..1] == "04" ? false : true) unless pubkey_compressed
66
+ pubkey_compressed = false
67
+
68
+ init_ffi_ssl
69
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
70
+ priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new())
71
+
72
+ group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new()
73
+ EC_GROUP_get_order(group, order, ctx)
74
+
75
+ pub_key = EC_POINT_new(group)
76
+ EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
77
+ EC_KEY_set_private_key(eckey, priv_key)
78
+ EC_KEY_set_public_key(eckey, pub_key)
79
+
80
+ signature = ECDSA_do_sign(hash, hash.bytesize, eckey)
81
+
82
+ BN_free(order)
83
+ BN_CTX_free(ctx)
84
+ EC_POINT_free(pub_key)
85
+ BN_free(priv_key)
86
+ EC_KEY_free(eckey)
87
+
88
+ buf, rec_id, head = FFI::MemoryPointer.new(:uint8, 32), nil, nil
89
+ 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") }
90
+
91
+ if signature.get_array_of_pointer(0, 2).all?{|i| BN_num_bits(i) <= 256 }
92
+ 4.times{|i|
93
+ head = [ 27 + i + (pubkey_compressed ? 4 : 0) ].pack("C")
94
+ if public_key_hex == recover_public_key_from_signature(hash, [head, r, s].join, i, pubkey_compressed)
95
+ rec_id = i; break
96
+ end
97
+ }
98
+ end
99
+
100
+ ECDSA_SIG_free(signature)
101
+
102
+ [ head, [r,s] ].join if rec_id
103
+ end
104
+
105
+ def self.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed)
106
+ return nil if rec_id < 0 or signature.bytesize != 65
107
+ init_ffi_ssl
108
+
109
+ signature = FFI::MemoryPointer.from_string(signature)
110
+ #signature_bn = BN_bin2bn(signature, 65, BN_new())
111
+ r = BN_bin2bn(signature[1], 32, BN_new())
112
+ s = BN_bin2bn(signature[33], 32, BN_new())
113
+
114
+ n, i = 0, rec_id / 2
115
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
116
+
117
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
118
+
119
+ group = EC_KEY_get0_group(eckey)
120
+ order = BN_new()
121
+ EC_GROUP_get_order(group, order, nil)
122
+ x = BN_dup(order)
123
+ BN_mul_word(x, i)
124
+ BN_add(x, x, r)
125
+
126
+ field = BN_new()
127
+ EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
128
+
129
+ if BN_cmp(x, field) >= 0
130
+ [r, s, order, x, field].each{|i| BN_free(i) }
131
+ EC_KEY_free(eckey)
132
+ return nil
133
+ end
134
+
135
+ big_r = EC_POINT_new(group)
136
+ EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil)
137
+
138
+ big_q = EC_POINT_new(group)
139
+ n = EC_GROUP_get_degree(group)
140
+ e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new())
141
+ BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n
142
+
143
+ ctx = BN_CTX_new()
144
+ zero, rr, sor, eor = BN_new(), BN_new(), BN_new(), BN_new()
145
+ BN_set_word(zero, 0)
146
+ BN_mod_sub(e, zero, e, order, ctx)
147
+ BN_mod_inverse(rr, r, order, ctx)
148
+ BN_mod_mul(sor, s, rr, order, ctx)
149
+ BN_mod_mul(eor, e, rr, order, ctx)
150
+ EC_POINT_mul(group, big_q, eor, big_r, sor, ctx)
151
+ EC_KEY_set_public_key(eckey, big_q)
152
+ BN_CTX_free(ctx)
153
+
154
+ [r, s, order, x, field, e, zero, rr, sor, eor].each{|i| BN_free(i) }
155
+ [big_r, big_q].each{|i| EC_POINT_free(i) }
156
+
157
+ length = i2o_ECPublicKey(eckey, nil)
158
+ buf = FFI::MemoryPointer.new(:uint8, length)
159
+ ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
160
+ pub_hex = if i2o_ECPublicKey(eckey, ptr) == length
161
+ buf.read_string(length).unpack("H*")[0]
162
+ end
163
+
164
+ EC_KEY_free(eckey)
165
+
166
+ pub_hex
167
+ end
168
+
169
+ def self.recover_compact(hash, signature)
170
+ return false if signature.bytesize != 65
171
+ #i = signature.unpack("C")[0] - 27
172
+ #pubkey = recover_public_key_from_signature(hash, signature, (i & ~4), i >= 4)
173
+
174
+ version = signature.unpack('C')[0]
175
+ return false if version < 27 or version > 34
176
+
177
+ compressed = (version >= 31) ? (version -= 4; true) : false
178
+ pubkey = recover_public_key_from_signature(hash, signature, version-27, compressed)
179
+ end
180
+
181
+ def self.init_ffi_ssl
182
+ return if @ssl_loaded
183
+ SSL_library_init()
184
+ ERR_load_crypto_strings()
185
+ SSL_load_error_strings()
186
+ RAND_poll()
187
+ @ssl_loaded = true
188
+ end
189
+
190
+ end
191
+ 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,103 @@
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: 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\h+\Z/)
23
+ deserialize(RLP.decode data)
24
+ end
25
+
26
+ def initialize(*args)
27
+ fields = {v: 0, r: 0, s: 0}.merge parse_field_args(args)
28
+ fields[:to] = Utils.normalize_address(fields[:to])
29
+
30
+ serializable_initialize fields
31
+
32
+ check_transaction_validity
33
+ end
34
+
35
+ def unsigned_encoded
36
+ RLP.encode self, sedes: Tx.exclude([:v, :r, :s])
37
+ end
38
+
39
+ def encoded
40
+ RLP.encode self
41
+ end
42
+
43
+ def hex
44
+ bin_to_hex encoded
45
+ end
46
+
47
+ def sign(key)
48
+ self.signature = key.sign(unsigned_encoded)
49
+ self.vrs = Utils.v_r_s_for signature
50
+
51
+ self
52
+ end
53
+
54
+ def to_h
55
+ self.class.serializable_fields.keys.inject({}) do |hash, field|
56
+ hash[field] = send field
57
+ hash
58
+ end
59
+ end
60
+
61
+ def from
62
+ return @from if @from
63
+ @from ||= OpenSsl.recover_compact(signature_hash, signature) if signature
64
+ end
65
+
66
+ def signature
67
+ return @signature if @signature
68
+ self.signature = [v, r, s].map do |integer|
69
+ Utils.int_to_base256 integer
70
+ end.join if [v, r, s].all?
71
+ end
72
+
73
+
74
+ private
75
+
76
+ def check_transaction_validity
77
+ if [gas_price, gas_limit, value, nonce].max > UINT_MAX
78
+ raise InvalidTransaction, "Values way too high!"
79
+ elsif gas_limit < intrinsic_gas_used
80
+ raise InvalidTransaction, "Gas limit too low"
81
+ end
82
+ end
83
+
84
+ def vrs=(vrs)
85
+ self.v = vrs[0]
86
+ self.r = vrs[1]
87
+ self.s = vrs[2]
88
+ end
89
+
90
+ def intrinsic_gas_used
91
+ num_zero_bytes = data.count(BYTE_ZERO)
92
+ num_non_zero_bytes = data.size - num_zero_bytes
93
+
94
+ GTXCOST + GTXDATAZERO * num_zero_bytes +
95
+ GTXDATANONZERO * num_non_zero_bytes
96
+ end
97
+
98
+ def signature_hash
99
+ Utils.keccak256 unsigned_encoded
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,56 @@
1
+ module Eth
2
+
3
+ module Utils
4
+
5
+ extend self
6
+
7
+ def keccak256(message)
8
+ Digest::SHA3.new(256).digest(message)
9
+ end
10
+
11
+ def normalize_address(address)
12
+ if address.nil? || address == ''
13
+ ''
14
+ elsif address.size == 40
15
+ hex_to_bin address
16
+ elsif address.size == 42 && address[0..1] == '0x'
17
+ hex_to_bin address[2..-1]
18
+ else
19
+ address
20
+ end
21
+ end
22
+
23
+ def bin_to_hex(string)
24
+ string.unpack("H*")[0]
25
+ end
26
+
27
+ def hex_to_bin(string)
28
+ [string].pack("H*")
29
+ end
30
+
31
+ def base256_to_int(string)
32
+ string.bytes.inject do |result, byte|
33
+ result *= 256
34
+ result + byte
35
+ end
36
+ end
37
+
38
+ def int_to_base256(int)
39
+ bytes = []
40
+ while int > 0 do
41
+ bytes.unshift(int % 256)
42
+ int /= 256
43
+ end
44
+ bytes.pack('C*')
45
+ end
46
+
47
+ def v_r_s_for(signature)
48
+ [
49
+ signature[0].bytes[0],
50
+ Utils.base256_to_int(signature[1..32]),
51
+ Utils.base256_to_int(signature[33..65]),
52
+ ]
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module Eth
2
+ VERSION = "0.3.0"
3
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Steve Ellis
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-07-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: digest-sha3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ethereum-base
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: ffi
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: money-tree
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rlp
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.7'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.1'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ description: Library to build, parse, and sign Ethereum transactions.
140
+ email:
141
+ - email@steveell.is
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".rspec"
148
+ - ".travis.yml"
149
+ - Gemfile
150
+ - LICENSE.txt
151
+ - README.md
152
+ - Rakefile
153
+ - bin/console
154
+ - bin/setup
155
+ - eth.gemspec
156
+ - lib/eth.rb
157
+ - lib/eth/key.rb
158
+ - lib/eth/open_ssl.rb
159
+ - lib/eth/sedes.rb
160
+ - lib/eth/tx.rb
161
+ - lib/eth/utils.rb
162
+ - lib/eth/version.rb
163
+ homepage: https://github.com/se3000/ruby-eth
164
+ licenses:
165
+ - MIT
166
+ metadata: {}
167
+ post_install_message:
168
+ rdoc_options: []
169
+ require_paths:
170
+ - lib
171
+ required_ruby_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ requirements: []
182
+ rubyforge_project:
183
+ rubygems_version: 2.5.1
184
+ signing_key:
185
+ specification_version: 4
186
+ summary: Simple API to sign Ethereum transactions.
187
+ test_files: []
188
+ has_rdoc: