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.