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
Runtimes (1)