tl;dr Wie sollte man Hash160 mit den meisten grundlegenden Tools ausführen?
=============================================== ==
Hi,
Ich versuche herauszufinden, wie Transaktionen in Bitcoin funktionieren.
Wenn ich Eingänge für einen neuen Sender auswähle, möchte ich sicherstellen, dass sie zu einer bestimmten Adresse gehören. Existierende TXs geben jedoch nicht die Adressen früherer Ausgaben an, sondern enthalten stattdessen Adress-Hashes.
z.B:
>> bx fetch-tx 11a1b7ac0a65bd50b7094c720aecd77cfd83d84b1707960fd00dd82a888aab5c --config /home/theo/Desktop/bx-testnet.cfg
{
hash 11a1b7ac0a65bd50b7094c720aecd77cfd83d84b1707960fd00dd82a888aab5c
inputs
{
input
{
address_hash f3b7278583827a049d6be894bf7f516178a0c8e6
previous_output
{
hash 4a3532061d43086299ae9b2409a456bb9638dff32e0858c4ccda27203fb2e4f6
index 1
}
script "[30440220146b8b5b014245a9e27e21122d4dded04c3f39c3a49ac2494743d6f6ae8efff602206d417a4be9c7431ea69699132438510ade1cf8d746607f77d114907762ed1eb301] [023dd2e892290e41bb78efce6ea30a97015ef13eaaa9ebb7b0514485fc365cc391]"
sequence 4294967295
}
}
lock_time 0
outputs
{
output
{
address_hash a73706385fffbf18855f2aee2a6168f29dbb597e
script "dup hash160 [a73706385fffbf18855f2aee2a6168f29dbb597e] equalverify checksig"
value 130000000
}
output
{
address_hash ad6e80394af99ece5d7701bf2f457480b93965b7
script "dup hash160 [ad6e80394af99ece5d7701bf2f457480b93965b7] equalverify checksig"
value 49525957813
}
}
version 1
}
Angenommen, ich möchte überprüfen, welche der Ausgaben von der Adresse gesendet werden können. mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa
Also nehme ich seinen Hash160 in Python:
>> hashlib.new('ripemd160', hashlib.sha256("mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa".encode('utf-8')).digest()).hexdigest()
'748598cd9b004aecf8a2d97464fb1f2a90562ffe'
Das ist nicht das Ergebnis, das ich erwartet hatte:a73706385fffbf18855f2aee2a6168f29dbb597e
Inzwischen berechnet dieser Onlinedienst den Hash korrekt.
Wie hash160 ich eine Bitcoin-Adresse, vorzugsweise in Python?
Die Adresse ist bereits ein Hash, zusammen mit einer 4-Byte-Prüfsumme und einem Versionsbyte. Um von einer Adresse zu einem hash160 zu gelangen, müssen Sie sha256 oder ricemd160 von nichts berechnen. Sie müssen es nur von base58 zurück in hex decodieren und den unerwünschten Müll verwerfen.
Wenn Sie nehmen mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa
und base58 decodieren, erhalten Sie
6FA73706385FFFBF18855F2AEE2A6168F29DBB597EF59C240B
VVxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxSSSSSSSS
Das erste Byte (6F) ist das Versionsbyte; verwirf es. Die letzten 4 Bytes sind die Prüfsumme; verwirf es. Die restlichen 20 Bytes sind der Hash160 des öffentlichen Schlüssels, der der Adresse entspricht.
Ich habe diese Frage bereits auf StackOverflow beantwortet, aber ich denke, ich werde die Antwort hier einfach erneut veröffentlichen.
Endlich habe ich es geschafft. Einige Enthüllungen in meiner Antwort mögen für Sie offensichtlich und grundlegend erscheinen, aber ich hoffe, dass sie für die Leute hilfreich sind, die völlig neu bei Bitcoin sind (wie ich).
Wiki sagt, dass ich Hash160 erhalten kann, indem ich den letzten Schritt der Adressproduktion umkehre
Dieser Schritt kodiert eine Bytefolge mit dem base58-Alphabet
b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
In diesem Alphabet fehlen 0, I, l, O, da diese Symbole leicht zu verwechseln sind. Und das ist das Letzte, was Sie tun wollen, wenn ein falsches Symbol dazu führen kann, dass Sie viel Geld verlieren.
Daher müssen wir uns mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa
in einen Byte-String verwandeln. Bytes sind im Hexadezimalformat und können von 0x00
(0 dezimal) bis 0xff
(255 dezimal) reichen. Und denken Sie daran, dass wir uns mit einem speziellen b58-Alphabet befassen müssen: Die Dekodierung der Adresse mit utf-8 oder anderen Kodierungsstandards ergibt Unsinn.
Zuerst dachte ich, dass ich die Adresse mit dieser Funktion einfach entschlüsseln kann:
def decode(addr):
b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
decoded = ''
for i in addr:
temp = hex(b58.index(i))
if len(temp) == 3:
temp = '0' + temp[-1]
else:
temp = temp[2:]
decoded += (temp)
return (decoded)
decode('mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa')
>> '2c352c06030e090b212127390803312a1d22152c1d010d2c2811242c0d0f23372f21'
Aber das Ergebnis ist nicht wie der Hash, den ich in der Transaktion ( a73706385fffbf18855f2aee2a6168f29dbb597e
) nachgeschlagen habe. Auf diese Weise erfuhr ich, dass ich keine Ahnung hatte, wie die Dekodierung durchgeführt wird. Was ist, wenn Hash160 0xff
? Es gibt kein solches Symbol in b58, da 58 in Hex einfach ist 0x3a
. Bei der Dekodierung von b58 können wir nicht jedes Symbol einzeln behandeln. Die gesamte Adresse bildet eine riesige Zahl, die im Zahlensystem base58 geschrieben ist (ihre erste Ziffer entspricht 58**34).
Um den Byte-String zu erhalten, habe ich diese Zahl zuerst in eine Dezimalzahl und erst dann in Byte-String umgewandelt.
Wenn Sie wissen, wie Sie diesen Umweg vermeiden und Bytes direkt erhalten können, kommentieren Sie dies bitte
def decode(addr):
b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def base58_to_dec(addr):
dec = 0
for i in range(len(addr)):
dec = int(dec * 58 + b58.index(addr[i]))
print('Decimal representation')
print(dec)
return(dec)
def dec_to_byte(dec):
out = ''
while dec != 0:
print(dec)
remn = dec % 256
dec = int((dec - remn) / 256)
temp = hex(remn)
if len(temp) == 3:
temp = '0' + temp[-1]
else:
temp = temp[2:]
out = temp + out
return(out)
dec = base58_to_dec(addr)
out = dec_to_byte(dec)
return (out)
decode("mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa")
>> Decimal representation
>> 700858390993795610399098743129153130886272689085970101576715
>> '6fa7370638600000000000000000000000000000000000000b'
Diese Ausgabe sieht ungefähr so aus, wie ich sie brauche ( a7370638...
), hat aber viel zu viele Nullen. Achten Sie nicht darauf, dass das erste Byte ( 6f
) nicht übereinstimmt: Es hat nichts mit Hash160 zu tun, das wir brauchen, nur mit der Protokollversion.
Dies ist wahrscheinlich ein Genauigkeitsfehler. Um damit umzugehen, habe ich mpmath
das verwendet, mit dem Sie präzise mit ganzen Zahlen arbeiten können.
import mpmath as mp
mp.dps = 1000
def decode(addr):
b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def base58_to_dec(addr):
dec = 0
for i in range(len(addr)):
dec = int(dec * 58 + b58.index(addr[i]))
return(dec)
def dec_to_byte(dec):
out = ''
while dec != 0:
remn = mp.mpf(dec % 256)
dec = mp.mpf((dec - remn) / 256)
temp = hex(int(remn))
if len(temp) == 3:
temp = '0' + temp[-1]
else:
temp = temp[2:]
out = temp + out
return (out)
dec = base58_to_dec(addr)
out = dec_to_byte(dec)
return (out)
Wenden Sie eine präzise Modulo-Operation an und wir können endlich den Hash160 erhalten. Stellen Sie nur sicher, dass Sie die ersten und letzten 4 Bytes auslösen, die einen Fat-Finger-Check enthalten.
x = decode('mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa')
print(x)
>> 6fa73706385fffbf18855f2aee2a6168f29dbb597ef59c240b
print(x[2:-8])
>> a73706385fffbf18855f2aee2a6168f29dbb597e
Yay! Genau wie in der Transaktion!
print(decode('mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa'))
druckt 6fa7370638600000000000000000000000000000000000000b
statt 6fa73706385fffbf18855f2aee2a6168f29dbb597ef59c240b
(Python 3).Installieren Sie base58
das Paket (Ubuntu: sudo apt-get install base58
) und führen Sie dann Folgendes aus:
$ printf mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa | base58 -d | xxd -p
6fa73706385fffbf18855f2aee2a6168f29dbb597ef59c240b
Verwenden Sie zum Decodieren in eine Adresse:
$ printf mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa | base58 -d | cut -c2- | xxd -p | head -c40
a73706385fffbf18855f2aee2a6168f29dbb597e
Installieren Sie base58 ( pip3 install base58
) und verwenden Sie den folgenden Code:
import base58
print(base58.b58decode_check(b'mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa').hex()[2:])
Einzeiler:
$ echo 'import base58; print(base58.b58decode_check(b"mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa").hex()[2:])' | python3
a73706385fffbf18855f2aee2a6168f29dbb597e
Skript zum Konvertieren der Datei mit der Liste der Adressen in die entsprechenden Hashes:
while read addr; do python3 -c "import base58; print(base58.b58decode_check(b'$addr').hex()[2:])"; done < btc.csv > btc.hash
pebwindkraft
Lotrus28
pebwindkraft