[PYTHON] Verstehen Sie das Protokoll der Kryptowährung (Bitcoin, Monacoin): öffentliche und private Schlüssel

Überblick

In den letzten Jahren sind Kryptowährungen wie Bitcoin und Litecoin ein heißes Thema geworden (zum Guten oder Schlechten). Kryptowährung ist derzeit extrem chaotisch und Hunderte von Derivatwährungen (Alt-Währungen) waren bisher überfüllt, aber auch hier in Japan wurde kürzlich eine Derivatwährung aus Japan namens "Monacoin" geboren, die in der Ecke von 2ch geheim ist. Zeigt Aufregung. Dieser Autor ist derjenige, der die sogenannte Kryptowährungsversion des gumroad-Webdienstes "Monapay" ausführt.

Zuvor habe ich aus einer Laune heraus die folgende Art von Spiel vorgeschlagen und auf 2ch eingefügt.

Ich möchte ein Spiel mit einem Preis für Werbung + Zeit zum Töten spielen. Der Inhalt ist "Steal my monacoin"

M9WJPA8npJQEwcxXwvzKHwWz5msQfEKzf5 Ich habe gerade 10MONA an diese Adresse hinterlegt. Sie können bei Abe nachfragen, ob die Einzahlung tatsächlich erfolgt ist. Und hier ist der in Base64 codierte private Rohschlüssel. 0fHys0+Iy89GnEUfA0ZCJ652Tf8409Yor4ekLdazlXE= Als ich vor langer Zeit eine Bitcoin-Geschenkkarte im Fernsehen kopierte, wurde sie von Sokko gestohlen. Das gleiche passiert. Durch die Bereitstellung des privaten Schlüssels im Internet kann jeder die 10MONA an dieser Adresse hinterlegen lassen.

Das Spiel ist super einfach. Bitte verwenden Sie diesen privaten Schlüssel so schnell wie möglich, um 10MONA von dieser Adresse zu stehlen. Kannst du wirklich ein Hacker sein? ?? Mach was der Fernsehmoderator gemacht hat! (Wenn es sich um einen Fernseher handelt, wird er in Eile gestohlen, aber wenn er diesmal nicht gestohlen wird, werden täglich 10 MONA hinzugefügt.)

10MONA bezieht sich auf die Monacoin-Währung, bei der es sich um eine Kryptowährung handelt. Der einfache Grund, dieses "Diebstahlproblem" vorzuschlagen, ist, dass ich mich gefragt habe, wie viele Leute dieses Problem tatsächlich lösen können. Ich dachte, dass es wie erwartet mehr als einen Tag dauern würde, aber das tatsächliche Ergebnis erschien zum ersten Mal 2 Stunden nach dem Einfügen, und Schließlich gelang es insgesamt 3 Personen, es zu erfassen. Ich habe es getan. 10MONA war mit etwa 5,60 Yen billig, als es in den aktuellen japanischen Yen umgerechnet wurde, aber ich war froh, dass es Leute gab, die dieses Problem herausforderten und lösten (Dank an diejenigen, die zusammengearbeitet haben). Es gibt).

Um dieses Problem zu lösen, muss der private Schlüssel in ein Format namens Wallet Import Format konvertiert und vom Monacoin-Client gelesen werden. Zu diesem Zweck müssen jedoch nicht nur Kenntnisse über Kryptowährungen, sondern auch [Monacoin-Quellcode] vorliegen. Sie müssen lesen (https://github.com/monacoinproject/monacoin). Der Zweck dieses Artikels ist es, einen Kommentar zu diesem Thema abzugeben und gleichzeitig Ihr Wissen über die Protokolle Bitcoin und Monacoin zu vertiefen. Derzeit gibt es fast keine technischen japanischen Artikel zu Kryptowährungen, daher denke ich, dass dies bis zu einem gewissen Grad nützlich sein wird.

Darüber hinaus enthält dieser Artikel zur Erläuterung auch Python-Code. Außerdem wird am Ende ein weiteres Diebstahlspiel als Übung veröffentlicht. Der Preis ist klein, aber ich habe nicht viel Geld zur Hand, bitte vergib mir.

Spenden werden immer angenommen :) MKrJpLy8Dg8mATKdH5zWCYiUVYQGvVW5Sx

Elektronische Unterschrift

Wie Sie wissen, haben viele Kryptowährungen, einschließlich Bitcoin und Monacoin, den gesamten Transaktionsverlauf (Transaktionen) in der "[Blockchain]( Es besteht aus einer verteilten Datenbank bestehend aus "https://en.bitcoin.it/wiki/Block_chain)". Der Benutzer führt eine tatsächliche Transaktion durch, indem er die Details der Transaktion, die er ausführen möchte, in diese riesige Datenbank schreibt. Mit anderen Worten, eine Überweisung in Kryptowährung entspricht dem Schreiben einer Transaktion mit dem Inhalt "Senden des Geldbetrags auf Ihrem (A) Konto an B" an die Blockchain.

Das Problem, das hier auftritt, ist, dass es notwendig ist zu beweisen, dass "die Person, die die Überweisung von A's Konto angewiesen hat, wirklich A selbst ist?" Um dies zu beweisen, verwendet Monacoin einen Verschlüsselungsalgorithmus mit öffentlichem Schlüssel, um zu überprüfen, ob der Benutzer, der das Schreiben der Transaktion geleitet hat, tatsächlich der Eigentümer des Kontos ist. Lass uns genauer hinschauen:

relationship.png

Die Verschlüsselung mit öffentlichem Schlüssel besteht aus zwei Schlüsselpaaren: * privater Schlüssel * und * öffentlicher Schlüssel *. Im Fall von Monacoin ist der private Schlüssel eine 256-Bit-Sequenz und der öffentliche Schlüssel eine 512-Bit-Sequenz. Der private Schlüssel wird verwendet, um zu beweisen, dass die Person, die das Schreiben der Transaktion geleitet hat, A ist. Stellen Sie sich so etwas wie ein Siegel oder eine Unterschrift in der realen Welt vor. Indem Sie die Transaktion mit einem privaten Schlüssel signieren, können Sie nachweisen, dass die Person, die das Schreiben der Transaktion geleitet hat, A ist. Diese Informationen sollten niemals nach außen weitergegeben werden, da jeder A fälschen und anweisen kann, Geld von A's Konto zu überweisen, wenn der private Schlüssel online durchgesickert ist.

Der private Schlüssel wird im Allgemeinen hexadezimal ausgedrückt, ist jedoch etwas redundant zu tragen, da er so wie er ist 64 Zeichen hat. Sie möchten auch, dass eine Prüfsumme angibt, ob dies wirklich eine Zeichenfolge ist, die den privaten Schlüssel von Monacoin darstellt. Daher bietet Monacoin auch ein Format namens * Wallet Import Format (WIF) *, das eine präzisere Darstellung des privaten Schlüssels darstellt. Das Wort "privater Schlüssel" in Monacoin bezieht sich im Allgemeinen eher auf WIF als auf den rohen privaten Schlüssel. Da der private Rohschlüssel und WIF dieselben Informationen darstellen, können Sie den privaten Rohschlüssel von WIF beziehen und umgekehrt.

Fahren wir als nächstes mit der Erläuterung des öffentlichen Schlüssels fort. Der öffentliche Schlüssel ist die öffentliche Information, die in die Blockchain eingegeben wird und zum Überprüfen der Signatur mit dem privaten Schlüssel verwendet wird. Alle mit dem Monacoin-Netzwerk verbundenen Benutzer überprüfen, ob der Verfasser der Transaktion A ist, indem sie diesen öffentlichen Schlüssel mit der elektronischen Signatur vergleichen. Beachten Sie, dass Sie einen öffentlichen Schlüssel aus einem privaten Schlüssel generieren können, aber nicht umgekehrt.

Da der öffentliche Schlüssel 512 Bit groß ist, ist er etwas zu groß, um ihn so wie er ist in ein Blog oder Bulletin Board einzufügen. Um dieses Problem zu beheben, bietet Monacoin eine kürzere Darstellung des öffentlichen Schlüssels. Dies ist die allgemein bekannte "Monacoin-Brieftaschenadresse". Beachten Sie, dass es zwar einfach ist, eine Brieftaschenadresse aus einem öffentlichen Schlüssel zu generieren, Sie jedoch keinen öffentlichen Schlüssel aus einer Brieftaschenadresse generieren können.

Konvertierungsmethode

Nun wollen wir sehen, wie ein bestimmter privater und öffentlicher Schlüssel generiert wird. Das Generieren einer Monacoin-Adresse umfasst drei Hauptschritte: (1) Generieren eines privaten Schlüssels (2) Generieren eines öffentlichen Schlüssels aus einem privaten Schlüssel (3) Generieren einer Adresse aus einem öffentlichen Schlüssel. Darüber hinaus sind auch die in der obigen Abbildung (A) Generieren von WIF aus privatem Schlüssel (B) Generieren von Privatschlüssel aus WIF erwähnten Vorgänge wichtig. Daher werden wir erklären, wie dies getan wird.

(1) Generieren Sie einen privaten Schlüssel

Es gibt keine bestimmte Regel dafür, dass es sich um einen privaten Schlüssel handelt, und 256 Bit reichen aus. Im Allgemeinen werden echte Zufallszahlen verwendet, die von Zufallsgeneratoren wie "/ dev / random /" erhalten wurden. Aus Sicherheitsgründen ist es wünschenswert, die Verwendung von Pseudozufallszahlen zu vermeiden, die nicht kryptografisch sicher sind, wie z. B. Mercenne Twister.

def make_private_key():
    return os.urandom(32)  # 32 = 256/8

Das Ergebnis der Ausführung ist wie folgt:

>>> private_key = make_private_key()
>>> print(private_key.encode("hex_codec"))
3954e0c9a3ce58a8dca793e214232e569ff0cb9da79689ca56d0af614227d540

(2) Generieren Sie einen öffentlichen Schlüssel aus dem privaten Schlüssel

Monacoin verwendet einen Algorithmus namens * [Elliptical Curve DSA](http://ja.wikipedia.org/wiki/Elliptical Curve DSA) * für den elektronischen Signaturalgorithmus (Parameter ist Secp256k1). Es ist schwierig, den detaillierten Mechanismus zu verstehen, aber wenn Sie ihn nur verwenden möchten, müssen Sie nur eine Standardbibliothek wie OpenSSL verwenden, daher ist es am besten, ihn zu verwenden.

Dieses Mal werden wir eine Python-Bibliothek namens ecdsa verwenden. Ich denke, es ist einfach, mit pip zu installieren.

$ pip install ecdsa

Der Python-Code zum Generieren eines öffentlichen Schlüssels aus einem privaten Schlüssel sieht folgendermaßen aus:

def private_to_public_key(private_key):
    signing_key = ecdsa.SigningKey.from_string(
        private_key, curve=ecdsa.SECP256k1)
    verifying_key = signing_key.verifying_key
    return verifying_key.to_string()

Das Ergebnis der Ausführung ist wie folgt:

>>> public_key = private_to_public_key(private_key)
>>> print(public_key.encode("hex_codec"))
47f272a8dad703f809489dfc9ea3606e206ba6a16ecbde314186a03b68326284eaecd034af5300bb6991ac5897c8163ed67894205bc1b7dd5dac8080dba2fe69

(3) Generieren Sie eine Adresse aus dem öffentlichen Schlüssel

Dieser Prozess ist etwas komplizierter als zuvor, aber nicht schwierig. Lassen Sie uns ihn nacheinander aufschlüsseln. Stellen Sie dem angegebenen öffentlichen Schlüssel zunächst "\ x04" voran (aus unbekannten Gründen). Bitte beachten Sie, dass dieses Präfix kein für Monacoin eindeutiger Wert ist, sondern ein für Bitcoin und Litecoin gemeinsamer Wert.

pk_with_prefix = "\x04" + public_key

Wenden Sie als Nächstes zwei unidirektionale Funktionen "sha256" und "ripemd160" auf diesen öffentlichen Schlüssel an, um ihn in einen 160-Bit-Hash zu konvertieren.

ripemd160 = hashlib.new('ripemd160')
ripemd160.update(hashlib.sha256(pk_with_prefix).digest())
hash160 = ripemd160.digest()

Stellen Sie diesem Hash dann "\ x32" voran. Dadurch beginnt die Brieftaschenadresse von Monacoin mit "M", wodurch die Art der Brieftaschenadresse leichter identifiziert werden kann.

vhash160 = "\x32" + hash160  # monacoin addresses start with M

Der Wert des Präfixes hängt von der Kryptowährung ab. Beispielsweise nimmt Bitcoin den Wert "\ x00" und Litecoin den Wert "\ x30" an. Wenn Sie die Präfixe anderer abgeleiteter Währungen kennen möchten, lesen Sie bitte PUBKEY_ADDRESS in src / base58.h. Für Monacoin sieht der Quellcode für src / base58.h beispielsweise folgendermaßen aus:

src/base58.h


class CBitcoinAddress : public CBase58Data
{
public:
    enum
    {
        PUBKEY_ADDRESS = 50, // Monacoin addresses start with M or N
        SCRIPT_ADDRESS = 5,
        PUBKEY_ADDRESS_TEST = 111,
        SCRIPT_ADDRESS_TEST = 196,
    };
...

Der Quellcode lautet "Start mit M oder N", aber mit Liste der Adresspräfixe zeigt "\ x32" immer auf "M". Wahrscheinlich ist der Quellcode falsch.

Fügen Sie als nächstes nach dem Hash des (8 + 160) -Bits mit diesem \ x32 eine Prüfsumme hinzu, die zum Überprüfen der Adresse verwendet wird. Viele Kryptowährungen behandeln den Wert, der durch Ausschneiden von 32 Bit vom Anfang einer Zahlenfolge erhalten wird, auf die die Hash-Funktion "sha256" zweimal als Prüfsumme angewendet wird.

def _make_checksum_for_address(data):
    code = hashlib.sha256(hashlib.sha256(data).digest()).digest()
    return code[:4]

Schließlich ist der Wert des (8 + 160) -Bit-Hashs mit einer hinzugefügten Prüfsumme Base58 (ausgenommen verwirrende Zeichen wie 0, O). Es ist in einem Codierungsformat codiert, das Daten mit 58 Zeichentypen ausdrückt.

checksum = _make_checksum_for_address(vhash160)
raw_address = vhash160 + checksum
return base58_encode(raw_address)

Es ist lange her, aber der endgültige Python-Code sieht folgendermaßen aus:

def _make_checksum_for_address(data):
    code = hashlib.sha256(hashlib.sha256(data).digest()).digest()
    return code[:4]

def public_key_to_address(public_key):
    pk_with_prefix = "\x04" + public_key
    ripemd160 = hashlib.new('ripemd160')
    ripemd160.update(hashlib.sha256(pk_with_prefix).digest())
    hash160 = ripemd160.digest()
    vhash160 = "\x32" + hash160  # monacoin addresses start with M
    checksum = _make_checksum_for_address(vhash160)
    raw_address = vhash160 + checksum
    return base58_encode(raw_address)

Das Ergebnis der Ausführung ist wie folgt:

>>> public_key_to_address(public_key)
MB3D45ngvaWRcACUmAFUf6fzcdXR8bVM6k

(A) Generieren Sie WIF aus einem privaten Schlüssel

Im Folgenden wird beschrieben, wie Sie aus einem privaten Schlüssel ein WIF generieren. Führen Sie die folgenden Schritte aus, um ein WIF zu generieren. Zunächst stellt Monacoin dem privaten Schlüssel "\ xb2" voran. Der Wert des Präfixes hängt von der Kryptowährung ab. Beispielsweise nimmt Bitcoin den Wert "\ x80" und Litecoin den Wert "\ xb0" an.

Der spezifische Wert des Präfix hängt von der PUBKEY_ADDRESS in [ src / base58.h] ab (https://github.com/monacoinproject/monacoin/blob/master/src/base58.h). Insbesondere ist der Wert von "PUBKEY_ADDRESS" plus "128" der Wert des Präfixes "PRIVKEY_ADDRESS":

src/base58.h


class CBitcoinSecret : public CBase58Data
{
public:
    enum
    {
        PRIVKEY_ADDRESS = CBitcoinAddress::PUBKEY_ADDRESS + 128,
        PRIVKEY_ADDRESS_TEST = CBitcoinAddress::PUBKEY_ADDRESS_TEST + 128,
    };
...

Fügen Sie dann nach dem Wert des privaten Schlüssels mit diesem Präfix eine Prüfsumme hinzu, um den privaten Schlüssel zu überprüfen. Viele Kryptowährungen behandeln den Wert, der durch Ausschneiden von 32 Bit vom Anfang einer Zahlenfolge erhalten wird, auf die die Hash-Funktion "sha256" zweimal als Prüfsumme angewendet wird.

def _make_checksum_for_wif(code):
    return hashlib.sha256(
        hashlib.sha256(code).digest()).digest()[:4]

Schließlich wird der Wert mit der Prüfsumme in Base58 codiert. Der endgültige Python-Code sieht folgendermaßen aus:

def _make_checksum_for_wif(code):
    return hashlib.sha256(
        hashlib.sha256(code).digest()).digest()[:4]


def private_key_to_wif(private_key):
    assert(len(private_key) == 32)
    checksum = _make_checksum_for_wif("\xb2" + private_key)
    return base58_encode("\xb2" + private_key + checksum)

Das Ergebnis der Ausführung ist wie folgt:

>>> private_key_to_wif(private_key)
6ySkrpLpwm6gKsWo2aS6EL1SZxidZNdJkKqsKRNjXzv9WSrpHjR

(B) Generieren Sie einen privaten Schlüssel aus WIF

Damit WIF einen privaten Schlüssel generiert, kehren Sie einfach die obigen Schritte um. Es ist mühsam, diesen Schritt noch einmal zu erklären, daher reicht es aus, den folgenden Python-Code zu betrachten:

def wif_to_private_key(wif):
    code = base58_decode(wif)
    prefix, private_key, checksum = code[0], code[1:33], code[33:]
    checksum_from_hex = _make_checksum_for_wif(prefix + private_key)
    assert(checksum == checksum_from_hex)
    return private_key

Übungen

Mit der bisherigen Erklärung ist es nun möglich, den privaten Schlüssel in das WIF-Format zu konvertieren. Jetzt müssen Sie nur noch dieses WIF-Format verwenden, um den privaten Schlüssel in den Monacoin-Client zu übertragen. Die spezifische Importmethode finden Sie in der Methode von Bitcoin-Wiki. Stellen Sie sicher, dass Sie eine Sicherungskopie von wallet.dat erstellen.

Abschließend eine kurze Übung als Rückblick auf die Vergangenheit. Die erste Person, die es löst, hat das Privileg, den Preis zu stehlen :)

Monacoin Brieftaschenadresse MPKWCip9CLawFKwwMBDTTp2ZWJcrkDf7rX Privater Schlüssel durch Computervirus durchgesickert 9a833fd68f30459bd6f7b718818668c5c6d20b5a2b491558cea08be63937f847 Es stellte sich heraus, zu sein. Verwenden Sie diesen privaten Schlüssel, um den vollen Betrag zu stehlen, der unter der oben angegebenen Adresse gespeichert ist.

Recommended Posts

Verstehen Sie das Protokoll der Kryptowährung (Bitcoin, Monacoin): öffentliche und private Schlüssel
Erstellen Sie mit ssh-keygen einen privaten und einen öffentlichen Schlüssel (Unterschied zwischen Windows 10 und Linux)