You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby生成Bitcoin Testnet地址无效问题求助

修复比特币测试网地址生成无效的问题

问题描述

尝试用Ruby生成比特币测试网地址,但生成的地址在blockchain.info等工具中被标记为无效,原代码如下:

require 'openssl'
require 'ecdsa'
require 'securerandom'
require 'base58'

class BitcoinAddressGenerator

  ADDRESS_VERSION = '6f'

  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(pk + checksum(pk))
  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

问题根源

核心错误在于公钥格式不符合比特币规范:
比特币要求非压缩公钥必须以04开头,后面拼接64位的x坐标和64位的y坐标(共130位十六进制字符)。但原代码中curve.public_key.to_bn.to_s(16)仅返回x和y的拼接值,缺少04前缀,导致后续公钥哈希计算完全错误,最终生成的地址无效。

修复方案

修改公钥生成逻辑补全04前缀,同时优化base58编码的前导零处理,避免格式计算错误。

修复后的代码

require 'openssl'
require 'ecdsa'
require 'securerandom'
require 'base58'
require 'digest' # 确保引入Digest模块

class BitcoinAddressGenerator

  ADDRESS_VERSION = '6f' # 测试网地址版本字节(十六进制)

  def self.generate_address
    curve = OpenSSL::PKey::EC.new('secp256k1')
    curve.generate_key

    # 补全私钥到64位标准格式
    private_key_hex = curve.private_key.to_s(16).rjust(64, '0')
    puts "private_key_hex: #{private_key_hex}"

    # 生成符合比特币规范的非压缩公钥(04前缀 + x坐标 + y坐标)
    pub_point = curve.public_key.public_key
    x_hex = pub_point.x.to_s(16).rjust(64, '0')
    y_hex = pub_point.y.to_s(16).rjust(64, '0')
    public_key_hex = "04#{x_hex}#{y_hex}"
    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(pub_key_hash)
    puts "address: #{address}"
  end

  def self.generate_address_from_public_key_hash(pub_key_hash)
    versioned_hash = ADDRESS_VERSION + pub_key_hash
    checksum = checksum(versioned_hash)
    encode_base58(versioned_hash + checksum)
  end

  def self.encode_base58(hex)
    # 转字节数组统计前导零,避免字符串匹配误差
    bytes = [hex].pack('H*')
    leading_zeros = bytes.bytes.take_while { |b| b == 0 }.size
    
    int_val = hex.to_i(16)
    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

    ('1' * leading_zeros) + base58_val
  end

  def self.checksum(hex)
    sha256(sha256(hex))[0...8]
  end

  def self.rmd160(hex)
    Digest::RMD160.hexdigest([hex].pack('H*'))
  end

  def self.sha256(hex)
    Digest::SHA256.hexdigest([hex].pack('H*'))
  end

  def self.public_key_hash(hex)
    rmd160(sha256(hex))
  end

end

关键修改点

  1. 公钥规范补全:从EC点中提取x、y坐标,手动拼接04前缀,生成符合比特币标准的非压缩公钥。
  2. 私钥格式修正:将私钥补全到64位,匹配比特币私钥的标准长度。
  3. base58编码优化:通过字节数组统计前导零字节数,避免原字符串匹配方式可能出现的计算误差。

验证方法

运行修复后的代码,生成的地址应以m或n开头(比特币测试网地址特征),可直接在测试网区块浏览器中验证有效性。

内容的提问来源于stack exchange,提问作者Nitin Arora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 03:48:08