În criptomonede, o cheie privată permite utilizatorului să aibă acces la portofelul său. Persoana care deține cheia privată controlează pe deplin monedele din portofelul respectiv. Din acest motiv, ar trebui să îl păstrați secret. Și dacă doriți cu adevărat să generați singur cheia, este logic să o generați într-un mod sigur.

Aici, voi oferi o introducere a cheilor private și vă voi arăta cum puteți genera propria cheie utilizând diferite funcții criptografice. Voi oferi o descriere a algoritmului și a codului în Python.

Trebuie să generez o cheie privată?

De cele mai multe ori nu. De exemplu, dacă utilizați un portofel web precum Coinbase sau Blockchain.info, acestea creează și gestionează cheia privată pentru dvs. La fel este și pentru schimburi.

Portofelele mobile și desktop generează, de obicei, și o cheie privată pentru dvs., deși ar putea avea opțiunea de a crea un portofel din propria cheie privată.

Deci, de ce să o generăm oricum? Iată motivele pe care le am:

  • Vrei să te asiguri că nimeni nu știe cheia
  • Vrei doar să afli mai multe despre criptografie și generarea numerelor aleatorii (RNG)

Ce este mai exact o cheie privată?

În mod formal, o cheie privată pentru Bitcoin (și multe alte criptomonede) este o serie de 32 de octeți. Acum, există multe modalități de a înregistra acești octeți. Poate fi un șir de 256 de unuri și zerouri (32 * 8 = 256) sau 100 de aruncări de zaruri. Poate fi un șir binar, șir Base64, a Cheie WIF, frază mnemonică, sau în cele din urmă, un șir hexagonal. În scopul nostru, vom folosi un șir hexagonal lung de 64 de caractere.

Cum sa va generati propria cheie privata Bitcoin
Aceeași cheie privată, scrisă în diferite formate.

De ce exact 32 de octeți? Marea întrebare! Vedeți, pentru a crea o cheie publică dintr-una privată, Bitcoin folosește ECDSA, sau Algoritmul semnăturii digitale a curbei eliptice. Mai precis, folosește o anumită curbă numită secp256k1.

Acum, această curbă are un ordin de 256 de biți, ia 256 de biți ca intrare și scoate numere întregi de 256 de biți. Iar 256 de biți reprezintă exact 32 de octeți. Deci, pentru a spune altfel, avem nevoie de 32 de octeți de date pentru a alimenta acest algoritm de curbă.

Există o cerință suplimentară pentru cheia privată. Deoarece folosim ECDSA, cheia ar trebui să fie pozitivă și ar trebui să fie mai mică decât ordinea curbei. Ordinea secp256k1 este FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141, care este destul de mare: aproape orice număr de 32 de octeți va fi mai mic decât acesta.

Metoda naivă

Deci, cum generăm un număr întreg de 32 de octeți? Primul lucru care îți vine în minte este să folosești doar o bibliotecă RNG în limba preferată. Python oferă chiar și un mod drăguț de a genera doar biți:

import random
bits = random.getrandbits(256)
# 30848827712021293731208415302456569301499384654877289245795786476741155372082
bits_hex = hex(bits)
# 0x4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32
private_key = bits_hex[2:]
# 4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32

Arată bine, dar de fapt nu este. Vedeți, bibliotecile RNG normale nu sunt destinate criptografiei, deoarece nu sunt foarte sigure. Acestea generează numere pe baza unui seed și, în mod implicit, seed este ora curentă. În acest fel, dacă știți aproximativ când am generat biții de mai sus, tot ce trebuie să faceți este să forțați brutal câteva variante.

Când generați o cheie privată, doriți să fiți extrem de sigur. Amintiți-vă, dacă cineva învață cheia privată, poate fura cu ușurință toate monedele din portofelul corespunzător și nu aveți nicio șansă să le recuperați vreodată.

Deci, să încercăm să o facem mai sigur.

RNG puternic criptografic

Împreună cu o metodă standard RNG, limbajele de programare oferă de obicei un RNG special conceput pentru operațiuni criptografice. Această metodă este de obicei mult mai sigură, deoarece atrage entropia direct din sistemul de operare. Rezultatul unui astfel de RNG este mult mai greu de reprodus. Nu o poți face cunoscând timpul generației sau având sămânța, pentru că nu există sămânță. Ei bine, cel puțin utilizatorul nu introduce un seed – mai degrabă, este creat de program.

În Python, RNG criptografic puternic este implementat în secrets modul. Să modificăm codul de mai sus pentru a asigura securitatea generației de chei private!

import secrets
bits = secrets.randbits(256)
# 46518555179467323509970270980993648640987722172281263586388328188640792550961
bits_hex = hex(bits)
# 0x66d891b5ed7f51e5044be6a7ebe4e2eae32b960f5aa0883f7cc0ce4fd6921e31
private_key = bits_hex[2:]
# 66d891b5ed7f51e5044be6a7ebe4e2eae32b960f5aa0883f7cc0ce4fd6921e31

Asta este incredibil. Pun pariu că nu vei putea reproduce acest lucru, chiar și cu acces la computerul meu. Dar putem merge mai adânc?

Site-uri specializate

Există site-uri care generează numere aleatorii pentru dvs. Vom lua în considerare doar două aici. Unul este random.org, un bine-cunoscut generator de numere aleatorii cu scop general. Un altul este bitaddress.org, care este conceput special pentru generarea de chei private Bitcoin.

Poate sa random.org ne ajutați să generăm o cheie? Cu siguranță, așa cum au făcut-o serviciu pentru generarea de octeți aleatori. Dar aici apar două probleme. Random.org susține că este un generator cu adevărat aleatoriu, dar poți avea încredere în el? Poți fi sigur că este într-adevăr aleatoriu? Puteți fi sigur că proprietarul nu înregistrează toate rezultatele generației, în special cele care arată ca chei private? Răspunsul depinde de tine. Oh, și nu îl puteți rula local, ceea ce reprezintă o problemă suplimentară. Această metodă nu este 100% sigură.

Acum, bitaddress.org este o poveste cu totul diferită. Este open source, astfel încât să puteți vedea ce se află sub capota sa. Este partea clientului, deci îl puteți descărca și rula local, chiar și fără conexiune la Internet.

Deci, cum funcționează? Te folosește – da, tu – ca sursă de entropie. Vă cere să mutați mouse-ul sau să apăsați tastele aleatorii. O faci suficient de mult timp pentru a face imposibilă reproducerea rezultatelor.

Cum sa va generati propria cheie privata Bitcoin
Procesul de generare a unei entropii prin mișcarea aleatorie a mouse-ului. Bucata mare de simboluri arată piscina.

Ești interesat să vezi cum bitaddress.org lucrări? În scopuri educaționale, vom analiza codul acestuia și vom încerca să îl reproducem în Python.

Notă rapidă: bitaddress.org vă oferă cheia privată într-un format WIF comprimat, care este aproape de Format WIF despre care am discutat înainte. În scopurile noastre, vom face ca algoritmul să returneze un șir hexagonal, astfel încât să îl putem folosi mai târziu pentru o generație de chei publice.

Bitaddress: specificul

Bitaddress creează entropia în două forme: prin mișcarea mouse-ului și prin presiunea cheii. Vom vorbi despre amândouă, dar ne vom concentra pe apăsarea tastelor, deoarece este greu să implementezi urmărirea mouse-ului în Python lib. Ne vom aștepta ca utilizatorul final să introducă butoane până când vom avea suficientă entropie, apoi vom genera o cheie.

Bitaddress face trei lucruri. Inițializează matrița de octeți, încercând să obțină cât mai multă entropie posibilă de pe computer, umple matricea cu intrarea utilizatorului și apoi generează o cheie privată.

Bitaddress folosește matricea de 256 de octeți pentru a stoca entropia. Această matrice este rescrisă în cicluri, așa că atunci când matricea este umplută pentru prima dată, indicatorul merge la zero, iar procesul de umplere începe din nou.

Programul inițiază o matrice cu 256 de octeți din window.crypto. Apoi, scrie un timestamp pentru a obține încă 4 octeți de entropie. În cele din urmă, primește date precum dimensiunea ecranului, fusul orar, informații despre pluginurile browserului, localizarea dvs. și multe altele. Asta îi oferă încă 6 octeți.

După inițializare, programul așteaptă continuu introducerea utilizatorului pentru a rescrie octeții inițiali. Când utilizatorul deplasează cursorul, programul scrie poziția cursorului. Când utilizatorul apasă butoanele, programul scrie codul de caractere al butonului apăsat.

În cele din urmă, bitaddress folosește entropia acumulată pentru a genera o cheie privată. Trebuie să genereze 32 de octeți. Pentru această sarcină, bitaddress utilizează un algoritm RNG numit ARC4. Programul inițializează ARC4 cu ora curentă și entropia colectată, apoi primește octeți unul câte unul de 32 de ori.

Aceasta este o simplificare excesivă a modului în care funcționează programul, dar sper că veți avea ideea. Puteți verifica algoritmul în detaliu pe Github.

Făcând-o singur

În scopul nostru, vom construi o versiune mai simplă a bitaddress. În primul rând, nu vom colecta date despre computerul și locația utilizatorului. În al doilea rând, vom introduce entropia doar prin text, deoarece este destul de dificil să primești continuu poziția mouse-ului cu un script Python (bifează PyAutoGUI dacă vrei să faci asta).

Aceasta ne aduce la specificația formală a bibliotecii noastre generator. În primul rând, va inițializa o matrice de octeți cu RNG criptografic, apoi va umple marca de timp și, în cele din urmă, va umple șirul creat de utilizator. După ce grupul de semințe este umplut, biblioteca îi va permite dezvoltatorului să creeze o cheie. De fapt, vor putea crea oricâte chei private doresc, toate asigurate de entropia colectată.

Inițializarea bazinului

Aici am pus niște octeți din RNG criptografic și un timestamp. __seed_int și __seed_byte sunt două metode de ajutor care inserează entropia în matricea noastră de pool. Observați că folosim secrets.

def __init_pool(self):
    for i in range(self.POOL_SIZE):
        random_byte = secrets.randbits(8)
        self.__seed_byte(random_byte)
    time_int = int(time.time())
    self.__seed_int(time_int)
def __seed_int(self, n):
    self.__seed_byte(n)
    self.__seed_byte(n >> 8)
    self.__seed_byte(n >> 16)
    self.__seed_byte(n >> 24)
def __seed_byte(self, n):
    self.pool[self.pool_pointer] ^= n & 255
    self.pool_pointer += 1
    if self.pool_pointer >= self.POOL_SIZE:
        self.pool_pointer = 0

Semănat cu intrare

Aici punem mai întâi un timestamp și apoi șirul de intrare, caracter cu caracter.

def seed_input(self, str_input):
    time_int = int(time.time())
    self.__seed_int(time_int)
    for char in str_input:
        char_code = ord(char)
        self.__seed_byte(char_code)

Generarea cheii private

Această parte ar putea arăta greu, dar este de fapt foarte simplă.

În primul rând, trebuie să generăm un număr de 32 de octeți folosind pool-ul nostru. Din păcate, nu ne putem crea doar ale noastre random obiect și utilizați-l numai pentru generația de chei. În schimb, există un obiect partajat care este utilizat de orice cod care rulează într-un singur script.

Ce înseamnă asta pentru noi? Înseamnă că în fiecare moment, oriunde în cod, unul simplu random.seed(0) poate distruge toată entropia noastră colectată. Nu vrem asta. Din fericire, Python oferă getstate și setstate metode. Deci, pentru a ne salva entropia de fiecare dată când generăm o cheie, ne amintim de starea la care ne-am oprit și o setăm data viitoare când vrem să facem o cheie.

În al doilea rând, ne asigurăm doar că cheia noastră se află în raza de acțiune (1, CURVE_ORDER). Aceasta este o cerință pentru toate cheile private ECDSA. CURVE_ORDER este ordinea curbei secp256k1, care este FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141.

În cele din urmă, pentru comoditate, convertim în hex și dezizolăm partea ‘0x’.

def generate_key(self):
    big_int = self.__generate_big_int()
    big_int = big_int % (self.CURVE_ORDER — 1) # key < curve order
    big_int = big_int + 1 # key > 0
    key = hex(big_int)[2:]
    return key
def __generate_big_int(self):
    if self.prng_state is None:
    seed = int.from_bytes(self.pool, byteorder=’big’, signed=False)
    random.seed(seed)
    self.prng_state = random.getstate()
    random.setstate(self.prng_state)
    big_int = random.getrandbits(self.KEY_BYTES * 8)
    self.prng_state = random.getstate()
    return big_int

În acțiune

Să încercăm să folosim biblioteca. De fapt, este foarte simplu: puteți genera o cheie privată în trei linii de cod!

kg = KeyGenerator()
kg.seed_input(‘Truly random string. I rolled a dice and got 4.’)
kg.generate_key()
# 60cf347dbc59d31c1358c8e5cf5e45b822ab85b79cb32a9f3d98184779a9efc2

O poți vedea singur. Cheia este aleatorie și total valabilă. Mai mult, de fiecare dată când rulați acest cod, obțineți rezultate diferite.

Concluzie

După cum puteți vedea, există o mulțime de moduri de a genera chei private. Se diferențiază prin simplitate și securitate.

Generarea unei chei private este doar un prim pas. Următorul pas este extragerea unei chei publice și a unei adrese de portofel pe care le puteți utiliza pentru a primi plăți. Procesul de generare a unui portofel diferă pentru Bitcoin și Ethereum și intenționez să scriu încă două articole pe acest subiect.

Dacă vrei să te joci cu codul, l-am publicat la acest lucru Depozit Github.

Fac un curs despre criptomonede aici pe Routech News. Prima parte este o descriere detaliată a blockchain-ului.

De asemenea, postez gânduri aleatorii despre cripto pe Stare de nervozitate, deci este posibil să doriți să o verificați.