Flavio Sousa / Mar 23 2023
Mastering Bitcoin chapter 4 - 05 private key to bitcoin address
{:deps {org.clojure/clojure {:mvn/version "1.11.1"}
base58 {:git/url "https://github.com/fjsousa/base58"
:sha "807fba7f9f38175531be81c4f4c4a682fc380433"}
buddy/buddy-core {:mvn/version "1.10.413"}
org.bouncycastle/bcprov-jdk15on {:mvn/version "1.70"}
;; complient is used for autocompletion
;; add your libs here (and restart the runtime to pick up changes)
compliment/compliment {:mvn/version "0.3.9"}}}
Extensible Data Notation
(ns play-with-points
(:require
[buddy.core.hash :as hash]
[buddy.core.codecs :as codecs]
[base58.core :as base58])
(:import java.math.BigInteger
java.security.SecureRandom
[org.bouncycastle.jce ECNamedCurveTable]))
0.1s
Based on this python script example from Mastering Bitcoin.
1 - 256 random int is the private key
;; (def random (SecureRandom.))
;; (def private-key (BigInteger/probablePrime 256 random))
;; Using the reference integer from Mastering Bitcoin to
;; verify that we didn't mess things allong the way.
(def private-key
(BigInteger. "26563230048437957592232553826663696440606756685920117476832299673293013768870"))
0.0s
2. Private key as hex
(def private-key-hex
(-> private-key
(.toString 16)))
0.0s
3. Private key WIF
(def version-hex "80")
(def checksum-bytes
(->> (str version-hex private-key-hex)
codecs/hex->bytes
hash/sha256
hash/sha256
(take 4)))
(def private-key-wif
(base58/encode (concat
(codecs/hex->bytes version-hex)
(codecs/hex->bytes private-key-hex)
checksum-bytes)))
0.0s
4. Private key Compressed WIF
;; hex of a "compressed" private key - appending 01 to the Hex of the private key above
;; "The term "compressed private key" really means "private key from which only compressed
;; public keys should be derived"
;; "version prefix is the same (0x80) for both WIF and WIF-compressed formats"
(def version-hex "80")
(def suffix-hex "01")
(def private-key-compressed-hex
(str private-key-hex suffix-hex))
0.0s
(def checksum-bytes
(->> (str version-hex private-key-compressed-hex)
codecs/hex->bytes
hash/sha256
hash/sha256
(take 4)))
(def private-key-wif
(base58/encode (concat
(codecs/hex->bytes (str version-hex private-key-hex suffix-hex))
checksum-bytes)))
0.0s
5. Public key compressed
(def spec (ECNamedCurveTable/getParameterSpec "secp256k1"))
(def G (.getG spec))
(def P (.normalize (.multiply G private-key)))
(def x (str (.getRawXCoord P)))
(def y (str (.getRawYCoord P)))
(def public-key
(str
"04"
(format "%064X" (BigInteger. x 16))
(format "%064X" (BigInteger. y 16))))
0.3s
6. Public key compressed hex
(def compressed-public-key-hex
(str
(if (even? (BigInteger. y 16)) "02" "03")
x))
0.0s
7. Bitcoin Address
(def public-key-hash
(->>
public-key
codecs/hex->bytes
hash/sha256
hash/ripemd160
codecs/bytes->hex))
(def version-hex "00")
;;base 58check encode
(def checksum-bytes
(->> (str version-hex public-key-hash)
codecs/hex->bytes
hash/sha256
hash/sha256
(take 4)))
(def bitcoin-address
(base58/encode (concat
(codecs/hex->bytes version-hex)
(codecs/hex->bytes public-key-hash)
checksum-bytes)))
0.0s
8. Compressed bitcoin address
(def public-key-hash
(->>
compressed-publick-key-hex
codecs/hex->bytes
hash/sha256
hash/ripemd160
codecs/bytes->hex))
(def version-hex "00")
(def checksum-bytes
(->> (str version-hex public-key-hash)
codecs/hex->bytes
hash/sha256
hash/sha256
(take 4)))
(def bitcoin-address
(base58/encode (concat
(codecs/hex->bytes version-hex)
(codecs/hex->bytes public-key-hash)
checksum-bytes)))
0.0s