ruby-ethereum 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/LICENSE +21 -0
 - data/README.md +40 -0
 - data/lib/ethereum.rb +53 -0
 - data/lib/ethereum/abi.rb +333 -0
 - data/lib/ethereum/abi/contract_translator.rb +174 -0
 - data/lib/ethereum/abi/type.rb +117 -0
 - data/lib/ethereum/account.rb +72 -0
 - data/lib/ethereum/address.rb +60 -0
 - data/lib/ethereum/base_convert.rb +53 -0
 - data/lib/ethereum/block.rb +1311 -0
 - data/lib/ethereum/block_header.rb +211 -0
 - data/lib/ethereum/bloom.rb +83 -0
 - data/lib/ethereum/cached_block.rb +36 -0
 - data/lib/ethereum/chain.rb +400 -0
 - data/lib/ethereum/constant.rb +26 -0
 - data/lib/ethereum/core_ext/array/safe_slice.rb +18 -0
 - data/lib/ethereum/core_ext/module/lru_cache.rb +20 -0
 - data/lib/ethereum/core_ext/numeric/denominations.rb +45 -0
 - data/lib/ethereum/core_ext/object/truth.rb +47 -0
 - data/lib/ethereum/db.rb +6 -0
 - data/lib/ethereum/db/base_db.rb +9 -0
 - data/lib/ethereum/db/ephem_db.rb +63 -0
 - data/lib/ethereum/db/overlay_db.rb +72 -0
 - data/lib/ethereum/db/refcount_db.rb +188 -0
 - data/lib/ethereum/env.rb +64 -0
 - data/lib/ethereum/ethash.rb +78 -0
 - data/lib/ethereum/ethash_ruby.rb +38 -0
 - data/lib/ethereum/ethash_ruby/cache.rb +47 -0
 - data/lib/ethereum/ethash_ruby/hashimoto.rb +75 -0
 - data/lib/ethereum/ethash_ruby/utils.rb +53 -0
 - data/lib/ethereum/exceptions.rb +28 -0
 - data/lib/ethereum/external_call.rb +173 -0
 - data/lib/ethereum/fast_rlp.rb +81 -0
 - data/lib/ethereum/fast_vm.rb +625 -0
 - data/lib/ethereum/fast_vm/call_data.rb +44 -0
 - data/lib/ethereum/fast_vm/message.rb +29 -0
 - data/lib/ethereum/fast_vm/state.rb +25 -0
 - data/lib/ethereum/ffi/openssl.rb +390 -0
 - data/lib/ethereum/index.rb +97 -0
 - data/lib/ethereum/log.rb +43 -0
 - data/lib/ethereum/miner.rb +84 -0
 - data/lib/ethereum/opcodes.rb +131 -0
 - data/lib/ethereum/private_key.rb +92 -0
 - data/lib/ethereum/pruning_trie.rb +28 -0
 - data/lib/ethereum/public_key.rb +88 -0
 - data/lib/ethereum/receipt.rb +53 -0
 - data/lib/ethereum/secp256k1.rb +58 -0
 - data/lib/ethereum/secure_trie.rb +49 -0
 - data/lib/ethereum/sedes.rb +42 -0
 - data/lib/ethereum/special_contract.rb +95 -0
 - data/lib/ethereum/spv.rb +79 -0
 - data/lib/ethereum/spv/proof.rb +31 -0
 - data/lib/ethereum/spv/proof_constructor.rb +19 -0
 - data/lib/ethereum/spv/proof_verifier.rb +24 -0
 - data/lib/ethereum/tester.rb +14 -0
 - data/lib/ethereum/tester/abi_contract.rb +65 -0
 - data/lib/ethereum/tester/fixture.rb +31 -0
 - data/lib/ethereum/tester/language.rb +30 -0
 - data/lib/ethereum/tester/log_recorder.rb +13 -0
 - data/lib/ethereum/tester/solidity_wrapper.rb +144 -0
 - data/lib/ethereum/tester/state.rb +194 -0
 - data/lib/ethereum/transaction.rb +196 -0
 - data/lib/ethereum/transient_trie.rb +28 -0
 - data/lib/ethereum/trie.rb +549 -0
 - data/lib/ethereum/trie/nibble_key.rb +184 -0
 - data/lib/ethereum/utils.rb +191 -0
 - data/lib/ethereum/version.rb +5 -0
 - data/lib/ethereum/vm.rb +606 -0
 - data/lib/ethereum/vm/call_data.rb +40 -0
 - data/lib/ethereum/vm/message.rb +30 -0
 - data/lib/ethereum/vm/state.rb +25 -0
 - metadata +284 -0
 
| 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding : ascii-8bit -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Ethereum
         
     | 
| 
      
 4 
     | 
    
         
            +
              class FastVM
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                class CallData
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  attr :size
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(parent_memory, offset=0, size=nil)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @data = parent_memory
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @offset = offset
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @size = size || @data.size
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @rlimit = @offset + @size
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def extract_all
         
     | 
| 
      
 18 
     | 
    
         
            +
                    d = @data.safe_slice(@offset, @size)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    d += [0] * (@size - d.size)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    Utils.int_array_to_bytes(d)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def extract32(i)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    return 0 if i >= @size
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    right = [@offset+i+32, @rlimit].min
         
     | 
| 
      
 27 
     | 
    
         
            +
                    o = @data.safe_slice(@offset+i...right)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    Utils.bytearray_to_int(o + [0]*(32-o.size))
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def extract_copy(mem, memstart, datastart, size)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    [size, @size-datastart].min.times do |i|
         
     | 
| 
      
 33 
     | 
    
         
            +
                      mem[memstart+i] = @data[@offset + datastart + i]
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    ([0, [size, @size-datastart].min].max...size).each do |i|
         
     | 
| 
      
 37 
     | 
    
         
            +
                      mem[memstart+i] = 0
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding : ascii-8bit -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Ethereum
         
     | 
| 
      
 4 
     | 
    
         
            +
              class FastVM
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                class Message
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_accessor :sender, :to, :value, :gas, :data, :depth, :logs, :code_address, :is_create
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(sender, to, value, gas, data, depth:0, code_address:nil, is_create:false)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @sender = sender
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @to = to
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @value = value
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @gas = gas
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @data = data
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @depth = depth
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @logs = []
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @code_address = code_address
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @is_create = is_create
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 23 
     | 
    
         
            +
                    "#<#{self.class.name}:#{object_id} to=#{@to[0,8]}>"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  alias :inspect :to_s
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding : ascii-8bit -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Ethereum
         
     | 
| 
      
 4 
     | 
    
         
            +
              class FastVM
         
     | 
| 
      
 5 
     | 
    
         
            +
                class State
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  attr_accessor :memory, :stack, :pc, :gas
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def initialize(**kwargs)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @memory = []
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @stack = []
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @pc = 0
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @gas = 0
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    kwargs.each do |k,v|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      class <<self
         
     | 
| 
      
 17 
     | 
    
         
            +
                        self
         
     | 
| 
      
 18 
     | 
    
         
            +
                      end.class_eval("attr_accessor :#{k}")
         
     | 
| 
      
 19 
     | 
    
         
            +
                      send :"#{k}=", v
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,390 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: ascii-8bit
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'ffi'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Ethereum
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              ##
         
     | 
| 
      
 8 
     | 
    
         
            +
              # bindings for elliptic curve inside OpenSSL
         
     | 
| 
      
 9 
     | 
    
         
            +
              #
         
     | 
| 
      
 10 
     | 
    
         
            +
              # @see # https://github.com/lian/bitcoin-ruby/blob/master/lib/bitcoin/ffi/openssl.rb
         
     | 
| 
      
 11 
     | 
    
         
            +
              #
         
     | 
| 
      
 12 
     | 
    
         
            +
              module OpenSSL_EC
         
     | 
| 
      
 13 
     | 
    
         
            +
                extend FFI::Library
         
     | 
| 
      
 14 
     | 
    
         
            +
                if FFI::Platform.windows?
         
     | 
| 
      
 15 
     | 
    
         
            +
                  ffi_lib 'libeay32', 'ssleay32'
         
     | 
| 
      
 16 
     | 
    
         
            +
                else
         
     | 
| 
      
 17 
     | 
    
         
            +
                  ffi_lib 'ssl'
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                NID_secp256k1 = 714
         
     | 
| 
      
 21 
     | 
    
         
            +
                POINT_CONVERSION_COMPRESSED = 2
         
     | 
| 
      
 22 
     | 
    
         
            +
                POINT_CONVERSION_UNCOMPRESSED = 4
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                attach_function :SSL_library_init, [], :int
         
     | 
| 
      
 25 
     | 
    
         
            +
                attach_function :ERR_load_crypto_strings, [], :void
         
     | 
| 
      
 26 
     | 
    
         
            +
                attach_function :SSL_load_error_strings, [], :void
         
     | 
| 
      
 27 
     | 
    
         
            +
                attach_function :RAND_poll, [], :int
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                attach_function :BN_CTX_free, [:pointer], :int
         
     | 
| 
      
 30 
     | 
    
         
            +
                attach_function :BN_CTX_new, [], :pointer
         
     | 
| 
      
 31 
     | 
    
         
            +
                attach_function :BN_add, [:pointer, :pointer, :pointer], :int
         
     | 
| 
      
 32 
     | 
    
         
            +
                attach_function :BN_bin2bn, [:pointer, :int, :pointer], :pointer
         
     | 
| 
      
 33 
     | 
    
         
            +
                attach_function :BN_bn2bin, [:pointer, :pointer], :int
         
     | 
| 
      
 34 
     | 
    
         
            +
                attach_function :BN_cmp, [:pointer, :pointer], :int
         
     | 
| 
      
 35 
     | 
    
         
            +
                attach_function :BN_copy, [:pointer, :pointer], :pointer
         
     | 
| 
      
 36 
     | 
    
         
            +
                attach_function :BN_dup, [:pointer], :pointer
         
     | 
| 
      
 37 
     | 
    
         
            +
                attach_function :BN_free, [:pointer], :int
         
     | 
| 
      
 38 
     | 
    
         
            +
                attach_function :BN_mod_inverse, [:pointer, :pointer, :pointer, :pointer], :pointer
         
     | 
| 
      
 39 
     | 
    
         
            +
                attach_function :BN_mod_mul, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
         
     | 
| 
      
 40 
     | 
    
         
            +
                attach_function :BN_mod_sub, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
         
     | 
| 
      
 41 
     | 
    
         
            +
                attach_function :BN_mul_word, [:pointer, :int], :int
         
     | 
| 
      
 42 
     | 
    
         
            +
                attach_function :BN_new, [], :pointer
         
     | 
| 
      
 43 
     | 
    
         
            +
                attach_function :BN_rshift, [:pointer, :pointer, :int], :int
         
     | 
| 
      
 44 
     | 
    
         
            +
                attach_function :BN_rshift1, [:pointer, :pointer], :int
         
     | 
| 
      
 45 
     | 
    
         
            +
                attach_function :BN_set_word, [:pointer, :int], :int
         
     | 
| 
      
 46 
     | 
    
         
            +
                attach_function :BN_sub, [:pointer, :pointer, :pointer], :int
         
     | 
| 
      
 47 
     | 
    
         
            +
                attach_function :EC_GROUP_get_curve_GFp, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
         
     | 
| 
      
 48 
     | 
    
         
            +
                attach_function :EC_GROUP_get_degree, [:pointer], :int
         
     | 
| 
      
 49 
     | 
    
         
            +
                attach_function :EC_GROUP_get_order, [:pointer, :pointer, :pointer], :int
         
     | 
| 
      
 50 
     | 
    
         
            +
                attach_function :EC_KEY_free, [:pointer], :int
         
     | 
| 
      
 51 
     | 
    
         
            +
                attach_function :EC_KEY_get0_group, [:pointer], :pointer
         
     | 
| 
      
 52 
     | 
    
         
            +
                attach_function :EC_KEY_get0_private_key, [:pointer], :pointer
         
     | 
| 
      
 53 
     | 
    
         
            +
                attach_function :EC_KEY_new_by_curve_name, [:int], :pointer
         
     | 
| 
      
 54 
     | 
    
         
            +
                attach_function :EC_KEY_set_conv_form, [:pointer, :int], :void
         
     | 
| 
      
 55 
     | 
    
         
            +
                attach_function :EC_KEY_set_private_key, [:pointer, :pointer], :int
         
     | 
| 
      
 56 
     | 
    
         
            +
                attach_function :EC_KEY_set_public_key,  [:pointer, :pointer], :int
         
     | 
| 
      
 57 
     | 
    
         
            +
                attach_function :EC_POINT_free, [:pointer], :int
         
     | 
| 
      
 58 
     | 
    
         
            +
                attach_function :EC_POINT_is_at_infinity, [:pointer, :pointer], :int
         
     | 
| 
      
 59 
     | 
    
         
            +
                attach_function :EC_POINT_mul, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
         
     | 
| 
      
 60 
     | 
    
         
            +
                attach_function :EC_POINT_new, [:pointer], :pointer
         
     | 
| 
      
 61 
     | 
    
         
            +
                attach_function :EC_POINT_set_compressed_coordinates_GFp, [:pointer, :pointer, :pointer, :int, :pointer], :int
         
     | 
| 
      
 62 
     | 
    
         
            +
                attach_function :d2i_ECPrivateKey, [:pointer, :pointer, :long], :pointer
         
     | 
| 
      
 63 
     | 
    
         
            +
                attach_function :i2d_ECPrivateKey, [:pointer, :pointer], :int
         
     | 
| 
      
 64 
     | 
    
         
            +
                attach_function :i2o_ECPublicKey, [:pointer, :pointer], :uint
         
     | 
| 
      
 65 
     | 
    
         
            +
                attach_function :EC_KEY_check_key, [:pointer], :uint
         
     | 
| 
      
 66 
     | 
    
         
            +
                attach_function :ECDSA_do_sign, [:pointer, :uint, :pointer], :pointer
         
     | 
| 
      
 67 
     | 
    
         
            +
                attach_function :BN_num_bits, [:pointer], :int
         
     | 
| 
      
 68 
     | 
    
         
            +
                attach_function :ECDSA_SIG_free, [:pointer], :void
         
     | 
| 
      
 69 
     | 
    
         
            +
                attach_function :EC_POINT_add, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
         
     | 
| 
      
 70 
     | 
    
         
            +
                attach_function :EC_POINT_point2hex, [:pointer, :pointer, :int, :pointer], :string
         
     | 
| 
      
 71 
     | 
    
         
            +
                attach_function :EC_POINT_hex2point, [:pointer, :string, :pointer, :pointer], :pointer
         
     | 
| 
      
 72 
     | 
    
         
            +
                attach_function :ECDSA_SIG_new, [], :pointer
         
     | 
| 
      
 73 
     | 
    
         
            +
                attach_function :d2i_ECDSA_SIG, [:pointer, :pointer, :long], :pointer
         
     | 
| 
      
 74 
     | 
    
         
            +
                attach_function :i2d_ECDSA_SIG, [:pointer, :pointer], :int
         
     | 
| 
      
 75 
     | 
    
         
            +
                attach_function :OPENSSL_free, :CRYPTO_free, [:pointer], :void
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def self.BN_num_bytes(ptr); (BN_num_bits(ptr) + 7) / 8; end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                # resolve public from private key, using ffi and libssl.so
         
     | 
| 
      
 81 
     | 
    
         
            +
                # example:
         
     | 
| 
      
 82 
     | 
    
         
            +
                #   keypair = Bitcoin.generate_key; Bitcoin::OpenSSL_EC.regenerate_key(keypair.first) == keypair
         
     | 
| 
      
 83 
     | 
    
         
            +
                def self.regenerate_key(private_key)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  private_key = [private_key].pack("H*") if private_key.bytesize >= (32*2)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  private_key_hex = private_key.unpack("H*")[0]
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  #private_key = FFI::MemoryPointer.new(:uint8, private_key.bytesize)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  #                .put_bytes(0, private_key, 0, private_key.bytesize)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  private_key = FFI::MemoryPointer.from_string(private_key)
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  init_ffi_ssl
         
     | 
| 
      
 92 
     | 
    
         
            +
                  eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  #priv_key = BN_bin2bn(private_key, private_key.size, BN_new())
         
     | 
| 
      
 94 
     | 
    
         
            +
                  priv_key = BN_bin2bn(private_key, private_key.size-1, BN_new())
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new()
         
     | 
| 
      
 97 
     | 
    
         
            +
                  EC_GROUP_get_order(group, order, ctx)
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  pub_key = EC_POINT_new(group)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
         
     | 
| 
      
 101 
     | 
    
         
            +
                  EC_KEY_set_private_key(eckey, priv_key)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  EC_KEY_set_public_key(eckey, pub_key)
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                  BN_free(order)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  BN_CTX_free(ctx)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  EC_POINT_free(pub_key)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  BN_free(priv_key)
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  length = i2d_ECPrivateKey(eckey, nil)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  buf = FFI::MemoryPointer.new(:uint8, length)
         
     | 
| 
      
 112 
     | 
    
         
            +
                  ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  priv_hex = if i2d_ECPrivateKey(eckey, ptr) == length
         
     | 
| 
      
 114 
     | 
    
         
            +
                    size = buf.get_array_of_uint8(8, 1)[0]
         
     | 
| 
      
 115 
     | 
    
         
            +
                    buf.get_array_of_uint8(9, size).pack("C*").rjust(32, "\x00").unpack("H*")[0]
         
     | 
| 
      
 116 
     | 
    
         
            +
                    #der_to_private_key( ptr.read_pointer.read_string(length).unpack("H*")[0] )
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                  if priv_hex != private_key_hex
         
     | 
| 
      
 120 
     | 
    
         
            +
                    raise "regenerated wrong private_key, raise here before generating a faulty public_key too!"
         
     | 
| 
      
 121 
     | 
    
         
            +
                  end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                  length = i2o_ECPublicKey(eckey, nil)
         
     | 
| 
      
 125 
     | 
    
         
            +
                  buf = FFI::MemoryPointer.new(:uint8, length)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  pub_hex = if i2o_ECPublicKey(eckey, ptr) == length
         
     | 
| 
      
 128 
     | 
    
         
            +
                    buf.read_string(length).unpack("H*")[0]
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                  EC_KEY_free(eckey)
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  [ priv_hex, pub_hex ]
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                # extract private key from uncompressed DER format
         
     | 
| 
      
 137 
     | 
    
         
            +
                def self.der_to_private_key(der_hex)
         
     | 
| 
      
 138 
     | 
    
         
            +
                  init_ffi_ssl
         
     | 
| 
      
 139 
     | 
    
         
            +
                  #k  = EC_KEY_new_by_curve_name(NID_secp256k1)
         
     | 
| 
      
 140 
     | 
    
         
            +
                  #kp = FFI::MemoryPointer.new(:pointer).put_pointer(0, eckey)
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                  buf = FFI::MemoryPointer.from_string([der_hex].pack("H*"))
         
     | 
| 
      
 143 
     | 
    
         
            +
                  ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                  #ec_key = d2i_ECPrivateKey(kp, ptr, buf.size-1)
         
     | 
| 
      
 146 
     | 
    
         
            +
                  ec_key = d2i_ECPrivateKey(nil, ptr, buf.size-1)
         
     | 
| 
      
 147 
     | 
    
         
            +
                  return nil if ec_key.null?
         
     | 
| 
      
 148 
     | 
    
         
            +
                  bn = EC_KEY_get0_private_key(ec_key)
         
     | 
| 
      
 149 
     | 
    
         
            +
                  BN_bn2bin(bn, buf)
         
     | 
| 
      
 150 
     | 
    
         
            +
                  buf.read_string(32).unpack("H*")[0]
         
     | 
| 
      
 151 
     | 
    
         
            +
                end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                # Given the components of a signature and a selector value, recover and
         
     | 
| 
      
 154 
     | 
    
         
            +
                # return the public key that generated the signature according to the
         
     | 
| 
      
 155 
     | 
    
         
            +
                # algorithm in SEC1v2 section 4.1.6.
         
     | 
| 
      
 156 
     | 
    
         
            +
                #
         
     | 
| 
      
 157 
     | 
    
         
            +
                # rec_id is an index from 0 to 3 that indicates which of the 4 possible
         
     | 
| 
      
 158 
     | 
    
         
            +
                # keys is the correct one. Because the key recovery operation yields
         
     | 
| 
      
 159 
     | 
    
         
            +
                # multiple potential keys, the correct key must either be stored alongside
         
     | 
| 
      
 160 
     | 
    
         
            +
                # the signature, or you must be willing to try each rec_id in turn until
         
     | 
| 
      
 161 
     | 
    
         
            +
                # you find one that outputs the key you are expecting.
         
     | 
| 
      
 162 
     | 
    
         
            +
                #
         
     | 
| 
      
 163 
     | 
    
         
            +
                # If this method returns nil, it means recovery was not possible and rec_id
         
     | 
| 
      
 164 
     | 
    
         
            +
                # should be iterated.
         
     | 
| 
      
 165 
     | 
    
         
            +
                #
         
     | 
| 
      
 166 
     | 
    
         
            +
                # Given the above two points, a correct usage of this method is inside a
         
     | 
| 
      
 167 
     | 
    
         
            +
                # for loop from 0 to 3, and if the output is nil OR a key that is not the
         
     | 
| 
      
 168 
     | 
    
         
            +
                # one you expect, you try again with the next rec_id.
         
     | 
| 
      
 169 
     | 
    
         
            +
                #
         
     | 
| 
      
 170 
     | 
    
         
            +
                #   message_hash = hash of the signed message.
         
     | 
| 
      
 171 
     | 
    
         
            +
                #   signature = the R and S components of the signature, wrapped.
         
     | 
| 
      
 172 
     | 
    
         
            +
                #   rec_id = which possible key to recover.
         
     | 
| 
      
 173 
     | 
    
         
            +
                #   is_compressed = whether or not the original pubkey was compressed.
         
     | 
| 
      
 174 
     | 
    
         
            +
                def self.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed)
         
     | 
| 
      
 175 
     | 
    
         
            +
                  return nil if rec_id < 0 or signature.bytesize != 65
         
     | 
| 
      
 176 
     | 
    
         
            +
                  init_ffi_ssl
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  signature = FFI::MemoryPointer.from_string(signature)
         
     | 
| 
      
 179 
     | 
    
         
            +
                  #signature_bn = BN_bin2bn(signature, 65, BN_new())
         
     | 
| 
      
 180 
     | 
    
         
            +
                  r = BN_bin2bn(signature[1], 32, BN_new())
         
     | 
| 
      
 181 
     | 
    
         
            +
                  s = BN_bin2bn(signature[33], 32, BN_new())
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                  n, i = 0, rec_id / 2
         
     | 
| 
      
 184 
     | 
    
         
            +
                  eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                  EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                  group = EC_KEY_get0_group(eckey)
         
     | 
| 
      
 189 
     | 
    
         
            +
                  order = BN_new()
         
     | 
| 
      
 190 
     | 
    
         
            +
                  EC_GROUP_get_order(group, order, nil)
         
     | 
| 
      
 191 
     | 
    
         
            +
                  x = BN_dup(order)
         
     | 
| 
      
 192 
     | 
    
         
            +
                  BN_mul_word(x, i)
         
     | 
| 
      
 193 
     | 
    
         
            +
                  BN_add(x, x, r)
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
                  field = BN_new()
         
     | 
| 
      
 196 
     | 
    
         
            +
                  EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                  if BN_cmp(x, field) >= 0
         
     | 
| 
      
 199 
     | 
    
         
            +
                    [r, s, order, x, field].each{|i| BN_free(i) }
         
     | 
| 
      
 200 
     | 
    
         
            +
                    EC_KEY_free(eckey)
         
     | 
| 
      
 201 
     | 
    
         
            +
                    return nil
         
     | 
| 
      
 202 
     | 
    
         
            +
                  end
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
                  big_r = EC_POINT_new(group)
         
     | 
| 
      
 205 
     | 
    
         
            +
                  EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil)
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                  big_q = EC_POINT_new(group)
         
     | 
| 
      
 208 
     | 
    
         
            +
                  n = EC_GROUP_get_degree(group)
         
     | 
| 
      
 209 
     | 
    
         
            +
                  e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new())
         
     | 
| 
      
 210 
     | 
    
         
            +
                  BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                  ctx = BN_CTX_new()
         
     | 
| 
      
 213 
     | 
    
         
            +
                  zero, rr, sor, eor = BN_new(), BN_new(), BN_new(), BN_new()
         
     | 
| 
      
 214 
     | 
    
         
            +
                  BN_set_word(zero, 0)
         
     | 
| 
      
 215 
     | 
    
         
            +
                  BN_mod_sub(e, zero, e, order, ctx)
         
     | 
| 
      
 216 
     | 
    
         
            +
                  BN_mod_inverse(rr, r, order, ctx)
         
     | 
| 
      
 217 
     | 
    
         
            +
                  BN_mod_mul(sor, s, rr, order, ctx)
         
     | 
| 
      
 218 
     | 
    
         
            +
                  BN_mod_mul(eor, e, rr, order, ctx)
         
     | 
| 
      
 219 
     | 
    
         
            +
                  EC_POINT_mul(group, big_q, eor, big_r, sor, ctx)
         
     | 
| 
      
 220 
     | 
    
         
            +
                  EC_KEY_set_public_key(eckey, big_q)
         
     | 
| 
      
 221 
     | 
    
         
            +
                  BN_CTX_free(ctx)
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                  [r, s, order, x, field, e, zero, rr, sor, eor].each{|i| BN_free(i) }
         
     | 
| 
      
 224 
     | 
    
         
            +
                  [big_r, big_q].each{|i| EC_POINT_free(i) }
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                  length = i2o_ECPublicKey(eckey, nil)
         
     | 
| 
      
 227 
     | 
    
         
            +
                  buf = FFI::MemoryPointer.new(:uint8, length)
         
     | 
| 
      
 228 
     | 
    
         
            +
                  ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
         
     | 
| 
      
 229 
     | 
    
         
            +
                  pub_hex = if i2o_ECPublicKey(eckey, ptr) == length
         
     | 
| 
      
 230 
     | 
    
         
            +
                    buf.read_string(length).unpack("H*")[0]
         
     | 
| 
      
 231 
     | 
    
         
            +
                  end
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                  EC_KEY_free(eckey)
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                  pub_hex
         
     | 
| 
      
 236 
     | 
    
         
            +
                end
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
                # Regenerate a DER-encoded signature such that the S-value complies with the BIP62
         
     | 
| 
      
 239 
     | 
    
         
            +
                # specification.
         
     | 
| 
      
 240 
     | 
    
         
            +
                #
         
     | 
| 
      
 241 
     | 
    
         
            +
                def self.signature_to_low_s(signature)
         
     | 
| 
      
 242 
     | 
    
         
            +
                  init_ffi_ssl
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                  buf = FFI::MemoryPointer.new(:uint8, 34)
         
     | 
| 
      
 245 
     | 
    
         
            +
                  temp = signature.unpack("C*")
         
     | 
| 
      
 246 
     | 
    
         
            +
                  length_r = temp[3]
         
     | 
| 
      
 247 
     | 
    
         
            +
                  length_s = temp[5+length_r]
         
     | 
| 
      
 248 
     | 
    
         
            +
                  sig = FFI::MemoryPointer.from_string(signature)
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
                  # Calculate the lower s value
         
     | 
| 
      
 251 
     | 
    
         
            +
                  s = BN_bin2bn(sig[6 + length_r], length_s, BN_new())
         
     | 
| 
      
 252 
     | 
    
         
            +
                  eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
         
     | 
| 
      
 253 
     | 
    
         
            +
                  group, order, halforder, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_new(), BN_CTX_new()
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
                  EC_GROUP_get_order(group, order, ctx)
         
     | 
| 
      
 256 
     | 
    
         
            +
                  BN_rshift1(halforder, order)
         
     | 
| 
      
 257 
     | 
    
         
            +
                  if BN_cmp(s, halforder) > 0
         
     | 
| 
      
 258 
     | 
    
         
            +
                    BN_sub(s, order, s)
         
     | 
| 
      
 259 
     | 
    
         
            +
                  end
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
                  BN_free(halforder)
         
     | 
| 
      
 262 
     | 
    
         
            +
                  BN_free(order)
         
     | 
| 
      
 263 
     | 
    
         
            +
                  BN_CTX_free(ctx)
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
                  length_s = BN_bn2bin(s, buf)
         
     | 
| 
      
 266 
     | 
    
         
            +
                  # p buf.read_string(length_s).unpack("H*")
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                  # Re-encode the signature in DER format
         
     | 
| 
      
 269 
     | 
    
         
            +
                  sig = [0x30, 0, 0x02, length_r]
         
     | 
| 
      
 270 
     | 
    
         
            +
                  sig.concat(temp.slice(4, length_r))
         
     | 
| 
      
 271 
     | 
    
         
            +
                  sig << 0x02
         
     | 
| 
      
 272 
     | 
    
         
            +
                  sig << length_s
         
     | 
| 
      
 273 
     | 
    
         
            +
                  sig.concat(buf.read_string(length_s).unpack("C*"))
         
     | 
| 
      
 274 
     | 
    
         
            +
                  sig[1] = sig.size - 2
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
                  BN_free(s)
         
     | 
| 
      
 277 
     | 
    
         
            +
                  EC_KEY_free(eckey)
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
                  sig.pack("C*")
         
     | 
| 
      
 280 
     | 
    
         
            +
                end
         
     | 
| 
      
 281 
     | 
    
         
            +
             
     | 
| 
      
 282 
     | 
    
         
            +
                def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil)
         
     | 
| 
      
 283 
     | 
    
         
            +
                  private_key = [private_key].pack("H*") if private_key.bytesize >= 64
         
     | 
| 
      
 284 
     | 
    
         
            +
                  private_key_hex = private_key.unpack("H*")[0]
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
                  public_key_hex = regenerate_key(private_key_hex).last unless public_key_hex
         
     | 
| 
      
 287 
     | 
    
         
            +
                  pubkey_compressed = (public_key_hex[0..1] == "04" ? false : true) unless pubkey_compressed
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
                  init_ffi_ssl
         
     | 
| 
      
 290 
     | 
    
         
            +
                  eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
         
     | 
| 
      
 291 
     | 
    
         
            +
                  priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new())
         
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
      
 293 
     | 
    
         
            +
                  group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new()
         
     | 
| 
      
 294 
     | 
    
         
            +
                  EC_GROUP_get_order(group, order, ctx)
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
                  pub_key = EC_POINT_new(group)
         
     | 
| 
      
 297 
     | 
    
         
            +
                  EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
         
     | 
| 
      
 298 
     | 
    
         
            +
                  EC_KEY_set_private_key(eckey, priv_key)
         
     | 
| 
      
 299 
     | 
    
         
            +
                  EC_KEY_set_public_key(eckey, pub_key)
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
                  signature = ECDSA_do_sign(hash, hash.bytesize, eckey)
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
                  BN_free(order)
         
     | 
| 
      
 304 
     | 
    
         
            +
                  BN_CTX_free(ctx)
         
     | 
| 
      
 305 
     | 
    
         
            +
                  EC_POINT_free(pub_key)
         
     | 
| 
      
 306 
     | 
    
         
            +
                  BN_free(priv_key)
         
     | 
| 
      
 307 
     | 
    
         
            +
                  EC_KEY_free(eckey)
         
     | 
| 
      
 308 
     | 
    
         
            +
             
     | 
| 
      
 309 
     | 
    
         
            +
                  buf, rec_id, head = FFI::MemoryPointer.new(:uint8, 32), nil, nil
         
     | 
| 
      
 310 
     | 
    
         
            +
                  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") }
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                  if signature.get_array_of_pointer(0, 2).all?{|i| BN_num_bits(i) <= 256 }
         
     | 
| 
      
 313 
     | 
    
         
            +
                    4.times{|i|
         
     | 
| 
      
 314 
     | 
    
         
            +
                      head = [ 27 + i + (pubkey_compressed ? 4 : 0) ].pack("C")
         
     | 
| 
      
 315 
     | 
    
         
            +
                      if public_key_hex == recover_public_key_from_signature(hash, [head, r, s].join, i, pubkey_compressed)
         
     | 
| 
      
 316 
     | 
    
         
            +
                        rec_id = i; break
         
     | 
| 
      
 317 
     | 
    
         
            +
                      end
         
     | 
| 
      
 318 
     | 
    
         
            +
                    }
         
     | 
| 
      
 319 
     | 
    
         
            +
                  end
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
                  ECDSA_SIG_free(signature)
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
                  [ head, [r,s] ].join if rec_id
         
     | 
| 
      
 324 
     | 
    
         
            +
                end
         
     | 
| 
      
 325 
     | 
    
         
            +
             
     | 
| 
      
 326 
     | 
    
         
            +
                def self.recover_compact(hash, signature)
         
     | 
| 
      
 327 
     | 
    
         
            +
                  return false if signature.bytesize != 65
         
     | 
| 
      
 328 
     | 
    
         
            +
                  #i = signature.unpack("C")[0] - 27
         
     | 
| 
      
 329 
     | 
    
         
            +
                  #pubkey = recover_public_key_from_signature(hash, signature, (i & ~4), i >= 4)
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
      
 331 
     | 
    
         
            +
                  version = signature.unpack('C')[0]
         
     | 
| 
      
 332 
     | 
    
         
            +
                  return false if version < 27 or version > 34
         
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
                  compressed = (version >= 31) ? (version -= 4; true) : false
         
     | 
| 
      
 335 
     | 
    
         
            +
                  pubkey = recover_public_key_from_signature(hash, signature, version-27, compressed)
         
     | 
| 
      
 336 
     | 
    
         
            +
                end
         
     | 
| 
      
 337 
     | 
    
         
            +
             
     | 
| 
      
 338 
     | 
    
         
            +
                # lifted from https://github.com/GemHQ/money-tree
         
     | 
| 
      
 339 
     | 
    
         
            +
                def self.ec_add(point_0, point_1)
         
     | 
| 
      
 340 
     | 
    
         
            +
                  init_ffi_ssl
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
                  eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
         
     | 
| 
      
 343 
     | 
    
         
            +
                  group = EC_KEY_get0_group(eckey)
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
                  point_0_hex = point_0.to_bn.to_s(16)
         
     | 
| 
      
 346 
     | 
    
         
            +
                  point_0_pt = EC_POINT_hex2point(group, point_0_hex, nil, nil)
         
     | 
| 
      
 347 
     | 
    
         
            +
                  point_1_hex = point_1.to_bn.to_s(16)
         
     | 
| 
      
 348 
     | 
    
         
            +
                  point_1_pt = EC_POINT_hex2point(group, point_1_hex, nil, nil)
         
     | 
| 
      
 349 
     | 
    
         
            +
             
     | 
| 
      
 350 
     | 
    
         
            +
                  sum_point = EC_POINT_new(group)
         
     | 
| 
      
 351 
     | 
    
         
            +
                  success = EC_POINT_add(group, sum_point, point_0_pt, point_1_pt, nil)
         
     | 
| 
      
 352 
     | 
    
         
            +
                  hex = EC_POINT_point2hex(group, sum_point, POINT_CONVERSION_UNCOMPRESSED, nil)
         
     | 
| 
      
 353 
     | 
    
         
            +
                  EC_KEY_free(eckey)
         
     | 
| 
      
 354 
     | 
    
         
            +
                  EC_POINT_free(sum_point)
         
     | 
| 
      
 355 
     | 
    
         
            +
                  hex
         
     | 
| 
      
 356 
     | 
    
         
            +
                end
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
                # repack signature for OpenSSL 1.0.1k handling of DER signatures
         
     | 
| 
      
 359 
     | 
    
         
            +
                # https://github.com/bitcoin/bitcoin/pull/5634/files
         
     | 
| 
      
 360 
     | 
    
         
            +
                def self.repack_der_signature(signature)
         
     | 
| 
      
 361 
     | 
    
         
            +
                  init_ffi_ssl
         
     | 
| 
      
 362 
     | 
    
         
            +
             
     | 
| 
      
 363 
     | 
    
         
            +
                  return false if signature.empty?
         
     | 
| 
      
 364 
     | 
    
         
            +
             
     | 
| 
      
 365 
     | 
    
         
            +
                  # New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
         
     | 
| 
      
 366 
     | 
    
         
            +
                  norm_der = FFI::MemoryPointer.new(:pointer)
         
     | 
| 
      
 367 
     | 
    
         
            +
                  sig_ptr  = FFI::MemoryPointer.new(:pointer).put_pointer(0, FFI::MemoryPointer.from_string(signature))
         
     | 
| 
      
 368 
     | 
    
         
            +
             
     | 
| 
      
 369 
     | 
    
         
            +
                  norm_sig = d2i_ECDSA_SIG(nil, sig_ptr, signature.bytesize)
         
     | 
| 
      
 370 
     | 
    
         
            +
             
     | 
| 
      
 371 
     | 
    
         
            +
                  derlen = i2d_ECDSA_SIG(norm_sig, norm_der)
         
     | 
| 
      
 372 
     | 
    
         
            +
                  ECDSA_SIG_free(norm_sig)
         
     | 
| 
      
 373 
     | 
    
         
            +
                  return false if derlen <= 0
         
     | 
| 
      
 374 
     | 
    
         
            +
             
     | 
| 
      
 375 
     | 
    
         
            +
                  ret = norm_der.read_pointer.read_string(derlen)
         
     | 
| 
      
 376 
     | 
    
         
            +
                  OPENSSL_free(norm_der.read_pointer)
         
     | 
| 
      
 377 
     | 
    
         
            +
             
     | 
| 
      
 378 
     | 
    
         
            +
                  ret
         
     | 
| 
      
 379 
     | 
    
         
            +
                end
         
     | 
| 
      
 380 
     | 
    
         
            +
             
     | 
| 
      
 381 
     | 
    
         
            +
                def self.init_ffi_ssl
         
     | 
| 
      
 382 
     | 
    
         
            +
                  return if @ssl_loaded
         
     | 
| 
      
 383 
     | 
    
         
            +
                  SSL_library_init()
         
     | 
| 
      
 384 
     | 
    
         
            +
                  ERR_load_crypto_strings()
         
     | 
| 
      
 385 
     | 
    
         
            +
                  SSL_load_error_strings()
         
     | 
| 
      
 386 
     | 
    
         
            +
                  RAND_poll()
         
     | 
| 
      
 387 
     | 
    
         
            +
                  @ssl_loaded = true
         
     | 
| 
      
 388 
     | 
    
         
            +
                end
         
     | 
| 
      
 389 
     | 
    
         
            +
              end
         
     | 
| 
      
 390 
     | 
    
         
            +
            end
         
     |