Wiederherstellen einer HD-Wallet aus einer teilweisen Seed-Phrase

Ich versuche, bei der Wiederherstellung einer Brieftasche zu helfen, bei der der Besitzer nur 11 der 12 Wörter in der Seed-Phrase aufgeschrieben hat. Anfangs dachte ich, die Aufgabe wäre schnell und gut definiert, aber sie scheint etwas komplexer zu sein, als ich angenommen hatte, und Referenzmaterial ist ziemlich spärlich. Für den Fall, dass jemand anderes ein ähnliches Problem wie ich hat, möchte ich diesen Beitrag hinterlassen, in dem die Schritte aufgeführt sind, die ich befolgt habe (mit funktionierenden Codebeispielen).

Die Brieftasche, mit der ich es zu tun habe, ist Breadwallet, die anscheinend eine andere (ältere) Mnemonik-zu-HD-Master-Private-Key-Ableitungsstrategie als die meisten modernen Brieftaschen verwendet. Im Moment werde ich mich nur auf die Wiederherstellung teilweiser Breadwallet-Phrasen konzentrieren, aber ich plane, die Antwort schließlich zu erweitern, um auch neuere Ableitungsstrategien ( BIP44 ) abzudecken.

Das ist wirklich gutes Zeug. Wie würde es funktionieren, wenn Sie ein Electrum (2.x)-Wallet mit 13 Wörtern verwenden würden, bei dem nur das erste Seed-Wort fehlte? Wir haben also Position, aber zusätzliche Variabilität der Unterschiede in der Entropie usw. mit 13 gegenüber 12 ...
Mit einem fehlenden Wort und einer bekannten Position ist es einfach, den Seed zu regenerieren. Die Prüfsumme ist in den Seed eingebaut, daher gibt es nur sehr wenige Wörter, die überhaupt funktionieren können (wahrscheinlich nur eine Handvoll Seeds, die Sie überhaupt ausprobieren müssten).
Sie sollten in einem Antwortabschnitt keine Fragen stellen.

Antworten (1)

(Die in diesem Beitrag verwendete Sprache ist Python)

Breadwallet verwendet BIP39 , um den 128-Bit-Master-Seed aus der 12-Wort-Mnemonik zu generieren. Der Master-Seed wird dann verwendet, um mithilfe von BIP32 eine Reihe von Wallets/Konten zu generieren, die Adressketten enthalten .

https://github.com/bitcoin/bips/raw/master/bip-0032/derivation.png


Importieren Sie zunächst hashlib und binascii, wir werden sie später brauchen.

import hashlib
from binascii import hexlify, unhexlify

Nehmen wir an, Sie haben 11 der 12 Wörter in Ihrer Startphrase. Der Einfachheit halber verwende ich die ersten 11 Wörter in der BIP39-Wortliste:

partial_seed_phrase = [ 'abandon', 'ability', 'able', 'about', 'above', 'absent', 'absorb', 'abstract', 'absurd', 'abuse', 'access' ]

Die Wortliste enthält 2048 Einträge, was jedem Wort 11 Entropiebits gibt (2 11 = 2048). Die 12 Wörter haben insgesamt 12*11 = 132 Bit Entropie. Der HD-Master-Seed ist 128 Bit lang, und am Ende ist eine 4-Bit-Prüfsumme angehängt, die die Gesamtbits auf 132 erhöht. So weit, so gut.

Wenn wir davon ausgehen, dass wordlistes sich um eine Liste mit 2048 Elementen handelt (aus Platzgründen weggelassen), können wir den Index (in Dezimalzahl) der Elemente in finden partial_seed_phrase:

mnemonic_in_decimal = map(wordlist.index, partial_seed_phrase)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Konvertieren wir mnemonic_in_decimalin ein Array von 11 Bit breiten Binärzahlen.

mnemonic_in_binary = map('{0:011b}'.format, mnemonic_in_decimal)
# ['00000000000', '00000000001', '00000000010', '00000000011', '00000000100', '00000000101', '00000000110', '00000000111', '00000001000', '00000001001', '00000001010']

Wir wissen, dass ein einzelnes Wort (11 Bit) an einer unbekannten Stelle in diesem Array fehlt. Unter nicht idealen Umständen müssten wir jede der 12 Stellen auf das fehlende Wort gegen jeweils 2048 mögliche Wörter prüfen, für insgesamt 24576 (12*2048 = 24576) potenzielle Master-Seeds.

for missing_word_position in range(0,12):
    # The missing word belongs at some index from 0-11 in the final 12-word phrase

    for wordlist_index in range(0, 2048):
        # Iterate over all possibilities for the missing word

        missing_word_binary = '{0:011b}'.format(wordlist_index)
        front_half          = ''.join(mnemonic_in_binary[0:missing_word_position])
        back_half           = ''.join(mnemonic_in_binary[missing_word_position:12])
        seed_and_checksum   = front_half + missing_word_binary + back_half

        seed     = seed_and_checksum[0:128]
        checksum = seed_and_checksum[-4:]

Zum Glück haben wir eine 4-Bit-Prüfsumme, was bedeutet, dass nur einer von 16 Seeds (2 4 = 16) gültig ist. Das bedeutet, dass wir am Ende eine Gesamtsumme von ungefähr 1536 Master-Seeds (24576/16 = 1536) haben werden, um auf Geldmittel zu prüfen. Die Prüfsumme wird aus den ersten Bits (in diesem Fall 4) abgeleitet, die durch Anwenden der SHA-256-Hash-Funktion auf den Seed zurückgegeben werden, sodass die endgültige Anzahl gültiger Master-Seeds variieren kann, aber im Durchschnitt bei etwa 1/16 liegt insgesamt mögliche Samen.

[ Mehr folgt später, wenn jemand helfen möchte, Beschreibungen oder Code für einen der folgenden Schritte zu schreiben, würde ich es schätzen! ]

Machen:

  1. Berechnen Sie die actual_checksum aus den ersten 4 Bits von sha256 (Seed)
  2. Vergleichen Sie die Prüfsumme mit der aktuellen_Prüfsumme. Wenn sie gleich sind, schieben Sie den Seed in ein Array gültiger Master-Seeds.
  3. Berechnen Sie den Master-Knoten, der HMAC-SHA512 (Seed) ist.
  4. Berechnen Sie ein Konto von der Masternode
  5. Berechnen Sie eine Wallet-Kette aus dem Konto
  6. Berechnen Sie die ersten 5 privaten Schlüssel in der Wallet-Kette
  7. Berechnen Sie die ersten 5 öffentlichen Schlüssel aus diesen privaten Schlüsseln
  8. Schreiben Sie eine Beschreibung und Schritte zum Wiederherstellen von Teilphrasen für BIP44-Geldbörsen auf
  9. Schreiben Sie ein Programm, um entweder eine Blockchain lokal oder eine Blockchain-Explorer-API online abzufragen. Übergeben Sie ihm die kombinierte Liste der generierten öffentlichen Schlüssel und prüfen Sie, ob irgendwelche einen Saldo haben.