Ruby Quiz - Challenge #15 - Generate the Bitcoin (Base58) Address from the (Elliptic Curve) Public Key
Let's generate the classic bitcoin base58 address from an (elliptic curve) public key.
Let's follow the steps from the Bitcoin Wiki article titled "How to create Bitcoin Address":
Step 0 - Having a private Elliptic Curve Digital Signature Algorithm (ECDSA) key
18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725
Step 1 - Take the corresponding public key generated with it (33 bytes, 1 byte 0x02 (y-coord is even), and 32 bytes corresponding to X coordinate)
0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352
Step 2 - Perform SHA-256 hashing on the public key
0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98
Step 3 - Perform RIPEMD-160 hashing on the result of SHA-256
f54a5851e9372b87810a8e60cdd2e7cfd80b6e31
Step 4 - Add version byte in front of RIPEMD-160 hash (0x00 for Main Network)
00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31
Step 5 - Perform SHA-256 hash on the extended RIPEMD-160 result
ad3c854da227c7e99c4abfad4ea41d71311160df2e415e713318c70d67c6b41c
Step 6 - Perform SHA-256 hash on the result of the previous SHA-256 hash
c7f18fe8fcbed6396741e58ad259b5cb16b7fd7f041904147ba1dcffabf747fd
Step 7 - Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
c7f18fe8
Step 8 - Add the 4 checksum bytes from stage 7 at the end of extended RIPEMD-160 hash from stage 4. This is the 25-byte binary Bitcoin Address.
00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31c7f18fe8
Step 9 - Convert the result from a byte string into a base58 string using Base58Check encoding. This is the most commonly used Bitcoin Address format
1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs
That's it.
The challenge: Code a
hash160
(public key to public key hash),
a hash256
(double sha-256 hash function), and a base58
method that together return the classic Bitcoin address.
Start from scratch or, yes, use any library / gem you can find.
def hash160( pubkey ) # public key to public key hash
# step 2 - perform SHA-256 hashing
# step 3 - perform RIPEMD-160 hashing on the result of SHA-256
# ...
end
def hash256( hex ) # double sha-256 hash
# step 5 - perform SHA-256 hash
# step 6 - perform SHA-256 hash on the result of the previous SHA-256 hash
# ...
end
def base58( hex )
# ...
end
To qualify for solving the code challenge / puzzle you must pass the test:
require 'minitest/autorun'
class RubyQuizTest < MiniTest::Test
def test_addr
pubkey = '0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352'
pkh = hash160( pubkey )
assert_equal 'f54a5851e9372b87810a8e60cdd2e7cfd80b6e31', pkh
prefix = '00' ## version prefix
h = hash256( prefix + pkh )
assert_equal 'c7f18fe8fcbed6396741e58ad259b5cb16b7fd7f041904147ba1dcffabf747fd', h
assert_equal 'c7f18fe8', h[0..7]
addr = base58( prefix + pkh + h[0..7] )
assert_equal '1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs', addr
end # method test_addr
end # class RubyQuizTest
Post your code snippets on the "official" Ruby Quiz Channel, that is, the ruby-talk mailing list.
Happy hacking and crypto hashing with Ruby.