Leiten Sie Segwit-Adressen von xPub oder zPub mit PYTHON ab

Zusammenfassung

Ich raube mir die Haare und versuche, ein paar Konzepte zu verstehen. Ich möchte eine Segwit-Wallet in meinem Ledger Nano S verwenden, um ungehärtete (?) untergeordnete öffentliche Schlüssel (und damit Segwit-Adressen) abzuleiten, die mit denen übereinstimmen, die mein Nano produziert. Ich möchte dies mit Python 3 tun. Ich glaube, das Erstellen einer solchen Adresse wird als "Watch Wallet" bezeichnet oder wird zumindest in den Bip32-Dokumenten wie folgt beschrieben:

Dies ermöglicht beispielsweise einem Webshop-Unternehmen, seinen Webserver für jede Bestellung oder für jeden Kunden neue Adressen (Public Key Hashes) generieren zu lassen, ohne dem Webserver Zugriff auf die entsprechenden privaten Schlüssel (die für die Ausgabe der erhaltenen Gelder erforderlich sind) zu geben. https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Motivation

Genau das versuche ich mit Python für meine Django-Anwendung zu tun. Ich möchte keinen Drittanbieterdienst verwenden, da mir gesagt wird, dass ich der Weitergabe meines erweiterten öffentlichen Schlüssels (xPub) nicht vertrauen soll. Ich möchte den xPub von meinem Ledger Nano S verwenden. Eigentlich bin ich mir nicht ganz sicher, ob mein Nano S einen xpub oder einen zpub verwendet, aber ich habe dies in einer separaten Frage gestellt.

Hat Ledger Nano S ein xPub oder ein zPub für Bitcoin-Geldbörsen?

Unabhängig davon habe ich den "xpub"-Schlüssel in einen "zpub"-Schlüssel umgewandelt und versucht, neue Schlüssel abzuleiten, indem ich VIELE verschiedene Python-Module verwendet habe und ohne Erfolg eine Adresse erstellt habe, die mit der übereinstimmt, die mein Nano produziert, oder sogar ähnlich aussieht.

Was ich versucht habe

Um Antworten zu eliminieren, die Methoden vorschlagen, die ich bereits ausprobiert habe, finden Sie hier eine vollständige und erschöpfende Liste aller Methoden, die ich ausprobiert habe, mit Links zu allen ähnlichen Fragen auf Stack Exchange.

Zuerst habe ich btclib zusammen mit Pycoin ausprobiert .

Hinweis: In allen Beispielen versuche ich, das Bitcoin Testnet zu verwenden

from btclib import bip32
from pycoin.networks.registry import network_for_netcode

network = network_for_netcode("XTN") # XTN for the Testnet, BTC for the Mainnet
xpub = "x(z/t)pub-big-long-key-that-starts-with-tpub-zpub-xpub"

child_xpub_key = bip32.derive(xpub, "84'/1'/0'/0/0")
key = network.parse.bip32(child_xpub_key)

print(str("Key: {}").format(child_xpub_key))
print(str("Address: {}").format(key.address())) 

Ähnlich wie bei dieser Frage: Öffentlichen Schlüssel von xpub ableiten? Ich erhalte einen Fehler bei Verwendung des "gehärteten" Ableitungspfads, und damit der Fehler behoben wird, kann ich nur den Pfad 84/1/0/0/0 verwenden. Ich habe sogar Pfad 0 und 0/0 ausprobiert. Natürlich enthält der Pfad, den mein Nano mir gibt, das ('). Nach meinem Verständnis ist dieser Ableitungspfad für zpub-Schlüssel, aber selbst wenn ich in zpub konvertiere, gibt es mir keine Adresse, die zu meinem Nano passt. Ich nehme an, das liegt daran, dass ich Bip44 oder Bip84 verwenden sollte, um Adressen abzuleiten? Richtig?

Das nächste, was ich zu verwenden versuchte, war bip_utils

from bip_utils import Bip44, Bip44Coins
key_str = "x(z/t)pub-big-long-key-that-starts-with-tpub-zpub-xpub"
bip44_ctx = Bip44.FromExtendedKey(key_str, Bip44Coins.BITCOIN_TESTNET)

Dieser Code funktioniert, der Beispielcode auf der Github-Seite bip_utils legt jedoch nahe, dass die nächste Codezeile wie folgt aussehen sollte:

# Derive account 0 for Bitcoin: m/44'/0'/0'
bip44_acc = bip44_ctx.Purpose().Coin().Account(0)

Was mir den Fehler gibt

Bip44DepthError: Current depth (3) is not suitable for deriving purpose

Ich weiß bereits, dass ich m/44'/0'/0' nicht will, aber die Dokumentation gibt keinen Hinweis darauf, wie man den Pfad ändert, und ein Blick auf den Quellcode hat mir auch nicht geholfen.

Dann habe ich versucht, pybitcointools des berühmten Vitalik Buterin zu verwenden. Er hat sogar einen Teil in den Dokumenten über "Wallets beobachten":

Aus Sicherheitsgründen sollten Seed und xprv idealerweise nur im Kühlhaus aufbewahrt werden. Wenn eine Webanwendung in der Lage sein muss, Adressen auf Abruf bereitzustellen, besteht die Lösung darin, eine Watch-Wallet zu verwenden, die aus dem xpub generiert wird. Nehmen wir zum Beispiel das Dash xpub aus einem vorherigen Beispiel:

from cryptos import *
coin = Dash()
xpub = 'xpub-some-xpub-key'
wallet = coin.watch_wallet(xpub)
wallet.is_watching_only
wallet.new_receiving_address()
wallet.new_change_address()

Ich denke: "Das ist es, Vitalik ist mein Held! Er weiß, wonach ich suche!" Aber NEIN, dieser Beispielcode funktioniert anscheinend nur für Dash. Wenn ich die Klasse auf Bitcoin() ändere, funktioniert keine der in der Dokumentation beschriebenen „watch_wallet“-Methoden, oder sie existieren nicht. Nirgendwo ist ein Beispiel dafür, wie man das mit Bitcoin zum Laufen bringt.

Abschluss

Von allen Methoden, die ich ausprobiert habe, hat mir zumindest btclib keine Fehler gegeben. Ich könnte diese Python-Module falsch verwenden oder vielleicht gibt es ein besseres Python-Modul / eine bessere Klasse, die ich verwenden sollte. Jede Richtung wäre hilfreich. Vielen Dank im Voraus.

Sie könnten das mit python-bip32 tun, aber Sie müssten den what-pub vorher in ein richtiges xpub konvertieren, siehe github.com/darosior/python-bip32/pull/21 . BEARBEITEN: Eigentlich haben Sie auch xpubs erwähnt, in diesem Fall können Sie die Verwendung hier überprüfen github.com/darosior/python-bip32#usage

Antworten (2)

Da Sie mit xPubs keine gehärteten Pfade durchlaufen können, zeigt das Hauptbuch nicht den Master-XPUB an, sondern den XPUB an der Ableitungsadresse 84/0'/0'oder was auch immer Ihre Kontonummer ist. Von dort benötigen Sie zwei zusätzliche Ableitungen von 0/0, um den endgültigen 84/0'/0'/0/0öffentlichen Schlüssel zu erhalten.

Der resultierende öffentliche Schlüssel kann verwendet werden, um entweder eine P2PKH-Adresse (Nicht-Segwit) oder eine P2WPKH-Adresse (Segwit) abzuleiten. Xpub und Zpub sind beide Codierungen desselben Schlüssels, aber Zpub weist die Brieftasche zusätzlich an, eine P2WPKH-Adresse daraus abzuleiten. Ledger verwendet diesen Standard nicht und kodiert ihn lieber mit der allgemeineren Xpub-Kodierung (die keine Anweisungen enthält).

Mit meiner Spielzeug-Python-Bibliothek können Sie das folgende Skript verwenden, um Ihre Adressen abzuleiten:

from cryptotools import Xpub

MY_XPUB = 'xpub-as-shown-in-ledger'

key = Xpub.decode(MY_XPUB)

pubkey0 = key/0/0
print(pubkey0.address('P2WPKH'))  # Tell the wallet that you want a P2WPKH address

Wenn Sie Testnet-Adressen wünschen, setzen Sie die envvar CRYPTOTOOLS_NETWOK = 'test'

Es funktionierte wie ein Zauber! Danke schön. Ich habe mir den Quellcode genau angesehen und ihn auch gegabelt. Ihren Angaben zufolge haben Sie einen Haftungsausschluss zur Sicherheit. Gibt es etwas, das ich beachten sollte?

Pycoin unterstützt jetzt nach diesem Commit segwit xpub . Es kann xpub/ypub/zpub parsen und Adressen ableiten. Ledger verwendet immer noch ein falsches Präfix für segwit xpub und Sie müssen möglicherweise das xpub entsprechend in ypub/zpub umwandeln