Nitin Arora
Nitin Arora

Reputation: 1

Problem generating Bitcoin Testnet Address in Ruby

I'm trying to generate Bitcoin testnet addresses in ruby by using this guide:

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

Here's the class I'm using:

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

If I plug this address into blockchain.info and similar tools it says that it's an invalid address.

Any help would be greatly appreciated.

Upvotes: -1

Views: 114

Answers (2)

Taryn East
Taryn East

Reputation: 27747

Hi and welcome to Stack Overflow. I'm assuming that the code you've written above is the exact code you're using. If so, the problem is that the last line of your method is the puts, and the last line of the method is what is being returned by your method. So your method is outputting a string something like: Address: ADDRESS_HERE and what you need is to actually return the address.

To fix, change the last lines of your method to:


    address = generate_address_from_public_key_hash(public_key_hash(public_key_hex))

    puts "address: #{address}"

    address
  end

Upvotes: 0

it looks like there's a mistake in the generate_address_from_public_key_hash method. Instead of using pub_key_hash to generate the base58-encoded address, it should use pk. Here's the corrected code:

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

With these changes, the addresses generated by the generate_address method should be valid testnet addresses.

Upvotes: 0

Related Questions