代码之家  ›  专栏  ›  技术社区  ›  railsguy42

如何用Ruby生成比特币地址

  •  3
  • railsguy42  · 技术社区  · 10 年前

    我正在尝试使用以下指南以ruby格式生成比特币地址:

    https://bhelx.simst.im/articles/generating-bitcoin-keys-from-scratch-with-ruby/

    但有些地方不太正确,因为生成的地址并不是很正确。

    下面是我正在使用的类:

    require 'openssl'
    require 'ecdsa'
    require 'securerandom'
    require 'base58'
    
    class BitcoinAddressGenerator
    
      ADDRESS_VERSION = '00'
    
      def self.generate_address
        # Bitcoin uses the secp256k1 curve
        curve = OpenSSL::PKey::EC.new('secp256k1')
    
        # Now we generate the public and private key together
        curve.generate_key
    
        private_key_hex = curve.private_key.to_s(16)
        puts "private_key_hex: #{private_key_hex}"
        public_key_hex = curve.public_key.to_bn.to_s(16)
        puts "public_key_hex: #{public_key_hex}"
    
        pub_key_hash = public_key_hash(public_key_hex)
        puts "pub_key_hash: #{pub_key_hash}"
    
        address = generate_address_from_public_key_hash(public_key_hash(public_key_hex))
    
        puts "address: #{address}"
      end
    
      def self.generate_address_from_public_key_hash(pub_key_hash)
        pk = ADDRESS_VERSION + pub_key_hash
        encode_base58(pub_key_hash + checksum(pub_key_hash))
      end
    
      def self.int_to_base58(int_val, leading_zero_bytes=0)
        alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
        base58_val, base = '', alpha.size
        while int_val > 0
          int_val, remainder = int_val.divmod(base)
          base58_val = alpha[remainder] + base58_val
        end
        base58_val
      end
    
      def self.encode_base58(hex)
        leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : '').size / 2
        ("1"*leading_zero_bytes) + int_to_base58( hex.to_i(16) )
      end
    
      def self.checksum(hex)
        sha256(sha256(hex))[0...8]
      end
    
      # RIPEMD-160 (160 bit) hash
      def self.rmd160(hex)
        Digest::RMD160.hexdigest([hex].pack("H*"))
      end
    
      def self.sha256(hex)
       Digest::SHA256.hexdigest([hex].pack("H*"))
      end
    
      # Turns public key into the 160 bit public key hash
      def self.public_key_hash(hex)
        rmd160(sha256(hex))
      end
    
    end
    

    它输出如下:

    private_key_hex: C96DE079BAE4877E086288DEDD6F9F70B671862B7E6E4FC0EC401CADB81EDF45
    public_key_hex: 0422435DF80F62E643D3CFBA66194052EC9ED0DFB47A1B26A4731079A5FF84FBF98FF0A540B6981D75BA789E6192F3B38BABEF6B0286CAEB4CAFCB51BB96D97B46
    public_key_hash: db34927cc5ec0066411f366d9a95f9c6369c6e1d
    address: Lz3xnxx6Uh79PEzPpWSMMZJVWR36hJgVL
    

    如果我把这个地址插入区块链。info和类似工具显示这是一个无效地址。

    任何帮助都将不胜感激。

    1 回复  |  直到 10 年前
        1
  •  2
  •   matt    10 年前

    在您的 generate_address_from_public_key_hash 方法,则校验和应位于哈希之上 包括地址前缀 。您实际上没有使用 pk 赋值后的一刻,变量就变了。代码应类似于:

    def self.generate_address_from_public_key_hash(pub_key_hash)
      pk = ADDRESS_VERSION + pub_key_hash
      encode_base58(pk + checksum(pk)) # Using pk here, not pub_key_hash
    end
    

    这个错误似乎也在你链接的页面上,我猜作者一定是复制/粘贴错误。


    顺便说一句,将所有内容保留在十六进制字符串中并来回解码似乎是一种奇怪的方法。我本以为使用原始二进制字符串会更容易,并且在打印值时只编码为十六进制。