From e084e4fc7d0c7937dd64879f9e262e1dd2c1a33c Mon Sep 17 00:00:00 2001 From: /raw PONG _GHMoaCXLT <58883403+q9f@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:02:55 +0100 Subject: [PATCH 1/8] gem: add openssl dependency --- eth.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/eth.gemspec b/eth.gemspec index 4caee05..d87b03c 100644 --- a/eth.gemspec +++ b/eth.gemspec @@ -33,6 +33,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'keccak', '~> 1.2' spec.add_dependency 'ffi', '~> 1.15' spec.add_dependency 'money-tree', '~> 0.10' + spec.add_dependency 'openssl', '~> 2.2' spec.add_dependency 'rlp', '~> 0.7' spec.add_dependency 'scrypt', '~> 3.0' From e5edef7aa489c8d67c36bb52f37ed608bbe2576b Mon Sep 17 00:00:00 2001 From: /raw PONG _GHMoaCXLT <58883403+q9f@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:03:21 +0100 Subject: [PATCH 2/8] gem: bump version for next release --- lib/eth/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eth/version.rb b/lib/eth/version.rb index c12db39..d5a1caa 100644 --- a/lib/eth/version.rb +++ b/lib/eth/version.rb @@ -1,3 +1,3 @@ module Eth - VERSION = "0.4.16" + VERSION = "0.4.17" end From e41d3b072383fcb86cbbf017ce2737805402c272 Mon Sep 17 00:00:00 2001 From: /raw PONG _GHMoaCXLT <58883403+q9f@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:04:02 +0100 Subject: [PATCH 3/8] lib: update openssl class to allow for libressl compatibility --- lib/eth/open_ssl.rb | 462 ++++++++++++++++++++++++++++---------------- 1 file changed, 294 insertions(+), 168 deletions(-) diff --git a/lib/eth/open_ssl.rb b/lib/eth/open_ssl.rb index a8ead15..7dc421b 100644 --- a/lib/eth/open_ssl.rb +++ b/lib/eth/open_ssl.rb @@ -1,28 +1,22 @@ # originally lifted from https://github.com/lian/bitcoin-ruby # thanks to everyone there for figuring this out +# encoding: ascii-8bit + +require 'openssl' +require 'ffi' + module Eth class OpenSsl extend FFI::Library - if FFI::Platform.windows? - ffi_lib 'libeay32', 'ssleay32' - else - ffi_lib [ - 'libssl.so.1.1.0', 'libssl.so.1.1', - 'libssl.so.1.0.0', 'libssl.so.10', - 'ssl' - ] - end + # Use the library loaded by the extension require above. + ffi_lib FFI::CURRENT_PROCESS NID_secp256k1 = 714 POINT_CONVERSION_COMPRESSED = 2 POINT_CONVERSION_UNCOMPRESSED = 4 - # OpenSSL 1.1.0 version as a numerical version value as defined in: - # https://www.openssl.org/docs/man1.1.0/man3/OpenSSL_version.html - VERSION_1_1_0_NUM = 0x10100000 - # OpenSSL 1.1.0 engine constants, taken from: # https://github.com/openssl/openssl/blob/2be8c56a39b0ec2ec5af6ceaf729df154d784a43/include/openssl/crypto.h OPENSSL_INIT_ENGINE_RDRAND = 0x00000200 @@ -50,215 +44,347 @@ class OpenSsl attach_function :SSLeay, [], :long end - # Returns the version of SSL present. - # - # @return [Integer] version number as an integer. - def self.version - if self.respond_to?(:OpenSSL_version_num) - OpenSSL_version_num() - else - SSLeay() - end - end - - if version >= VERSION_1_1_0_NUM + begin # Initialization procedure for the library was changed in OpenSSL 1.1.0 attach_function :OPENSSL_init_ssl, [:uint64, :pointer], :int - else + rescue FFI::NotFoundError attach_function :SSL_library_init, [], :int attach_function :ERR_load_crypto_strings, [], :void attach_function :SSL_load_error_strings, [], :void end attach_function :RAND_poll, [], :int + attach_function :BN_CTX_free, [:pointer], :int attach_function :BN_CTX_new, [], :pointer - attach_function :BN_add, [:pointer, :pointer, :pointer], :int - attach_function :BN_bin2bn, [:pointer, :int, :pointer], :pointer - attach_function :BN_bn2bin, [:pointer, :pointer], :int - attach_function :BN_cmp, [:pointer, :pointer], :int + attach_function :BN_add, %i[pointer pointer pointer], :int + attach_function :BN_bin2bn, %i[pointer int pointer], :pointer + attach_function :BN_bn2bin, %i[pointer pointer], :int + attach_function :BN_cmp, %i[pointer pointer], :int attach_function :BN_dup, [:pointer], :pointer attach_function :BN_free, [:pointer], :int - attach_function :BN_mod_inverse, [:pointer, :pointer, :pointer, :pointer], :pointer - attach_function :BN_mod_mul, [:pointer, :pointer, :pointer, :pointer, :pointer], :int - attach_function :BN_mod_sub, [:pointer, :pointer, :pointer, :pointer, :pointer], :int - attach_function :BN_mul_word, [:pointer, :int], :int + attach_function :BN_mod_inverse, %i[pointer pointer pointer pointer], :pointer + attach_function :BN_mod_mul, %i[pointer pointer pointer pointer pointer], :int + attach_function :BN_mod_sub, %i[pointer pointer pointer pointer pointer], :int + attach_function :BN_mul_word, %i[pointer int], :int attach_function :BN_new, [], :pointer - attach_function :BN_num_bits, [:pointer], :int - attach_function :BN_rshift, [:pointer, :pointer, :int], :int - attach_function :BN_set_word, [:pointer, :int], :int - attach_function :ECDSA_SIG_free, [:pointer], :void - attach_function :ECDSA_do_sign, [:pointer, :uint, :pointer], :pointer - attach_function :EC_GROUP_get_curve_GFp, [:pointer, :pointer, :pointer, :pointer, :pointer], :int + attach_function :BN_rshift, %i[pointer pointer int], :int + attach_function :BN_rshift1, %i[pointer pointer], :int + attach_function :BN_set_word, %i[pointer int], :int + attach_function :BN_sub, %i[pointer pointer pointer], :int + attach_function :EC_GROUP_get_curve_GFp, %i[pointer pointer pointer pointer pointer], :int attach_function :EC_GROUP_get_degree, [:pointer], :int - attach_function :EC_GROUP_get_order, [:pointer, :pointer, :pointer], :int + attach_function :EC_GROUP_get_order, %i[pointer pointer pointer], :int attach_function :EC_KEY_free, [:pointer], :int attach_function :EC_KEY_get0_group, [:pointer], :pointer + attach_function :EC_KEY_get0_private_key, [:pointer], :pointer attach_function :EC_KEY_new_by_curve_name, [:int], :pointer - attach_function :EC_KEY_set_conv_form, [:pointer, :int], :void - attach_function :EC_KEY_set_private_key, [:pointer, :pointer], :int - attach_function :EC_KEY_set_public_key, [:pointer, :pointer], :int + attach_function :EC_KEY_set_conv_form, %i[pointer int], :void + attach_function :EC_KEY_set_private_key, %i[pointer pointer], :int + attach_function :EC_KEY_set_public_key, %i[pointer pointer], :int attach_function :EC_POINT_free, [:pointer], :int - attach_function :EC_POINT_mul, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int + attach_function :EC_POINT_mul, %i[pointer pointer pointer pointer pointer pointer], :int attach_function :EC_POINT_new, [:pointer], :pointer - attach_function :EC_POINT_set_compressed_coordinates_GFp, [:pointer, :pointer, :pointer, :int, :pointer], :int - attach_function :i2o_ECPublicKey, [:pointer, :pointer], :uint + attach_function :EC_POINT_set_compressed_coordinates_GFp, + %i[pointer pointer pointer int pointer], :int + attach_function :i2o_ECPublicKey, %i[pointer pointer], :uint + attach_function :ECDSA_do_sign, %i[pointer uint pointer], :pointer + attach_function :BN_num_bits, [:pointer], :int + attach_function :ECDSA_SIG_free, [:pointer], :void + attach_function :EC_POINT_add, %i[pointer pointer pointer pointer pointer], :int + attach_function :EC_POINT_point2hex, %i[pointer pointer int pointer], :string + attach_function :EC_POINT_hex2point, %i[pointer string pointer pointer], :pointer + attach_function :d2i_ECDSA_SIG, %i[pointer pointer long], :pointer + attach_function :i2d_ECDSA_SIG, %i[pointer pointer], :int + attach_function :OPENSSL_free, :CRYPTO_free, [:pointer], :void + + def self.BN_num_bytes(ptr) # rubocop:disable Naming/MethodName + (BN_num_bits(ptr) + 7) / 8 + end - class << self - def BN_num_bytes(ptr) - (BN_num_bits(ptr) + 7) / 8 + # resolve public from private key, using ffi and libssl.so + # example: + # keypair = Bitcoin.generate_key; Bitcoin::OpenSSL_EC.regenerate_key(keypair.first) == keypair + def self.regenerate_key(private_key) + private_key = [private_key].pack('H*') if private_key.bytesize >= (32 * 2) + private_key_hex = private_key.unpack('H*')[0] + + group = OpenSSL::PKey::EC::Group.new('secp256k1') + key = OpenSSL::PKey::EC.new(group) + key.private_key = OpenSSL::BN.new(private_key_hex, 16) + key.public_key = group.generator.mul(key.private_key) + + priv_hex = key.private_key.to_bn.to_s(16).downcase.rjust(64, '0') + if priv_hex != private_key_hex + raise 'regenerated wrong private_key, raise here before generating a faulty public_key too!' end - def sign_compact(hash, private_key, public_key_hex) - private_key = [private_key].pack("H*") if private_key.bytesize >= 64 - pubkey_compressed = false + [priv_hex, key.public_key.to_bn.to_s(16).downcase] + end - init_ffi_ssl - eckey = EC_KEY_new_by_curve_name(NID_secp256k1) - priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new()) + # Given the components of a signature and a selector value, recover and + # return the public key that generated the signature according to the + # algorithm in SEC1v2 section 4.1.6. + # + # rec_id is an index from 0 to 3 that indicates which of the 4 possible + # keys is the correct one. Because the key recovery operation yields + # multiple potential keys, the correct key must either be stored alongside + # the signature, or you must be willing to try each rec_id in turn until + # you find one that outputs the key you are expecting. + # + # If this method returns nil, it means recovery was not possible and rec_id + # should be iterated. + # + # Given the above two points, a correct usage of this method is inside a + # for loop from 0 to 3, and if the output is nil OR a key that is not the + # one you expect, you try again with the next rec_id. + # + # message_hash = hash of the signed message. + # signature = the R and S components of the signature, wrapped. + # rec_id = which possible key to recover. + # is_compressed = whether or not the original pubkey was compressed. + def self.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed) + return nil if rec_id < 0 || signature.bytesize != 65 + init_ffi_ssl + + signature = FFI::MemoryPointer.from_string(signature) + # signature_bn = BN_bin2bn(signature, 65, BN_new()) + r = BN_bin2bn(signature[1], 32, BN_new()) + s = BN_bin2bn(signature[33], 32, BN_new()) + + i = rec_id / 2 + eckey = EC_KEY_new_by_curve_name(NID_secp256k1) + + EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed + + group = EC_KEY_get0_group(eckey) + order = BN_new() + EC_GROUP_get_order(group, order, nil) + x = BN_dup(order) + BN_mul_word(x, i) + BN_add(x, x, r) + + field = BN_new() + EC_GROUP_get_curve_GFp(group, field, nil, nil, nil) + + if BN_cmp(x, field) >= 0 + [r, s, order, x, field].each { |item| BN_free(item) } + EC_KEY_free(eckey) + return nil + end + + big_r = EC_POINT_new(group) + EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil) + + big_q = EC_POINT_new(group) + n = EC_GROUP_get_degree(group) + e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new()) + BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n + + ctx = BN_CTX_new() + zero = BN_new() + rr = BN_new() + sor = BN_new() + eor = BN_new() + BN_set_word(zero, 0) + BN_mod_sub(e, zero, e, order, ctx) + BN_mod_inverse(rr, r, order, ctx) + BN_mod_mul(sor, s, rr, order, ctx) + BN_mod_mul(eor, e, rr, order, ctx) + EC_POINT_mul(group, big_q, eor, big_r, sor, ctx) + EC_KEY_set_public_key(eckey, big_q) + BN_CTX_free(ctx) + + [r, s, order, x, field, e, zero, rr, sor, eor].each { |item| BN_free(item) } + [big_r, big_q].each { |item| EC_POINT_free(item) } + + length = i2o_ECPublicKey(eckey, nil) + buf = FFI::MemoryPointer.new(:uint8, length) + ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf) + pub_hex = buf.read_string(length).unpack('H*')[0] if i2o_ECPublicKey(eckey, ptr) == length + + EC_KEY_free(eckey) + + pub_hex + end - group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new() - EC_GROUP_get_order(group, order, ctx) + # Regenerate a DER-encoded signature such that the S-value complies with the BIP62 + # specification. + # + def self.signature_to_low_s(signature) + init_ffi_ssl + + buf = FFI::MemoryPointer.new(:uint8, 34) + temp = signature.unpack('C*') + length_r = temp[3] + length_s = temp[5 + length_r] + sig = FFI::MemoryPointer.from_string(signature) + + # Calculate the lower s value + s = BN_bin2bn(sig[6 + length_r], length_s, BN_new()) + eckey = EC_KEY_new_by_curve_name(NID_secp256k1) + group = EC_KEY_get0_group(eckey) + order = BN_new() + halforder = BN_new() + ctx = BN_CTX_new() + + EC_GROUP_get_order(group, order, ctx) + BN_rshift1(halforder, order) + BN_sub(s, order, s) if BN_cmp(s, halforder) > 0 + + BN_free(halforder) + BN_free(order) + BN_CTX_free(ctx) + + length_s = BN_bn2bin(s, buf) + # p buf.read_string(length_s).unpack("H*") + + # Re-encode the signature in DER format + sig = [0x30, 0, 0x02, length_r] + sig.concat(temp.slice(4, length_r)) + sig << 0x02 + sig << length_s + sig.concat(buf.read_string(length_s).unpack('C*')) + sig[1] = sig.size - 2 + + BN_free(s) + EC_KEY_free(eckey) + + sig.pack('C*') + end - pub_key = EC_POINT_new(group) - EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx) - EC_KEY_set_private_key(eckey, priv_key) - EC_KEY_set_public_key(eckey, pub_key) + def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil) + msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash) - signature = ECDSA_do_sign(hash, hash.bytesize, eckey) + private_key = [private_key].pack('H*') if private_key.bytesize >= 64 + private_key_hex = private_key.unpack('H*')[0] - BN_free(order) - BN_CTX_free(ctx) - EC_POINT_free(pub_key) - BN_free(priv_key) - EC_KEY_free(eckey) + public_key_hex ||= regenerate_key(private_key_hex).last + pubkey_compressed ||= public_key_hex[0..1] != '04' - buf, rec_id, head = FFI::MemoryPointer.new(:uint8, 32), nil, nil - 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") } + init_ffi_ssl + eckey = EC_KEY_new_by_curve_name(NID_secp256k1) + priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new()) - if signature.get_array_of_pointer(0, 2).all?{|i| BN_num_bits(i) <= 256 } - 4.times{|i| - head = [ Eth.v_base + i ].pack("C") - if public_key_hex == recover_public_key_from_signature(hash, [head, r, s].join, i, pubkey_compressed) - rec_id = i; break - end - } - end + group = EC_KEY_get0_group(eckey) + order = BN_new() + ctx = BN_CTX_new() + EC_GROUP_get_order(group, order, ctx) - ECDSA_SIG_free(signature) + pub_key = EC_POINT_new(group) + EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx) + EC_KEY_set_private_key(eckey, priv_key) + EC_KEY_set_public_key(eckey, pub_key) - [ head, [r,s] ].join if rec_id - end + signature = ECDSA_do_sign(msg32, msg32.size, eckey) - def recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed) - return nil if rec_id < 0 or signature.bytesize != 65 - init_ffi_ssl + BN_free(order) + BN_CTX_free(ctx) + EC_POINT_free(pub_key) + BN_free(priv_key) + EC_KEY_free(eckey) - signature = FFI::MemoryPointer.from_string(signature) - r = BN_bin2bn(signature[1], 32, BN_new()) - s = BN_bin2bn(signature[33], 32, BN_new()) + buf = FFI::MemoryPointer.new(:uint8, 32) + head = nil + r, s = signature.get_array_of_pointer(0, 2).map do |i| + BN_bn2bin(i, buf) + buf.read_string(BN_num_bytes(i)).rjust(32, "\x00") + end - _n, i = 0, rec_id / 2 - eckey = EC_KEY_new_by_curve_name(NID_secp256k1) + rec_id = nil + if signature.get_array_of_pointer(0, 2).all? { |i| BN_num_bits(i) <= 256 } + 4.times do |i| + head = [27 + i + (pubkey_compressed ? 4 : 0)].pack('C') + recovered_key = recover_public_key_from_signature( + msg32.read_string(32), [head, r, s].join, i, pubkey_compressed + ) + if public_key_hex == recovered_key + rec_id = i + break + end + end + end - EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed + ECDSA_SIG_free(signature) - group = EC_KEY_get0_group(eckey) - order = BN_new() - EC_GROUP_get_order(group, order, nil) - x = BN_dup(order) - BN_mul_word(x, i) - BN_add(x, x, r) + [head, [r, s]].join if rec_id + end - field = BN_new() - EC_GROUP_get_curve_GFp(group, field, nil, nil, nil) + def self.recover_compact(hash, signature) + return false if signature.bytesize != 65 + msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash) - if BN_cmp(x, field) >= 0 - bn_free_each r, s, order, x, field - EC_KEY_free(eckey) - return nil - end + version = signature.unpack('C')[0] + return false if version < 27 || version > 34 - big_r = EC_POINT_new(group) - EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil) - - big_q = EC_POINT_new(group) - n = EC_GROUP_get_degree(group) - e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new()) - BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n - - ctx = BN_CTX_new() - zero, rr, sor, eor = BN_new(), BN_new(), BN_new(), BN_new() - BN_set_word(zero, 0) - BN_mod_sub(e, zero, e, order, ctx) - BN_mod_inverse(rr, r, order, ctx) - BN_mod_mul(sor, s, rr, order, ctx) - BN_mod_mul(eor, e, rr, order, ctx) - EC_POINT_mul(group, big_q, eor, big_r, sor, ctx) - EC_KEY_set_public_key(eckey, big_q) - BN_CTX_free(ctx) - - bn_free_each r, s, order, x, field, e, zero, rr, sor, eor - [big_r, big_q].each{|j| EC_POINT_free(j) } - - recover_public_hex eckey - end + compressed = version >= 31 + version -= 4 if compressed - def recover_compact(hash, signature) - return false if signature.bytesize != 65 + recover_public_key_from_signature(msg32.read_string(32), signature, version - 27, compressed) + end - version = signature.unpack('C')[0] + # lifted from https://github.com/GemHQ/money-tree + def self.ec_add(point0, point1) + init_ffi_ssl - # Version of signature should be 27 or 28, but 0 and 1 are also possible versions - # which can show up in Ledger hardwallet signings - if version < 27 - version += 27 - end + eckey = EC_KEY_new_by_curve_name(NID_secp256k1) + group = EC_KEY_get0_group(eckey) - v_base = Eth.replayable_v?(version) ? Eth.replayable_chain_id : Eth.v_base + point_0_hex = point0.to_bn.to_s(16) + point_0_pt = EC_POINT_hex2point(group, point_0_hex, nil, nil) + point_1_hex = point1.to_bn.to_s(16) + point_1_pt = EC_POINT_hex2point(group, point_1_hex, nil, nil) - return false if version < v_base + sum_point = EC_POINT_new(group) + EC_POINT_add(group, sum_point, point_0_pt, point_1_pt, nil) + hex = EC_POINT_point2hex(group, sum_point, POINT_CONVERSION_UNCOMPRESSED, nil) + EC_KEY_free(eckey) + EC_POINT_free(sum_point) + hex + end - recover_public_key_from_signature(hash, signature, (version - v_base), false) - end + # repack signature for OpenSSL 1.0.1k handling of DER signatures + # https://github.com/bitcoin/bitcoin/pull/5634/files + def self.repack_der_signature(signature) + init_ffi_ssl - def init_ffi_ssl - return if @ssl_loaded - if version >= VERSION_1_1_0_NUM - OPENSSL_init_ssl( - OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_ENGINE_ALL_BUILTIN, - nil - ) - else - SSL_library_init() - ERR_load_crypto_strings() - SSL_load_error_strings() - end + return false if signature.empty? - RAND_poll() - @ssl_loaded = true - end + # New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. + norm_der = FFI::MemoryPointer.new(:pointer) + sig_ptr = FFI::MemoryPointer.new(:pointer).put_pointer( + 0, FFI::MemoryPointer.from_string(signature) + ) + norm_sig = d2i_ECDSA_SIG(nil, sig_ptr, signature.bytesize) - private + derlen = i2d_ECDSA_SIG(norm_sig, norm_der) + ECDSA_SIG_free(norm_sig) + return false if derlen <= 0 - def bn_free_each(*list) - list.each{|j| BN_free(j) } - end + ret = norm_der.read_pointer.read_string(derlen) + OPENSSL_free(norm_der.read_pointer) - def recover_public_hex(eckey) - length = i2o_ECPublicKey(eckey, nil) - buf = FFI::MemoryPointer.new(:uint8, length) - ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf) - pub_hex = if i2o_ECPublicKey(eckey, ptr) == length - buf.read_string(length).unpack("H*")[0] - end + ret + end - EC_KEY_free(eckey) + def self.init_ffi_ssl + @ssl_loaded ||= false + return if @ssl_loaded - pub_hex + if self.method_defined?(:OPENSSL_init_ssl) + OPENSSL_init_ssl( + OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_ENGINE_ALL_BUILTIN, + nil + ) + else + SSL_library_init() + ERR_load_crypto_strings() + SSL_load_error_strings() end - end + RAND_poll() + @ssl_loaded = true + end end end From 9dab413024ba468025983c3f370c28188d6c36c9 Mon Sep 17 00:00:00 2001 From: /raw PONG _GHMoaCXLT <58883403+q9f@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:05:34 +0100 Subject: [PATCH 4/8] lib: allow for hardcoded version bytes of ledger signatures --- lib/eth/open_ssl.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/eth/open_ssl.rb b/lib/eth/open_ssl.rb index 7dc421b..05b7782 100644 --- a/lib/eth/open_ssl.rb +++ b/lib/eth/open_ssl.rb @@ -315,6 +315,13 @@ def self.recover_compact(hash, signature) msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash) version = signature.unpack('C')[0] + + # Version of signature should be 27 or 28, but 0 and 1 are also possible versions + # which can show up in Ledger hardwallet signings + if version < 27 + version += 27 + end + return false if version < 27 || version > 34 compressed = version >= 31 From 79385d1f97c2aab29e1993710719c0bfcc4f1625 Mon Sep 17 00:00:00 2001 From: /raw PONG _GHMoaCXLT <58883403+q9f@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:16:14 +0100 Subject: [PATCH 5/8] ci: enable macos-latest --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 19a60ef..307d5be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: [ubuntu-latest, macos-latest] steps: - uses: actions/checkout@v2 - uses: ruby/setup-ruby@v1 From e9ba5a42514a8f8e12c5a5cbb17d7ba3db101304 Mon Sep 17 00:00:00 2001 From: /raw PONG _GHMoaCXLT <58883403+q9f@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:21:58 +0100 Subject: [PATCH 6/8] ci: use matrix for os and ruby --- .github/workflows/build.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 307d5be..5990516 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,12 +11,22 @@ on: jobs: build: - runs-on: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + ruby: ['2.7', '3.0'] steps: - uses: actions/checkout@v2 - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.0 + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Brew Automake + run: | + brew install automake + if: startsWith(matrix.os, 'macOS') - name: Install Dependencies run: | git submodule update --init From 8903f1aaf1596ec68821a86addf90bc3596a0ad2 Mon Sep 17 00:00:00 2001 From: /raw PONG _GHMoaCXLT <58883403+q9f@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:25:36 +0100 Subject: [PATCH 7/8] ci: use bundler to exec rspec --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5990516..7c4724f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,4 +33,4 @@ jobs: bundle install - name: Run Tests run: | - rspec + bundle exec rspec From 08bf75612f742c93c9b88231a5b5a8a2d0086a23 Mon Sep 17 00:00:00 2001 From: Muhammad Abdullah Khalil Date: Tue, 4 Jan 2022 18:15:58 +0500 Subject: [PATCH 8/8] Mabdullahlkhalil/gemdependacies (#73) * gems: bump keccak to 1.3.0 (#69) * Gems: bump version to 0.4.17 (#70) * Gems: bump version to 0.4.17 * docs: update changelog * Dependancy money tree changed * Adding Money tree dependanccy * mabdullahlkhalil/gemdependacies * Gem dependanct * Gem dependanct * Gem dependacy * mabdullahlkhalil/gemdependacies * Gem dependacy * Money Tree fix * Update eth.gemspec * Update eth.gemspec --- CHANGELOG.md | 5 +++++ Gemfile | 3 ++- eth.gemspec | 8 ++++---- lib/eth.rb | 2 +- lib/eth/utils.rb | 5 ++--- lib/eth/version.rb | 2 +- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c95a56e..db568cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Unreleased +## [0.4.17] +### Changed +- Gems: bump version to 0.4.17 [#70](https://github.com/se3000/ruby-eth/pull/70) +- Gems: bump keccak to 1.3.0 [#69](https://github.com/se3000/ruby-eth/pull/69) + ## [0.4.16] ### Changed - Docs: update changelog [#65](https://github.com/se3000/ruby-eth/pull/65) diff --git a/Gemfile b/Gemfile index b4ca1f3..66378ac 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,7 @@ # frozen_string_literal: true -source 'https://rubygems.org' +gem 'money-tree', git: 'https://github.com/GemHQ/money-tree.git' +source 'https://rubygems.org' # Specify your gem's dependencies in eth.gemspec gemspec diff --git a/eth.gemspec b/eth.gemspec index d87b03c..702e389 100644 --- a/eth.gemspec +++ b/eth.gemspec @@ -30,15 +30,15 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.test_files = spec.files.grep %r{^(test|spec|features)/} - spec.add_dependency 'keccak', '~> 1.2' + spec.add_dependency 'keccak', '~> 1.3' spec.add_dependency 'ffi', '~> 1.15' - spec.add_dependency 'money-tree', '~> 0.10' - spec.add_dependency 'openssl', '~> 2.2' + spec.add_dependency 'money-tree', '~> 0.11' + spec.add_dependency 'openssl', '~> 3.0' spec.add_dependency 'rlp', '~> 0.7' spec.add_dependency 'scrypt', '~> 3.0' spec.platform = Gem::Platform::RUBY - spec.required_ruby_version = ">= 2.2", "< 4.0" + spec.required_ruby_version = ">= 2.6", "< 4.0" spec.add_development_dependency 'bundler', '~> 2.2' spec.add_development_dependency 'pry', '~> 0.14' diff --git a/lib/eth.rb b/lib/eth.rb index 74710d3..4e7fcfc 100644 --- a/lib/eth.rb +++ b/lib/eth.rb @@ -1,4 +1,4 @@ -require 'digest/sha3' +require 'digest/keccak' require 'ffi' require 'money-tree' require 'rlp' diff --git a/lib/eth/utils.rb b/lib/eth/utils.rb index ece7369..44a59d8 100644 --- a/lib/eth/utils.rb +++ b/lib/eth/utils.rb @@ -1,6 +1,5 @@ module Eth module Utils - extend self def normalize_address(address) @@ -66,11 +65,11 @@ def sha256(x) end def keccak256(x) - Digest::SHA3.new(256).digest(x) + Digest::Keccak.new(256).digest(x) end def keccak512(x) - Digest::SHA3.new(512).digest(x) + Digest::Keccak.new(512).digest(x) end def keccak256_rlp(x) diff --git a/lib/eth/version.rb b/lib/eth/version.rb index d5a1caa..855c447 100644 --- a/lib/eth/version.rb +++ b/lib/eth/version.rb @@ -1,3 +1,3 @@ module Eth - VERSION = "0.4.17" + VERSION = "0.4.18" end