eth 0.4.17 → 0.4.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d50d2e45f9d5e59e5d56cc1a5f43fd96d892fa991c3479d9f7b74623cc288593
4
- data.tar.gz: 519efad7ad2cc42e2402910ad298166dfa9266c552c579232715f8a7fa3b6a8b
3
+ metadata.gz: 2cfb1dbda97ae8033690aeb0ffe7410e2db112dbb3d2c78f34bad15db7dcbf45
4
+ data.tar.gz: '039a0fc3b15cd132f1409fc8636f32d501f237e338628c63672f21fed81047af'
5
5
  SHA512:
6
- metadata.gz: 7e38450c7a46789421250fe0f34900d4a1066c500744ba04cf76feddb52cba26bf9c94bc981c7979f07568e74799b3e31e4e887195ae235f29d7a33e3620dae2
7
- data.tar.gz: 0c3822f4a19288a63cb73fad38bab8cea19db5873c98ebc78aa5882ff921371617df97c728656ac0144aec2a13ab6c980be516036dfe0895ca6fb4b0a9c0fbb0
6
+ metadata.gz: e69bf16bccb10f673673c8f45167817930549813a3e9fa33b64e868a618f6bbd810c23a8512c1a0f535a18d38238b71ab18afdfd438e6ebd8cffb2deb5256a79
7
+ data.tar.gz: 67c6de579f25a7b9cdecd8fee97f5df927d8f0145c03b9604c324e86925ba905f6e98b42e49b1487178842ea25efe3a8f0ea35162ee96666db85345bf0281bd4
@@ -11,16 +11,26 @@ on:
11
11
 
12
12
  jobs:
13
13
  build:
14
- runs-on: ubuntu-latest
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ os: [ubuntu-latest, macos-latest]
19
+ ruby: ['2.7', '3.0']
15
20
  steps:
16
21
  - uses: actions/checkout@v2
17
22
  - uses: ruby/setup-ruby@v1
18
23
  with:
19
- ruby-version: 3.0
24
+ ruby-version: ${{ matrix.ruby }}
25
+ bundler-cache: true
26
+ - name: Brew Automake
27
+ run: |
28
+ brew install automake
29
+ if: startsWith(matrix.os, 'macOS')
20
30
  - name: Install Dependencies
21
31
  run: |
22
32
  git submodule update --init
23
33
  bundle install
24
34
  - name: Run Tests
25
35
  run: |
26
- rspec
36
+ bundle exec rspec
@@ -8,9 +8,6 @@ on:
8
8
  push:
9
9
  branches:
10
10
  - develop
11
- schedule:
12
- -
13
- cron: "45 1 * * 3"
14
11
 
15
12
  jobs:
16
13
  analyze:
@@ -36,3 +33,12 @@ jobs:
36
33
  uses: github/codeql-action/autobuild@v1
37
34
  - name: "Perform CodeQL Analysis"
38
35
  uses: github/codeql-action/analyze@v1
36
+ - uses: ruby/setup-ruby@v1
37
+ with:
38
+ ruby-version: '2.7'
39
+ bundler-cache: true
40
+ - name: "Run rufo code formatting checks"
41
+ run: |
42
+ gem install rufo
43
+ rufo --check ./lib
44
+ rufo --check ./spec
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: Docs
3
+
4
+ on:
5
+ push:
6
+ branches:
7
+ - develop
8
+
9
+ jobs:
10
+ docs:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ - uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: '2.7'
17
+ bundler-cache: true
18
+ - name: Run Yard Doc
19
+ run: |
20
+ gem install yard
21
+ yard doc
22
+ - name: Deploy GH Pages
23
+ uses: JamesIves/github-pages-deploy-action@4.1.7
24
+ with:
25
+ branch: gh-pages
26
+ folder: doc/
data/Gemfile CHANGED
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ # ref: https://github.com/GemHQ/money-tree/issues/50
4
+ gem "money-tree", git: "https://github.com/GemHQ/money-tree.git"
5
+
6
+ source "https://rubygems.org"
4
7
 
5
8
  # Specify your gem's dependencies in eth.gemspec
6
9
  gemspec
data/eth.gemspec CHANGED
@@ -1,46 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
  # coding: utf-8
3
3
 
4
- lib = File.expand_path('lib', __dir__).freeze
4
+ lib = File.expand_path("lib", __dir__).freeze
5
5
  $LOAD_PATH.unshift lib unless $LOAD_PATH.include? lib
6
6
 
7
- require 'eth/version'
7
+ require "eth/version"
8
8
 
9
9
  Gem::Specification.new do |spec|
10
- spec.name = "eth"
11
- spec.version = Eth::VERSION
12
- spec.authors = ["Steve Ellis", "Afri Schoedon"]
13
- spec.email = ["email@steveell.is", "ruby@q9f.cc"]
10
+ spec.name = "eth"
11
+ spec.version = Eth::VERSION
12
+ spec.authors = ["Steve Ellis", "Afri Schoedon"]
13
+ spec.email = ["email@steveell.is", "ruby@q9f.cc"]
14
14
 
15
- spec.summary = %q{Simple API to sign Ethereum transactions.}
16
- spec.description = %q{Library to build, parse, and sign Ethereum transactions.}
17
- spec.homepage = "https://github.com/se3000/ruby-eth"
18
- spec.license = "MIT"
15
+ spec.summary = %q{Simple API to sign Ethereum transactions.}
16
+ spec.description = %q{Library to build, parse, and sign Ethereum transactions.}
17
+ spec.homepage = "https://github.com/se3000/ruby-eth"
18
+ spec.license = "MIT"
19
19
 
20
20
  spec.metadata = {
21
- 'homepage_uri' => 'https://github.com/se3000/ruby-eth',
22
- 'source_code_uri' => 'https://github.com/se3000/ruby-eth',
23
- 'github_repo' => 'https://github.com/se3000/ruby-eth',
24
- 'bug_tracker_uri' => 'https://github.com/se3000/ruby-eth/issues',
21
+ "homepage_uri" => "https://github.com/se3000/ruby-eth",
22
+ "source_code_uri" => "https://github.com/se3000/ruby-eth",
23
+ "github_repo" => "https://github.com/se3000/ruby-eth",
24
+ "bug_tracker_uri" => "https://github.com/se3000/ruby-eth/issues",
25
25
  }.freeze
26
26
 
27
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
- spec.bindir = "exe"
29
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
30
  spec.require_paths = ["lib"]
31
- spec.test_files = spec.files.grep %r{^(test|spec|features)/}
31
+ spec.test_files = spec.files.grep %r{^(test|spec|features)/}
32
32
 
33
- spec.add_dependency 'keccak', '~> 1.3'
34
- spec.add_dependency 'ffi', '~> 1.15'
35
- spec.add_dependency 'money-tree', '~> 0.10'
36
- spec.add_dependency 'rlp', '~> 0.7'
37
- spec.add_dependency 'scrypt', '~> 3.0'
33
+ spec.add_dependency "keccak", "~> 1.3"
34
+ spec.add_dependency "ffi", "~> 1.15"
35
+ spec.add_dependency "money-tree", "~> 0.11"
36
+ spec.add_dependency "openssl", "~> 3.0"
37
+ spec.add_dependency "rlp", "~> 0.7"
38
+ spec.add_dependency "scrypt", "~> 3.0"
38
39
 
39
40
  spec.platform = Gem::Platform::RUBY
40
- spec.required_ruby_version = ">= 2.2", "< 4.0"
41
+ spec.required_ruby_version = ">= 2.6", "< 4.0"
41
42
 
42
- spec.add_development_dependency 'bundler', '~> 2.2'
43
- spec.add_development_dependency 'pry', '~> 0.14'
44
- spec.add_development_dependency 'rake', '~> 13.0'
45
- spec.add_development_dependency 'rspec', '~> 3.10'
43
+ spec.add_development_dependency "bundler", "~> 2.2"
44
+ spec.add_development_dependency "pry", "~> 0.14"
45
+ spec.add_development_dependency "rake", "~> 13.0"
46
+ spec.add_development_dependency "rspec", "~> 3.10"
46
47
  end
data/lib/eth/address.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Eth
2
2
  class Address
3
-
4
3
  def initialize(address)
5
4
  @address = Utils.prefix_hex(address)
6
5
  end
@@ -25,7 +24,6 @@ module Eth
25
24
  Utils.prefix_hex(cased.join)
26
25
  end
27
26
 
28
-
29
27
  private
30
28
 
31
29
  attr_reader :address
@@ -57,6 +55,5 @@ module Eth
57
55
  def unprefixed
58
56
  Utils.remove_hex_prefix address
59
57
  end
60
-
61
58
  end
62
59
  end
data/lib/eth/gas.rb CHANGED
@@ -1,9 +1,7 @@
1
1
  module Eth
2
2
  class Gas
3
-
4
3
  GTXCOST = 21000 # TX BASE GAS COST
5
4
  GTXDATANONZERO = 68 # TX DATA NON ZERO BYTE GAS COST
6
5
  GTXDATAZERO = 4 # TX DATA ZERO BYTE GAS COST
7
-
8
6
  end
9
7
  end
@@ -1,5 +1,5 @@
1
- require 'json'
2
- require 'scrypt'
1
+ require "json"
2
+ require "scrypt"
3
3
 
4
4
  class Eth::Key::Decrypter
5
5
  include Eth::Utils
@@ -19,16 +19,15 @@ class Eth::Key::Decrypter
19
19
  bin_to_hex decrypted_data
20
20
  end
21
21
 
22
-
23
22
  private
24
23
 
25
24
  attr_reader :data, :key, :password
26
25
 
27
26
  def derive_key(password)
28
27
  case kdf
29
- when 'pbkdf2'
28
+ when "pbkdf2"
30
29
  @key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
31
- when 'scrypt'
30
+ when "scrypt"
32
31
  # OpenSSL 1.1 inclues OpenSSL::KDF.scrypt, but it is not available usually, otherwise we could do: OpenSSL::KDF.scrypt(password, salt: salt, N: n, r: r, p: p, length: key_length)
33
32
  @key = SCrypt::Engine.scrypt(password, salt, n, r, p, key_length)
34
33
  else
@@ -37,8 +36,8 @@ class Eth::Key::Decrypter
37
36
  end
38
37
 
39
38
  def check_macs
40
- mac1 = keccak256(key[(key_length/2), key_length] + ciphertext)
41
- mac2 = hex_to_bin crypto_data['mac']
39
+ mac1 = keccak256(key[(key_length / 2), key_length] + ciphertext)
40
+ mac2 = hex_to_bin crypto_data["mac"]
42
41
 
43
42
  if mac1 != mac2
44
43
  raise "Message Authentications Codes do not match!"
@@ -50,11 +49,11 @@ class Eth::Key::Decrypter
50
49
  end
51
50
 
52
51
  def crypto_data
53
- @crypto_data ||= data['crypto'] || data['Crypto']
52
+ @crypto_data ||= data["crypto"] || data["Crypto"]
54
53
  end
55
54
 
56
55
  def ciphertext
57
- hex_to_bin crypto_data['ciphertext']
56
+ hex_to_bin crypto_data["ciphertext"]
58
57
  end
59
58
 
60
59
  def cipher_name
@@ -64,41 +63,41 @@ class Eth::Key::Decrypter
64
63
  def cipher
65
64
  @cipher ||= OpenSSL::Cipher.new(cipher_name).tap do |cipher|
66
65
  cipher.decrypt
67
- cipher.key = key[0, (key_length/2)]
66
+ cipher.key = key[0, (key_length / 2)]
68
67
  cipher.iv = iv
69
68
  end
70
69
  end
71
70
 
72
71
  def iv
73
- hex_to_bin crypto_data['cipherparams']['iv']
72
+ hex_to_bin crypto_data["cipherparams"]["iv"]
74
73
  end
75
74
 
76
75
  def salt
77
- hex_to_bin crypto_data['kdfparams']['salt']
76
+ hex_to_bin crypto_data["kdfparams"]["salt"]
78
77
  end
79
78
 
80
79
  def iterations
81
- crypto_data['kdfparams']['c'].to_i
80
+ crypto_data["kdfparams"]["c"].to_i
82
81
  end
83
82
 
84
83
  def kdf
85
- crypto_data['kdf']
84
+ crypto_data["kdf"]
86
85
  end
87
86
 
88
87
  def key_length
89
- crypto_data['kdfparams']['dklen'].to_i
88
+ crypto_data["kdfparams"]["dklen"].to_i
90
89
  end
91
90
 
92
91
  def n
93
- crypto_data['kdfparams']['n'].to_i
92
+ crypto_data["kdfparams"]["n"].to_i
94
93
  end
95
94
 
96
95
  def r
97
- crypto_data['kdfparams']['r'].to_i
96
+ crypto_data["kdfparams"]["r"].to_i
98
97
  end
99
98
 
100
99
  def p
101
- crypto_data['kdfparams']['p'].to_i
100
+ crypto_data["kdfparams"]["p"].to_i
102
101
  end
103
102
 
104
103
  def digest
@@ -108,6 +107,4 @@ class Eth::Key::Decrypter
108
107
  def digest_name
109
108
  "sha256"
110
109
  end
111
-
112
-
113
110
  end
@@ -1,5 +1,5 @@
1
- require 'json'
2
- require 'securerandom'
1
+ require "json"
2
+ require "securerandom"
3
3
 
4
4
  class Eth::Key::Encrypter
5
5
  include Eth::Utils
@@ -48,7 +48,6 @@ class Eth::Key::Encrypter
48
48
  @id ||= options[:id] || SecureRandom.uuid
49
49
  end
50
50
 
51
-
52
51
  private
53
52
 
54
53
  attr_reader :derived_key, :encrypted_key, :key, :options
@@ -57,7 +56,7 @@ class Eth::Key::Encrypter
57
56
  @cipher ||= OpenSSL::Cipher.new(cipher_name).tap do |cipher|
58
57
  cipher.encrypt
59
58
  cipher.iv = iv
60
- cipher.key = derived_key[0, (key_length/2)]
59
+ cipher.key = derived_key[0, (key_length / 2)]
61
60
  end
62
61
  end
63
62
 
@@ -74,7 +73,7 @@ class Eth::Key::Encrypter
74
73
  end
75
74
 
76
75
  def mac
77
- keccak256(derived_key[(key_length/2), key_length] + encrypted_key)
76
+ keccak256(derived_key[(key_length / 2), key_length] + encrypted_key)
78
77
  end
79
78
 
80
79
  def cipher_name
@@ -107,22 +106,21 @@ class Eth::Key::Encrypter
107
106
 
108
107
  def salt
109
108
  @salt ||= if options[:salt]
110
- hex_to_bin options[:salt]
111
- else
112
- SecureRandom.random_bytes(salt_length)
113
- end
109
+ hex_to_bin options[:salt]
110
+ else
111
+ SecureRandom.random_bytes(salt_length)
112
+ end
114
113
  end
115
114
 
116
115
  def iv
117
116
  @iv ||= if options[:iv]
118
- hex_to_bin options[:iv]
119
- else
120
- SecureRandom.random_bytes(iv_length)
121
- end
117
+ hex_to_bin options[:iv]
118
+ else
119
+ SecureRandom.random_bytes(iv_length)
120
+ end
122
121
  end
123
122
 
124
123
  def address
125
124
  Eth::Key.new(priv: key).address
126
125
  end
127
-
128
126
  end
data/lib/eth/key.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Eth
2
2
  class Key
3
- autoload :Decrypter, 'eth/key/decrypter'
4
- autoload :Encrypter, 'eth/key/encrypter'
3
+ autoload :Decrypter, "eth/key/decrypter"
4
+ autoload :Encrypter, "eth/key/encrypter"
5
5
 
6
6
  attr_reader :private_key, :public_key
7
7
 
@@ -17,7 +17,7 @@ module Eth
17
17
  end
18
18
 
19
19
  def self.personal_recover(message, signature)
20
- bin_signature = Utils.hex_to_bin(signature).bytes.rotate(-1).pack('c*')
20
+ bin_signature = Utils.hex_to_bin(signature).bytes.rotate(-1).pack("c*")
21
21
  OpenSsl.recover_compact(Utils.keccak256(Utils.prefix_message(message)), bin_signature)
22
22
  end
23
23
 
@@ -41,6 +41,7 @@ module Eth
41
41
  def address
42
42
  Utils.public_key_to_address public_hex
43
43
  end
44
+
44
45
  alias_method :to_address, :address
45
46
 
46
47
  def sign(message)
@@ -60,10 +61,9 @@ module Eth
60
61
  end
61
62
 
62
63
  def personal_sign(message)
63
- Utils.bin_to_hex(sign(Utils.prefix_message(message)).bytes.rotate(1).pack('c*'))
64
+ Utils.bin_to_hex(sign(Utils.prefix_message(message)).bytes.rotate(1).pack("c*"))
64
65
  end
65
66
 
66
-
67
67
  private
68
68
 
69
69
  def message_hash(message)
@@ -72,8 +72,7 @@ module Eth
72
72
 
73
73
  def valid_s?(signature)
74
74
  s_value = Utils.v_r_s_for(signature).last
75
- s_value <= Secp256k1::N/2 && s_value != 0
75
+ s_value <= Secp256k1::N / 2 && s_value != 0
76
76
  end
77
-
78
77
  end
79
78
  end
data/lib/eth/open_ssl.rb CHANGED
@@ -1,28 +1,22 @@
1
1
  # originally lifted from https://github.com/lian/bitcoin-ruby
2
2
  # thanks to everyone there for figuring this out
3
3
 
4
+ # encoding: ascii-8bit
5
+
6
+ require "openssl"
7
+ require "ffi"
8
+
4
9
  module Eth
5
10
  class OpenSsl
6
11
  extend FFI::Library
7
12
 
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
13
+ # Use the library loaded by the extension require above.
14
+ ffi_lib FFI::CURRENT_PROCESS
17
15
 
18
16
  NID_secp256k1 = 714
19
17
  POINT_CONVERSION_COMPRESSED = 2
20
18
  POINT_CONVERSION_UNCOMPRESSED = 4
21
19
 
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
20
  # OpenSSL 1.1.0 engine constants, taken from:
27
21
  # https://github.com/openssl/openssl/blob/2be8c56a39b0ec2ec5af6ceaf729df154d784a43/include/openssl/crypto.h
28
22
  OPENSSL_INIT_ENGINE_RDRAND = 0x00000200
@@ -30,13 +24,11 @@ module Eth
30
24
  OPENSSL_INIT_ENGINE_CRYPTODEV = 0x00001000
31
25
  OPENSSL_INIT_ENGINE_CAPI = 0x00002000
32
26
  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
- )
27
+ OPENSSL_INIT_ENGINE_ALL_BUILTIN = (OPENSSL_INIT_ENGINE_RDRAND |
28
+ OPENSSL_INIT_ENGINE_DYNAMIC |
29
+ OPENSSL_INIT_ENGINE_CRYPTODEV |
30
+ OPENSSL_INIT_ENGINE_CAPI |
31
+ OPENSSL_INIT_ENGINE_PADLOCK)
40
32
 
41
33
  # OpenSSL 1.1.0 load strings constant, taken from:
42
34
  # https://github.com/openssl/openssl/blob/c162c126be342b8cd97996346598ecf7db56130f/include/openssl/ssl.h
@@ -50,215 +42,354 @@ module Eth
50
42
  attach_function :SSLeay, [], :long
51
43
  end
52
44
 
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
45
+ begin
65
46
  # Initialization procedure for the library was changed in OpenSSL 1.1.0
66
47
  attach_function :OPENSSL_init_ssl, [:uint64, :pointer], :int
67
- else
48
+ rescue FFI::NotFoundError
68
49
  attach_function :SSL_library_init, [], :int
69
50
  attach_function :ERR_load_crypto_strings, [], :void
70
51
  attach_function :SSL_load_error_strings, [], :void
71
52
  end
72
53
 
73
54
  attach_function :RAND_poll, [], :int
55
+
74
56
  attach_function :BN_CTX_free, [:pointer], :int
75
57
  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
58
+ attach_function :BN_add, %i[pointer pointer pointer], :int
59
+ attach_function :BN_bin2bn, %i[pointer int pointer], :pointer
60
+ attach_function :BN_bn2bin, %i[pointer pointer], :int
61
+ attach_function :BN_cmp, %i[pointer pointer], :int
80
62
  attach_function :BN_dup, [:pointer], :pointer
81
63
  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
64
+ attach_function :BN_mod_inverse, %i[pointer pointer pointer pointer], :pointer
65
+ attach_function :BN_mod_mul, %i[pointer pointer pointer pointer pointer], :int
66
+ attach_function :BN_mod_sub, %i[pointer pointer pointer pointer pointer], :int
67
+ attach_function :BN_mul_word, %i[pointer int], :int
86
68
  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
69
+ attach_function :BN_rshift, %i[pointer pointer int], :int
70
+ attach_function :BN_rshift1, %i[pointer pointer], :int
71
+ attach_function :BN_set_word, %i[pointer int], :int
72
+ attach_function :BN_sub, %i[pointer pointer pointer], :int
73
+ attach_function :EC_GROUP_get_curve_GFp, %i[pointer pointer pointer pointer pointer], :int
93
74
  attach_function :EC_GROUP_get_degree, [:pointer], :int
94
- attach_function :EC_GROUP_get_order, [:pointer, :pointer, :pointer], :int
75
+ attach_function :EC_GROUP_get_order, %i[pointer pointer pointer], :int
95
76
  attach_function :EC_KEY_free, [:pointer], :int
96
77
  attach_function :EC_KEY_get0_group, [:pointer], :pointer
78
+ attach_function :EC_KEY_get0_private_key, [:pointer], :pointer
97
79
  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
80
+ attach_function :EC_KEY_set_conv_form, %i[pointer int], :void
81
+ attach_function :EC_KEY_set_private_key, %i[pointer pointer], :int
82
+ attach_function :EC_KEY_set_public_key, %i[pointer pointer], :int
101
83
  attach_function :EC_POINT_free, [:pointer], :int
102
- attach_function :EC_POINT_mul, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
84
+ attach_function :EC_POINT_mul, %i[pointer pointer pointer pointer pointer pointer], :int
103
85
  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
86
+ attach_function :EC_POINT_set_compressed_coordinates_GFp,
87
+ %i[pointer pointer pointer int pointer], :int
88
+ attach_function :i2o_ECPublicKey, %i[pointer pointer], :uint
89
+ attach_function :ECDSA_do_sign, %i[pointer uint pointer], :pointer
90
+ attach_function :BN_num_bits, [:pointer], :int
91
+ attach_function :ECDSA_SIG_free, [:pointer], :void
92
+ attach_function :EC_POINT_add, %i[pointer pointer pointer pointer pointer], :int
93
+ attach_function :EC_POINT_point2hex, %i[pointer pointer int pointer], :string
94
+ attach_function :EC_POINT_hex2point, %i[pointer string pointer pointer], :pointer
95
+ attach_function :d2i_ECDSA_SIG, %i[pointer pointer long], :pointer
96
+ attach_function :i2d_ECDSA_SIG, %i[pointer pointer], :int
97
+ attach_function :OPENSSL_free, :CRYPTO_free, [:pointer], :void
98
+
99
+ def self.BN_num_bytes(ptr) # rubocop:disable Naming/MethodName
100
+ (BN_num_bits(ptr) + 7) / 8
101
+ end
106
102
 
107
- class << self
108
- def BN_num_bytes(ptr)
109
- (BN_num_bits(ptr) + 7) / 8
103
+ # resolve public from private key, using ffi and libssl.so
104
+ # example:
105
+ # keypair = Bitcoin.generate_key; Bitcoin::OpenSSL_EC.regenerate_key(keypair.first) == keypair
106
+ def self.regenerate_key(private_key)
107
+ private_key = [private_key].pack("H*") if private_key.bytesize >= (32 * 2)
108
+ private_key_hex = private_key.unpack("H*")[0]
109
+
110
+ group = OpenSSL::PKey::EC::Group.new("secp256k1")
111
+ key = OpenSSL::PKey::EC.new(group)
112
+ key.private_key = OpenSSL::BN.new(private_key_hex, 16)
113
+ key.public_key = group.generator.mul(key.private_key)
114
+
115
+ priv_hex = key.private_key.to_bn.to_s(16).downcase.rjust(64, "0")
116
+ if priv_hex != private_key_hex
117
+ raise "regenerated wrong private_key, raise here before generating a faulty public_key too!"
110
118
  end
111
119
 
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
120
+ [priv_hex, key.public_key.to_bn.to_s(16).downcase]
121
+ end
115
122
 
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())
123
+ # Given the components of a signature and a selector value, recover and
124
+ # return the public key that generated the signature according to the
125
+ # algorithm in SEC1v2 section 4.1.6.
126
+ #
127
+ # rec_id is an index from 0 to 3 that indicates which of the 4 possible
128
+ # keys is the correct one. Because the key recovery operation yields
129
+ # multiple potential keys, the correct key must either be stored alongside
130
+ # the signature, or you must be willing to try each rec_id in turn until
131
+ # you find one that outputs the key you are expecting.
132
+ #
133
+ # If this method returns nil, it means recovery was not possible and rec_id
134
+ # should be iterated.
135
+ #
136
+ # Given the above two points, a correct usage of this method is inside a
137
+ # for loop from 0 to 3, and if the output is nil OR a key that is not the
138
+ # one you expect, you try again with the next rec_id.
139
+ #
140
+ # message_hash = hash of the signed message.
141
+ # signature = the R and S components of the signature, wrapped.
142
+ # rec_id = which possible key to recover.
143
+ # is_compressed = whether or not the original pubkey was compressed.
144
+ def self.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed)
145
+ return nil if rec_id < 0 || signature.bytesize != 65
146
+ init_ffi_ssl
147
+
148
+ signature = FFI::MemoryPointer.from_string(signature)
149
+ # signature_bn = BN_bin2bn(signature, 65, BN_new())
150
+ r = BN_bin2bn(signature[1], 32, BN_new())
151
+ s = BN_bin2bn(signature[33], 32, BN_new())
152
+
153
+ i = rec_id / 2
154
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
155
+
156
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
157
+
158
+ group = EC_KEY_get0_group(eckey)
159
+ order = BN_new()
160
+ EC_GROUP_get_order(group, order, nil)
161
+ x = BN_dup(order)
162
+ BN_mul_word(x, i)
163
+ BN_add(x, x, r)
164
+
165
+ field = BN_new()
166
+ EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
167
+
168
+ if BN_cmp(x, field) >= 0
169
+ [r, s, order, x, field].each { |item| BN_free(item) }
170
+ EC_KEY_free(eckey)
171
+ return nil
172
+ end
119
173
 
120
- group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new()
121
- EC_GROUP_get_order(group, order, ctx)
174
+ big_r = EC_POINT_new(group)
175
+ EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil)
176
+
177
+ big_q = EC_POINT_new(group)
178
+ n = EC_GROUP_get_degree(group)
179
+ e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new())
180
+ BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n
181
+
182
+ ctx = BN_CTX_new()
183
+ zero = BN_new()
184
+ rr = BN_new()
185
+ sor = BN_new()
186
+ eor = BN_new()
187
+ BN_set_word(zero, 0)
188
+ BN_mod_sub(e, zero, e, order, ctx)
189
+ BN_mod_inverse(rr, r, order, ctx)
190
+ BN_mod_mul(sor, s, rr, order, ctx)
191
+ BN_mod_mul(eor, e, rr, order, ctx)
192
+ EC_POINT_mul(group, big_q, eor, big_r, sor, ctx)
193
+ EC_KEY_set_public_key(eckey, big_q)
194
+ BN_CTX_free(ctx)
195
+
196
+ [r, s, order, x, field, e, zero, rr, sor, eor].each { |item| BN_free(item) }
197
+ [big_r, big_q].each { |item| EC_POINT_free(item) }
198
+
199
+ length = i2o_ECPublicKey(eckey, nil)
200
+ buf = FFI::MemoryPointer.new(:uint8, length)
201
+ ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
202
+ pub_hex = buf.read_string(length).unpack("H*")[0] if i2o_ECPublicKey(eckey, ptr) == length
203
+
204
+ EC_KEY_free(eckey)
205
+
206
+ pub_hex
207
+ end
122
208
 
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)
209
+ # Regenerate a DER-encoded signature such that the S-value complies with the BIP62
210
+ # specification.
211
+ #
212
+ def self.signature_to_low_s(signature)
213
+ init_ffi_ssl
214
+
215
+ buf = FFI::MemoryPointer.new(:uint8, 34)
216
+ temp = signature.unpack("C*")
217
+ length_r = temp[3]
218
+ length_s = temp[5 + length_r]
219
+ sig = FFI::MemoryPointer.from_string(signature)
220
+
221
+ # Calculate the lower s value
222
+ s = BN_bin2bn(sig[6 + length_r], length_s, BN_new())
223
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
224
+ group = EC_KEY_get0_group(eckey)
225
+ order = BN_new()
226
+ halforder = BN_new()
227
+ ctx = BN_CTX_new()
228
+
229
+ EC_GROUP_get_order(group, order, ctx)
230
+ BN_rshift1(halforder, order)
231
+ BN_sub(s, order, s) if BN_cmp(s, halforder) > 0
232
+
233
+ BN_free(halforder)
234
+ BN_free(order)
235
+ BN_CTX_free(ctx)
236
+
237
+ length_s = BN_bn2bin(s, buf)
238
+ # p buf.read_string(length_s).unpack("H*")
239
+
240
+ # Re-encode the signature in DER format
241
+ sig = [0x30, 0, 0x02, length_r]
242
+ sig.concat(temp.slice(4, length_r))
243
+ sig << 0x02
244
+ sig << length_s
245
+ sig.concat(buf.read_string(length_s).unpack("C*"))
246
+ sig[1] = sig.size - 2
247
+
248
+ BN_free(s)
249
+ EC_KEY_free(eckey)
250
+
251
+ sig.pack("C*")
252
+ end
127
253
 
128
- signature = ECDSA_do_sign(hash, hash.bytesize, eckey)
254
+ def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil)
255
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
129
256
 
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)
257
+ private_key = [private_key].pack("H*") if private_key.bytesize >= 64
258
+ private_key_hex = private_key.unpack("H*")[0]
135
259
 
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") }
260
+ public_key_hex ||= regenerate_key(private_key_hex).last
261
+ pubkey_compressed ||= public_key_hex[0..1] != "04"
138
262
 
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
263
+ init_ffi_ssl
264
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
265
+ priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new())
147
266
 
148
- ECDSA_SIG_free(signature)
267
+ group = EC_KEY_get0_group(eckey)
268
+ order = BN_new()
269
+ ctx = BN_CTX_new()
270
+ EC_GROUP_get_order(group, order, ctx)
149
271
 
150
- [ head, [r,s] ].join if rec_id
151
- end
272
+ pub_key = EC_POINT_new(group)
273
+ EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
274
+ EC_KEY_set_private_key(eckey, priv_key)
275
+ EC_KEY_set_public_key(eckey, pub_key)
152
276
 
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
277
+ signature = ECDSA_do_sign(msg32, msg32.size, eckey)
156
278
 
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())
279
+ BN_free(order)
280
+ BN_CTX_free(ctx)
281
+ EC_POINT_free(pub_key)
282
+ BN_free(priv_key)
283
+ EC_KEY_free(eckey)
160
284
 
161
- _n, i = 0, rec_id / 2
162
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
285
+ buf = FFI::MemoryPointer.new(:uint8, 32)
286
+ head = nil
287
+ r, s = signature.get_array_of_pointer(0, 2).map do |i|
288
+ BN_bn2bin(i, buf)
289
+ buf.read_string(BN_num_bytes(i)).rjust(32, "\x00")
290
+ end
163
291
 
164
- EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
292
+ rec_id = nil
293
+ if signature.get_array_of_pointer(0, 2).all? { |i| BN_num_bits(i) <= 256 }
294
+ 4.times do |i|
295
+ head = [27 + i + (pubkey_compressed ? 4 : 0)].pack("C")
296
+ recovered_key = recover_public_key_from_signature(
297
+ msg32.read_string(32), [head, r, s].join, i, pubkey_compressed
298
+ )
299
+ if public_key_hex == recovered_key
300
+ rec_id = i
301
+ break
302
+ end
303
+ end
304
+ end
165
305
 
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)
306
+ ECDSA_SIG_free(signature)
172
307
 
173
- field = BN_new()
174
- EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
308
+ [head, [r, s]].join if rec_id
309
+ end
175
310
 
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
311
+ def self.recover_compact(hash, signature)
312
+ return false if signature.bytesize != 65
313
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
314
+
315
+ version = signature.unpack("C")[0]
181
316
 
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
317
+ # Version of signature should be 27 or 28, but 0 and 1 are also possible versions
318
+ # which can show up in Ledger hardwallet signings
319
+ if version < 27
320
+ version += 27
205
321
  end
206
322
 
207
- def recover_compact(hash, signature)
208
- return false if signature.bytesize != 65
323
+ return false if version < 27 || version > 34
209
324
 
210
- version = signature.unpack('C')[0]
325
+ compressed = version >= 31
326
+ version -= 4 if compressed
211
327
 
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
328
+ recover_public_key_from_signature(msg32.read_string(32), signature, version - 27, compressed)
329
+ end
217
330
 
218
- v_base = Eth.replayable_v?(version) ? Eth.replayable_chain_id : Eth.v_base
331
+ # lifted from https://github.com/GemHQ/money-tree
332
+ def self.ec_add(point0, point1)
333
+ init_ffi_ssl
219
334
 
220
- return false if version < v_base
335
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
336
+ group = EC_KEY_get0_group(eckey)
221
337
 
222
- recover_public_key_from_signature(hash, signature, (version - v_base), false)
223
- end
338
+ point_0_hex = point0.to_bn.to_s(16)
339
+ point_0_pt = EC_POINT_hex2point(group, point_0_hex, nil, nil)
340
+ point_1_hex = point1.to_bn.to_s(16)
341
+ point_1_pt = EC_POINT_hex2point(group, point_1_hex, nil, nil)
224
342
 
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
343
+ sum_point = EC_POINT_new(group)
344
+ EC_POINT_add(group, sum_point, point_0_pt, point_1_pt, nil)
345
+ hex = EC_POINT_point2hex(group, sum_point, POINT_CONVERSION_UNCOMPRESSED, nil)
346
+ EC_KEY_free(eckey)
347
+ EC_POINT_free(sum_point)
348
+ hex
349
+ end
237
350
 
238
- RAND_poll()
239
- @ssl_loaded = true
240
- end
351
+ # repack signature for OpenSSL 1.0.1k handling of DER signatures
352
+ # https://github.com/bitcoin/bitcoin/pull/5634/files
353
+ def self.repack_der_signature(signature)
354
+ init_ffi_ssl
241
355
 
356
+ return false if signature.empty?
242
357
 
243
- private
358
+ # New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
359
+ norm_der = FFI::MemoryPointer.new(:pointer)
360
+ sig_ptr = FFI::MemoryPointer.new(:pointer).put_pointer(
361
+ 0, FFI::MemoryPointer.from_string(signature)
362
+ )
244
363
 
245
- def bn_free_each(*list)
246
- list.each{|j| BN_free(j) }
247
- end
364
+ norm_sig = d2i_ECDSA_SIG(nil, sig_ptr, signature.bytesize)
248
365
 
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
366
+ derlen = i2d_ECDSA_SIG(norm_sig, norm_der)
367
+ ECDSA_SIG_free(norm_sig)
368
+ return false if derlen <= 0
256
369
 
257
- EC_KEY_free(eckey)
370
+ ret = norm_der.read_pointer.read_string(derlen)
371
+ OPENSSL_free(norm_der.read_pointer)
258
372
 
259
- pub_hex
260
- end
373
+ ret
261
374
  end
262
375
 
376
+ def self.init_ffi_ssl
377
+ @ssl_loaded ||= false
378
+ return if @ssl_loaded
379
+
380
+ if self.method_defined?(:OPENSSL_init_ssl)
381
+ OPENSSL_init_ssl(
382
+ OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_ENGINE_ALL_BUILTIN,
383
+ nil
384
+ )
385
+ else
386
+ SSL_library_init()
387
+ ERR_load_crypto_strings()
388
+ SSL_load_error_strings()
389
+ end
390
+
391
+ RAND_poll()
392
+ @ssl_loaded = true
393
+ end
263
394
  end
264
395
  end
data/lib/eth/secp256k1.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  module Eth
2
2
  class Secp256k1
3
-
4
3
  N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
5
-
6
4
  end
7
5
  end
data/lib/eth/sedes.rb CHANGED
@@ -35,6 +35,5 @@ module Eth
35
35
  def binary
36
36
  RLP::Sedes.binary
37
37
  end
38
-
39
38
  end
40
39
  end
data/lib/eth/tx.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Eth
2
2
  class Tx
3
-
4
3
  include RLP::Sedes::Serializable
5
4
  extend Sedes
6
5
 
@@ -13,7 +12,7 @@ module Eth
13
12
  data_bin: binary,
14
13
  v: big_endian_int,
15
14
  r: big_endian_int,
16
- s: big_endian_int
15
+ s: big_endian_int,
17
16
  })
18
17
 
19
18
  attr_writer :signature
@@ -28,7 +27,7 @@ module Eth
28
27
  end
29
28
 
30
29
  def initialize(params)
31
- fields = {v: 0, r: 0, s: 0}.merge params
30
+ fields = { v: 0, r: 0, s: 0 }.merge params
32
31
  fields[:to] = Utils.normalize_address(fields[:to])
33
32
 
34
33
  self.chain_id = (params[:chain_id]) ? params.delete(:chain_id) : Eth.chain_id
@@ -105,6 +104,7 @@ module Eth
105
104
  def hash
106
105
  "0x#{Utils.bin_to_hex Utils.keccak256_rlp(self)}"
107
106
  end
107
+
108
108
  alias_method :id, :hash
109
109
 
110
110
  def data_hex
@@ -120,7 +120,7 @@ module Eth
120
120
  end
121
121
 
122
122
  def data=(string)
123
- Eth.tx_data_hex? ? self.data_hex=(string) : self.data_bin=(string)
123
+ Eth.tx_data_hex? ? self.data_hex = (string) : self.data_bin = (string)
124
124
  end
125
125
 
126
126
  def chain_id
@@ -190,7 +190,6 @@ module Eth
190
190
  UnsignedTx
191
191
  end
192
192
  end
193
-
194
193
  end
195
194
 
196
195
  UnsignedTx = Tx.exclude([:v, :r, :s])
data/lib/eth/utils.rb CHANGED
@@ -3,11 +3,11 @@ module Eth
3
3
  extend self
4
4
 
5
5
  def normalize_address(address)
6
- if address.nil? || address == ''
7
- ''
6
+ if address.nil? || address == ""
7
+ ""
8
8
  elsif address.size == 40
9
9
  hex_to_bin address
10
- elsif address.size == 42 && address[0..1] == '0x'
10
+ elsif address.size == 42 && address[0..1] == "0x"
11
11
  hex_to_bin address[2..-1]
12
12
  else
13
13
  address
@@ -23,7 +23,7 @@ module Eth
23
23
  end
24
24
 
25
25
  def base256_to_int(str)
26
- RLP::Sedes.big_endian_int.deserialize str.sub(/\A(\x00)+/, '')
26
+ RLP::Sedes.big_endian_int.deserialize str.sub(/\A(\x00)+/, "")
27
27
  end
28
28
 
29
29
  def int_to_base256(int)
@@ -43,7 +43,7 @@ module Eth
43
43
  end
44
44
 
45
45
  def remove_hex_prefix(s)
46
- s[0,2] == '0x' ? s[2..-1] : s
46
+ s[0, 2] == "0x" ? s[2..-1] : s
47
47
  end
48
48
 
49
49
  def bin_to_prefixed_hex(binary)
@@ -89,14 +89,14 @@ module Eth
89
89
  end
90
90
 
91
91
  def zunpad(x)
92
- x.sub(/\A\x00+/, '')
92
+ x.sub(/\A\x00+/, "")
93
93
  end
94
94
 
95
- def zpad_int(n, l=32)
95
+ def zpad_int(n, l = 32)
96
96
  zpad encode_int(n), l
97
97
  end
98
98
 
99
- def zpad_hex(s, l=32)
99
+ def zpad_hex(s, l = 32)
100
100
  zpad decode_hex(s), l
101
101
  end
102
102
 
@@ -108,8 +108,6 @@ module Eth
108
108
  Address.new(address).checksummed
109
109
  end
110
110
 
111
-
112
-
113
111
  private
114
112
 
115
113
  def lpad(x, symbol, l)
@@ -124,6 +122,5 @@ module Eth
124
122
 
125
123
  int_to_base256 n
126
124
  end
127
-
128
125
  end
129
126
  end
data/lib/eth/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eth
2
- VERSION = "0.4.17"
2
+ VERSION = "0.4.18"
3
3
  end
data/lib/eth.rb CHANGED
@@ -1,20 +1,20 @@
1
- require 'digest/keccak'
2
- require 'ffi'
3
- require 'money-tree'
4
- require 'rlp'
1
+ require "digest/keccak"
2
+ require "ffi"
3
+ require "money-tree"
4
+ require "rlp"
5
5
 
6
6
  module Eth
7
7
  BYTE_ZERO = "\x00".freeze
8
- UINT_MAX = 2**256 - 1
8
+ UINT_MAX = 2 ** 256 - 1
9
9
 
10
- autoload :Address, 'eth/address'
11
- autoload :Gas, 'eth/gas'
12
- autoload :Key, 'eth/key'
13
- autoload :OpenSsl, 'eth/open_ssl'
14
- autoload :Secp256k1, 'eth/secp256k1'
15
- autoload :Sedes, 'eth/sedes'
16
- autoload :Tx, 'eth/tx'
17
- autoload :Utils, 'eth/utils'
10
+ autoload :Address, "eth/address"
11
+ autoload :Gas, "eth/gas"
12
+ autoload :Key, "eth/key"
13
+ autoload :OpenSsl, "eth/open_ssl"
14
+ autoload :Secp256k1, "eth/secp256k1"
15
+ autoload :Sedes, "eth/sedes"
16
+ autoload :Tx, "eth/tx"
17
+ autoload :Utils, "eth/utils"
18
18
 
19
19
  class << self
20
20
  def configure
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.17
4
+ version: 0.4.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Ellis
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2021-12-01 00:00:00.000000000 Z
12
+ date: 2022-01-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: keccak
@@ -45,14 +45,28 @@ dependencies:
45
45
  requirements:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: '0.10'
48
+ version: '0.11'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: '0.10'
55
+ version: '0.11'
56
+ - !ruby/object:Gem::Dependency
57
+ name: openssl
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '3.0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.0'
56
70
  - !ruby/object:Gem::Dependency
57
71
  name: rlp
58
72
  requirement: !ruby/object:Gem::Requirement
@@ -147,6 +161,7 @@ extra_rdoc_files: []
147
161
  files:
148
162
  - ".github/workflows/build.yml"
149
163
  - ".github/workflows/codeql.yml"
164
+ - ".github/workflows/docs.yml"
150
165
  - ".gitignore"
151
166
  - ".gitmodules"
152
167
  - ".rspec"
@@ -186,7 +201,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
201
  requirements:
187
202
  - - ">="
188
203
  - !ruby/object:Gem::Version
189
- version: '2.2'
204
+ version: '2.6'
190
205
  - - "<"
191
206
  - !ruby/object:Gem::Version
192
207
  version: '4.0'
@@ -196,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
211
  - !ruby/object:Gem::Version
197
212
  version: '0'
198
213
  requirements: []
199
- rubygems_version: 3.2.31
214
+ rubygems_version: 3.2.32
200
215
  signing_key:
201
216
  specification_version: 4
202
217
  summary: Simple API to sign Ethereum transactions.