Wie erstelle ich eine Hash160-Bitcoin-Adresse?

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. mvm74FACaagz94rjWbNmW2EmhJdmEGcxpaAlso 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?

Während ich mit Python nicht helfen kann, möchten Sie vielleicht " righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html " ansehen, es hat eine gute Erklärung. Ich bin mir auch nicht sicher, ob ich Ihre Logik mit den Adressen verstehe, von denen ausgegeben werden soll. Sie würden die UTXOs aus früheren Transaktionen verwenden ... Also würde ich "listunspent" in der Core-Wallet verwenden, um die vorherige tx-ID und den vout anzuzeigen, um sie in einer neuen (unsignierten) Transaktion zu verwenden. Ein Adress-Hash kann nicht einfach rückgängig gemacht werden, deshalb haben wir Hash-Funktionen. Leicht in eine Richtung zu gehen, unmöglich umzukehren. Das gibt uns die Sicherheit im gesamten Bitcoin-Netzwerk.
@pebwindkraft Aber ich brauche das Skript in der vorherigen Ausgabe zum Signieren, oder? Außerdem scheint mir, dass ich die Codierungsidee falsch verstanden habe. Hash160 hat eindeutig Bytes, die größer als 3a (58 dezimal) sind, daher ist meine Decodierungsfunktion Unsinn
ja, du gibst ihm den scriptPubKey, siehe das mittlerweile berühmte 19step-Beispiel, und etwas Python am Ende: hier: bitcoin.stackexchange.com/questions/3374/…

Antworten (4)

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 mvm74FACaagz94rjWbNmW2EmhJdmEGcxpaund 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

Geben Sie hier die Bildbeschreibung ein(Hash160 ist hervorgehoben)

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 mvm74FACaagz94rjWbNmW2EmhJdmEGcxpain 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 mpmathdas 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!

Ich habe das letzte Codebeispiel getestet und es gibt den falschen Wert aus. print(decode('mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa'))druckt 6fa7370638600000000000000000000000000000000000000bstatt 6fa73706385fffbf18855f2aee2a6168f29dbb597ef59c240b(Python 3).

Installieren Sie base58das 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

Python 3

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