Skip to content

Instantly share code, notes, and snippets.

@colindean
Last active October 12, 2023 23:45
Show Gist options
  • Save colindean/5239812 to your computer and use it in GitHub Desktop.
Save colindean/5239812 to your computer and use it in GitHub Desktop.
Bitcoin address generator in bash
#!/bin/bash
#
# This is free and unencumbered software released into the public domain.
#
# Requires bc, dc, openssl, xxd
#
# by grondilu from https://bitcointalk.org/index.php?topic=10970.msg156708#msg156708
base58=({1..9} {A..H} {J..N} {P..Z} {a..k} {m..z})
bitcoinregex="^[$(printf "%s" "${base58[@]}")]{34}$"
if [ `uname -s` = 'Darwin' ]; then
TAC="tail -r "
else
TAC="tac"
fi
decodeBase58() {
local s=$1
for i in {0..57}
do s="${s//${base58[i]}/ $i}"
done
dc <<< "16o0d${s// /+58*}+f"
}
encodeBase58() {
# 58 = 0x3A
echo -n "$1" | sed -e's/^\(\(00\)*\).*/\1/' -e's/00/1/g' | tr -d '\n'
dc -e "16i ${1^^} [3A ~r d0<x]dsxx +f" |
while read -r n; do echo -n "${base58[n]}"; done
}
checksum() {
xxd -p -r <<<"$1" |
openssl dgst -sha256 -binary |
openssl dgst -sha256 -binary |
xxd -p -c 80 |
head -c 8
}
checkBitcoinAddress() {
if [[ "$1" =~ $bitcoinregex ]]
then
h=$(decodeBase58 "$1")
checksum "00${h::${#h}-8}" |
grep -qi "^${h: -8}$"
else return 2
fi
}
hash160() {
openssl dgst -sha256 -binary |
openssl dgst -rmd160 -binary |
xxd -p -c 80
}
hash160ToAddress() {
printf "%34s\n" "$(encodeBase58 "00$1$(checksum "00$1")")" |
sed "y/ /1/"
}
publicKeyToAddress() {
hash160ToAddress $(
openssl ec -pubin -pubout -outform DER |
tail -c 65 |
hash160
)
}
echo -n "Public key: "
openssl ecparam -name secp256k1 -genkey | tee priv.pem | openssl ec -pubout | publicKeyToAddress
echo ""
echo -n "Private key: "
cat priv.pem
echo ""
@liushooter
Copy link

liushooter commented Jun 24, 2017

@Rello
I thinke you should:

Get private key:

openssl ec -in priv.pem -outform DER|tail -c +8|head -c 32|xxd -p -c 32

Get public key:

openssl ec -in priv.pem -pubout -outform DER|tail -c 65|xxd -p -c 65

from https://bitcoin.stackexchange.com/a/11843

@esolitos
Copy link

esolitos commented Aug 10, 2017

Am I not understanding something?
I did some tests and the address i get on generation doesn't seems to match the key?

Here are the steps taken:

  • Generate the address: generate_bitcoin_address.sh [Key at the end of this post]
  • Import the address to blockchain.info/wallet all good
  • Send a tiny payment to the address, still all good (as expected)
  • Generate the btc-private key from the EC using @shooterman oneliner: openssl ec -in priv.pem -outform DER |tail -c +8 |head -c 32 |xxd -p -c 32 ==> f68f38a156d9da6747ea4318c3cc2513159e4fa9224c106ff946d900022f4e11
  • Import this private key to blockchain.info/wallet, and here's the weirdness: I do actually manage to import the wallet, but I get a different address!!!

Help?

Attached data

Key generation:

# ./generate_bitcoin_address.sh
Public key: 1Ho5y31HGWViGVtj4J4J2gVrn9kHhbD11z

Private key:
 -----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIGktBoOg2mOYqf91vKHOwLge36XyFjRwrGFlC964uzXXoAcGBSuBBAAK
oUQDQgAEovoPa1wLZrGh0xJuoe9FA9iWrYsuqXOcg/5SYv/Fr0K0m9K/JcY0TtUZ
xPFAyU5yAjS2pVRLevjmQb0RHocDKw==
-----END EC PRIVATE KEY-----

Imported address in blockchain.info/wallet:
image

Retrive the btc-key:

# openssl ec -in priv.pem -outform DER |tail -c +8 |head -c 32 |xxd -p -c 32
692d0683a0da6398a9ff75bca1cec0b81edfa5f2163470ac61650bdeb8bb35d7

Import to blockchain.info/wallet
image

EDIT

In pursuit of the right tool i found here an alternative in python (Note you need ecdsa from pip, before you can run it).

@Rotsor
Copy link

Rotsor commented Nov 30, 2017

This prints a wrong number of leading '1' characters in the address. For example, it prints 11wv6n4DaLQLHqfAUXzchLVBVv1P5CrSoH instead of 1wv6n4DaLQLHqfAUXzchLVBVv1P5CrSoH when encoding 000a62c98943feeb9ea0572ebac7bd323bc54cada0b87ca958.

@arno01
Copy link

arno01 commented Dec 8, 2017

@Rotsor looks like an extra leading space problem... I think this should fix that, at least it works for me:

hash160ToAddress() {
    printf "%34s\n" "$(encodeBase58 "00$1$(checksum "00$1")")" |
    sed -e 's/^  / /' |
    sed "y/ /1/"
}

Edit

Or rather use this function, apparently it encodes the leading 00 properly:

base58=({1..9} {A..H} {J..N} {P..Z} {a..k} {m..z});

function encodeBase58() {
    echo -n "$1" | sed -e's/^\(\(00\)*\).*/\1/' -e's/00/1/g' | tr -d '\n'
    dc -e "16i ${1^^} [3A ~r d0<x]dsxx +f" |
    while read -r n; do echo -n "${base58[n]}"; done
}

Found at https://github.com/grondilu/bitcoin-bash-tools/blob/master/bitcoin.sh

@Pablo36
Copy link

Pablo36 commented Mar 31, 2018

Hello, I have a question on how to generate the key of the given address, please and any info if I can give you a btc helper. I have no idea how to do this and info on priv or email zarabaniaprzeznecik@gmail.com. I have btc to pay, but I do not have a private kucza please help

@colindean
Copy link
Author

colindean commented Jun 23, 2019

After far too many years of not knowing that I was getting comments on this, I've updated it a with @arno01's recommendation.

@MichaelMichaelMichaelMichaelMichael

Hi, with the edited encodeBase58 function, from time to time, it's still generating addresses with a prefix 11.
Examples:

address: 11NVGRNwpqYCUiJ42TJ5iLdHt8wALLyRyV secret:  0527fee5b586ddea8837cdbf58e6f9b334e10bb95c20519db63561eda3861f01
address: 11BC84pND1z7ekq12FF7LLDKmRmQT6QhxB secret:  bb35d58aecd49a012587a6093de0ffd2d4c143242fe60196900fa4e88a72480e
address: 11PgGJsvRZBynVcfSTMAnZQXLx2pnGSCNk secret:  3096e3fc4027e63cc3ca46b208b45581ded83773f798658a9b3b5fcdcb9ab3a3
address: 11PZLAC8yDV76gLv2EN7BykAS3Kor8Fcym secret:  29a7cef80bdf63571f8b93a629943475f50aa1f9e4cebc911e8ee0f3e19baa20
address: 11Bp95CTxgyWecEXxV6m3UzUiT6JutJ8VN secret:  0d5c20fd922cb9c134aecf9a4bd992af429f16b8742d91d056aeab22f2a08392
address: 11AWP79DdTHmogAiuvyokDK28LQoq1QnB2 secret:  d698fd92748de1a484bcb18d1f5c9bd4f066a30eb7f56c92b6281cf68e7d7127
address: 11R1T3jv92emkonrjfkUDJdeWR7naDVuR3 secret:  51a37515a5964f5c293733a179f1072d6918249bf0c264ca903bbe8267a4a352
address: 11MNiiYjA57xKfTZo6cTCZV5Q6n3kyMFma secret:  79bbd8bd40a3e3f581aad528bc0320c525ec8a92717070d7327c879c1a597c1c
address: 11kUJeGjdUnubuuxECmWdzzMpCGLzhYBZU secret:  8ad77d1b6695cb5bce4654110aa30b62cf16e46db5d97189604019d1200f8943
address: 11wMeBcQW2QNuLXE7rfdC1KA1x6E8Bio7A secret:  25ca9ec03fa6935ed4ce36edb817fc6fd30864309520af99051a14376d623595
address: 11Nu6WymbKBmZKpiSyJEAwMM9MT495BHGZ secret:  a1b55bd7d2c449a5480b67e84f774f8c1372b431b16408430cdac5626878a23b
address: 11ec8HgPZZxHkGR1og79QPwLSkuhqTNDma secret:  fd93585c1fafa30ebdfc068da8579001764a4c75bb9b8bba532331f5df621e2a
address: 11yhkhxVD73YmmW7vtB153TDLdPHvBnvhZ secret:  3f8f89f30acf1e08f129d3a5d725189fdd6384cb5178c5901432c25207742b02
address: 11a6eEoWH47KCf2w5pEYbLGQ4Rn31wjxiJ secret:  0a6cfd67b4cc859321f450e6d020a6b9abbdd838a0ec4afa30976a72344f0292

Just to let you know that this issue still exists.

@colindean
Copy link
Author

I welcome suggestions. I don't have the bandwidth available right now to debug it.

@b4zz4
Copy link

b4zz4 commented Sep 6, 2021

Is it possible to recover the public key from the bitcoin direction?

for example to encrypt messages using openssl

@colindean
Copy link
Author

@b4zz4 Can you clarify what you mean? The Bitcoin address is the public address but not the public key. I think you're wanting to see it output a public key in addition to the Base58 address. That may be possible but I don't really have the bandwidth available to do it.

@b4zz4
Copy link

b4zz4 commented Sep 7, 2021 via email

@colindean
Copy link
Author

Negative.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment