Skip to content

Commit a80c966

Browse files
author
grondilu
authored
Merge pull request grondilu#15 from dsuchka/master
Support QTUM, TRX (Tron), and Ethereum-like addresses
2 parents 8afbe00 + 7364003 commit a80c966

File tree

1 file changed

+63
-17
lines changed

1 file changed

+63
-17
lines changed

bitcoin.sh

100644100755
Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ decodeBase58() {
7272
dc -e "$dcr 16o0$(sed 's/./ 58*l&+/g' <<<$1)p" |
7373
while read line; do echo -n ${line/\\/}; done
7474
}
75+
7576
encodeBase58() {
7677
local n
7778
echo -n "$1" | sed -e's/^\(\(00\)*\).*/\1/' -e's/00/1/g' | tr -d '\n'
@@ -87,6 +88,20 @@ checksum() {
8788
head -c 8
8889
}
8990

91+
toEthereumAddressWithChecksum() {
92+
local addrLower=$(sed -r -e 's/[[:upper:]]/\l&/g' <<< "$1")
93+
local addrHash=$(echo -n "$addrLower" | sha3-256 | xxd -p -c32)
94+
local addrChecksum=""
95+
local i c x
96+
for i in {0..39}; do
97+
c=${addrLower:i:1}
98+
x=${addrHash:i:1}
99+
[[ $c =~ [a-f] ]] && [[ $x =~ [89a-f] ]] && c=${c^^}
100+
addrChecksum+=$c
101+
done
102+
echo -n $addrChecksum
103+
}
104+
90105
checkBitcoinAddress() {
91106
if [[ "$1" =~ ^[$(IFS= ; echo "${base58[*]}")]+$ ]]
92107
then
@@ -102,6 +117,16 @@ hash160() {
102117
unpack
103118
}
104119

120+
sha3-256() {
121+
python3 -c "
122+
import sys
123+
from Crypto.Hash import keccak
124+
data = sys.stdin.buffer.read()
125+
hash = keccak.new(digest_bits=256).update(data)
126+
sys.stdout.buffer.write(hash.digest())
127+
"
128+
}
129+
105130
hexToAddress() {
106131
local x="$(printf "%2s%${3:-40}s" ${2:-00} $1 | sed 's/ /0/g')"
107132
encodeBase58 "$x$(checksum "$x")"
@@ -117,33 +142,54 @@ newBitcoinKey() {
117142
fi
118143
elif [[ "$1" =~ ^[0-9]+$ ]]
119144
then $FUNCNAME "0x$(dc -e "16o$1p")"
120-
elif [[ "${1^^}" =~ ^0X([0-9A-F]{1,64})$ ]]
145+
elif [[ "${1^^}" =~ ^0X([0-9A-F]{1,})$ ]]
121146
then
122147
local exponent="${BASH_REMATCH[1]}"
123-
local uncompressed_wif="$(hexToAddress "$exponent" 80 64)"
124-
local compressed_wif="$(hexToAddress "${exponent}01" 80 66)"
148+
local full_wif="$(hexToAddress "$exponent" 80 64)"
149+
local comp_wif="$(hexToAddress "${exponent}01" 80 66)"
125150
dc -e "$ec_dc lG I16i${exponent^^}ri lMx 16olm~ n[ ]nn" |
126151
{
127152
read y x
128-
X="$(printf "%64s" $x| sed 's/ /0/g')"
129-
Y="$(printf "%64s" $y| sed 's/ /0/g')"
130-
if [[ "$y" =~ [02468ACE]$ ]]
131-
then y_parity="02"
132-
else y_parity="03"
133-
fi
134-
uncompressed_addr="$(hexToAddress "$(pack "04$X$Y" | hash160)")"
135-
compressed_addr="$(hexToAddress "$(pack "$y_parity$X" | hash160)")"
153+
X="$(printf "%64s" $x | sed 's/ /0/g')"
154+
Y="$(printf "%64s" $y | sed 's/ /0/g')"
155+
[[ "$y" =~ [02468ACE]$ ]] && y_parity="02" || y_parity="03"
156+
full_pubkey="04${X}${Y}"
157+
comp_pubkey="${y_parity}${X}"
158+
full_p2pkh_addr="$(hexToAddress "$(pack "$full_pubkey" | hash160)")"
159+
comp_p2pkh_addr="$(hexToAddress "$(pack "$comp_pubkey" | hash160)")"
160+
full_p2sh_addr="$(hexToAddress "$(pack "41${full_pubkey}AC" | hash160)" 05)"
161+
comp_p2sh_addr="$(hexToAddress "$(pack "21${comp_pubkey}AC" | hash160)" 05)"
162+
# Note: Witness uses only compressed public key
163+
comp_p2wpkh_addr="$(hexToAddress "$(pack "0014$(pack "$comp_pubkey" | hash160)" | hash160)" 05)"
164+
full_multisig_1_of_1_addr="$(hexToAddress "$(pack "5141${full_pubkey}51AE" | hash160)" 05)"
165+
comp_multisig_1_of_1_addr="$(hexToAddress "$(pack "5121${comp_pubkey}51AE" | hash160)" 05)"
166+
qtum_addr="$(hexToAddress "$(pack "${comp_pubkey}" | hash160)" 3a)"
167+
ethereum_addr="$(pack "$X$Y" | sha3-256 | unpack | tail -c 40)"
168+
tron_addr="$(hexToAddress "$ethereum_addr" 41)"
136169
echo ---
137170
echo "secret exponent: 0x$exponent"
138171
echo "public key:"
139172
echo " X: $X"
140173
echo " Y: $Y"
141-
echo "compressed:"
142-
echo " WIF: $compressed_wif"
143-
echo " bitcoin address: $compressed_addr"
144-
echo "uncompressed:"
145-
echo " WIF: $uncompressed_wif"
146-
echo " bitcoin address: $uncompressed_addr"
174+
echo
175+
echo "compressed addresses:"
176+
echo " WIF: $comp_wif"
177+
echo " Bitcoin (P2PKH): $comp_p2pkh_addr"
178+
echo " Bitcoin (P2SH [PKH]): $comp_p2sh_addr"
179+
echo " Bitcoin (P2WPKH): $comp_p2wpkh_addr"
180+
echo " Bitcoin (1-of-1): $comp_multisig_1_of_1_addr"
181+
echo " ---- other networks ----"
182+
echo " Qtum: $qtum_addr"
183+
echo
184+
echo "uncompressed addresses:"
185+
echo " WIF: $full_wif"
186+
echo " Bitcoin (P2PKH): $full_p2pkh_addr"
187+
echo " Bitcoin (P2SH [PKH]): $full_p2sh_addr"
188+
echo " Bitcoin (1-of-1): $full_multisig_1_of_1_addr"
189+
echo " ---- other networks ----"
190+
echo " Ethereum: 0x$(toEthereumAddressWithChecksum $ethereum_addr)"
191+
echo " Tron: $tron_addr"
192+
echo
147193
}
148194
elif test -z "$1"
149195
then $FUNCNAME "0x$(openssl rand -rand <(date +%s%N; ps -ef) -hex 32 2>&-)"

0 commit comments

Comments
 (0)