Kaip sukurti savo asmeninį „Bitcoin“ privatųjį raktą

Kriptovaliutomis privatus raktas leidžia vartotojui pasiekti savo piniginę. Asmuo, turintis privatų raktą, visiškai kontroliuoja tos piniginės monetas. Dėl šios priežasties turėtumėte tai laikyti paslaptyje. Ir jei jūs tikrai norite sugeneruoti raktą patys, prasminga jį sugeneruoti saugiu būdu.

Čia pateiksiu asmeninių raktų įvadą ir parodysiu, kaip galite sugeneruoti savo raktą naudodami įvairias kriptografines funkcijas. Pateiksiu algoritmo ir „Python“ kodo aprašymą.

Ar man reikia sugeneruoti privatų raktą?

Dažniausiai to nedarote. Pavyzdžiui, jei naudojate internetinę piniginę, pvz., „Coinbase“ ar „Blockchain.info“, jie sukuria ir tvarko jums asmeninį raktą. Tai tas pats ir mainams.

Mobiliosios ir darbalaukio piniginės paprastai taip pat sugeneruoja jums privatų raktą, nors jose gali būti galimybė sukurti piniginę iš savo asmeninio rakto.

Taigi kodėl vis tiek jį generuoti? Štai priežastys, kurias turiu:

  • Norite įsitikinti, kad niekas nežino rakto
  • Jūs tiesiog norite sužinoti daugiau apie kriptografiją ir atsitiktinių skaičių generavimą (RNG)

Kas iš tikrųjų yra privatus raktas?

Formaliai privatus „Bitcoin“ (ir daugelio kitų kriptovaliutų) raktas yra 32 baitų serija. Dabar yra daug būdų įrašyti šiuos baitus. Tai gali būti 256 vienetų ir nulių eilutė (32 * 8 = 256) arba 100 kauliukų. Tai gali būti dvejetainė eilutė, „Base64“ eilutė, WIF raktas, atmintinė frazė arba galiausiai šešiakampė eilutė. Savo tikslams naudosime 64 simbolių ilgio šešiakampę eilutę.

Kodėl būtent 32 baitai? Puikus klausimas! Matote, kad kurdamas viešąjį raktą iš privataus, „Bitcoin“ naudoja ECDSA arba „Elliptic Curve Digital Signature Algorithm“. Tiksliau, ji naudoja vieną konkrečią kreivę, vadinamą secp256k1 .

Dabar šios kreivės eilė yra 256 bitai, įvestis yra 256 bitai, o 256 bitų skaičiai išvedami. 256 bitai yra lygiai 32 baitai. Taigi, kitaip tariant, mums reikia 32 baitų duomenų, kad būtų galima pateikti šį kreivės algoritmą.

Privalomas privatus raktas. Kadangi mes naudojame ECDSA, raktas turėtų būti teigiamas ir mažesnis už kreivės eiliškumą. Sekp256k1 tvarka FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141yra gana didelė: beveik bet koks 32 baitų skaičius bus mažesnis už ją.

Naivus metodas

Taigi, kaip generuoti 32 baitų sveikąjį skaičių? Pirmas dalykas, kuris ateina į galvą, yra tiesiog naudoti RNG biblioteką pasirinkta kalba. „Python“ netgi suteikia mielą būdą sukurti pakankamai bitų:

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

Atrodo gerai, bet iš tikrųjų taip nėra. Matote, įprastos RNG bibliotekos nėra skirtos kriptografijai, nes nėra labai saugios. Jie generuoja skaičius pagal sėklą, o pagal numatytuosius nustatymus sėklos yra dabartinis laikas. Tokiu būdu, jei maždaug žinote, kada aš sugeneravau aukščiau esančius bitus, jums tereikia kelis variantus padaryti grubia jėga.

Kai generuojate privatų raktą, norite būti ypač saugūs. Atminkite, kad jei kas nors sužino privatų raktą, jis gali lengvai pavogti visas monetas iš atitinkamos piniginės, ir jūs neturite jokių šansų jas kada nors susigrąžinti.

Taigi pabandykime tai padaryti saugiau.

Kriptografiškai stiprus RNG

Kartu su standartiniu RNG metodu programavimo kalbos paprastai pateikia RNG, specialiai sukurtą kriptografinėms operacijoms. Šis metodas paprastai yra daug saugesnis, nes jis ištraukia entropiją tiesiai iš operacinės sistemos. Tokio RNG rezultatą daug sunkiau atkurti. Negalite to padaryti žinodami kartos laiką ar turėdami sėklą, nes sėklos nėra. Na, bent jau vartotojas neįveda pradinės informacijos - ją sukuria programa.

„Python“ secretsmodulyje įdiegta kriptografiškai stipri RNG . Pakeiskite aukščiau pateiktą kodą, kad privačių raktų generavimas būtų saugus!

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

Tai nuostabu. Lažinuosi, kad to negalėsite atkurti, net turėdami prieigą prie mano kompiuterio. Bet ar galime gilintis?

Specializuotos svetainės

Yra svetainių, kurios generuoja jums atsitiktinius skaičius. Čia apsvarstysime tik du. Vienas iš jų yra random.org, gerai žinomas bendrosios paskirties atsitiktinių skaičių generatorius. Kitas yra „bitaddress.org“, sukurtas specialiai „Bitcoin“ privačių raktų generavimui.

Ar random.org gali padėti mums sugeneruoti raktą? Tikrai, nes jie turi atsitiktinių baitų generavimo paslaugą. Tačiau čia kyla dvi problemos. „Random.org“ teigia esąs tikrai atsitiktinis generatorius, bet ar galite juo pasitikėti? Ar galite būti tikri, kad tai tikrai atsitiktinis? Ar galite būti tikri, kad savininkas neužfiksuoja visų kartos rezultatų, ypač tų, kurie atrodo kaip privatūs raktai? Atsakymas priklauso nuo jūsų. O ir jūs negalite jo paleisti vietoje, o tai yra papildoma problema. Šis metodas nėra 100% saugus.

Dabar „bitaddress.org“ yra visai kita istorija. Tai atvirojo kodo, todėl galite pamatyti, kas yra po jo gaubtu. Tai kliento pusė, todėl ją galite atsisiųsti ir paleisti vietoje, net neturėdami interneto ryšio.

Taigi kaip tai veikia? Jis naudoja jus - taip, jūs - kaip entropijos šaltinį. Jis prašo perkelti pelę arba paspausti atsitiktinius klavišus. Tai darote pakankamai ilgai, kad būtų neįmanoma atkurti rezultatų.

Ar norite sužinoti, kaip veikia bitaddress.org? Švietimo tikslais mes pažvelgsime į jo kodą ir bandysime jį atkurti „Python“.

Greita pastaba: bitaddress.org suteikia privatųjį raktą suglaudintu WIF formatu, kuris yra artimas anksčiau aptartam WIF formatui. Savo tikslais mes priversime algoritmą grąžinti šešioliktainę eilutę, kad vėliau galėtume ją naudoti viešojo rakto generavimui.

„Bitaddress“: specifika

„Bitaddress“ sukuria entropiją dviem pavidalais: pelės judesiu ir mygtuko paspaudimu. Kalbėsime apie abu dalykus, tačiau daugiausia dėmesio skirsime klavišų paspaudimams, nes „Python lib“ sunku įdiegti pelės stebėjimą. Mes tikimės, kad galutinis vartotojas suras mygtukus, kol turėsime pakankamai entropijos, tada sugeneruosime raktą.

„Bitaddress“ daro tris dalykus. Jis inicijuoja baitų masyvą, bandydamas iš jūsų kompiuterio gauti kuo daugiau entropijos, užpildo masyvą vartotojo įvestimi ir tada sukuria privatų raktą.

„Bitaddress“ naudoja 256 baitų masyvą entropijai laikyti. Šis masyvas yra perrašomas ciklais, todėl pirmą kartą užpildžius masyvą, rodyklė eina į nulį, o pildymo procesas prasideda iš naujo.

The program initiates an array with 256 bytes from window.crypto. Then, it writes a timestamp to get an additional 4 bytes of entropy. Finally, it gets such data as the size of the screen, your time zone, information about browser plugins, your locale, and more. That gives it another 6 bytes.

After the initialization, the program continually waits for user input to rewrite initial bytes. When the user moves the cursor, the program writes the position of the cursor. When the user presses buttons, the program writes the char code of the button pressed.

Finally, bitaddress uses accumulated entropy to generate a private key. It needs to generate 32 bytes. For this task, bitaddress uses an RNG algorithm called ARC4. The program initializes ARC4 with the current time and collected entropy, then gets bytes one by one 32 times.

This is all an oversimplification of how the program works, but I hope that you get the idea. You can check out the algorithm in full detail on Github.

Doing it yourself

For our purposes, we’ll build a simpler version of bitaddress. First, we won’t collect data about the user’s machine and location. Second, we will input entropy only via text, as it’s quite challenging to continually receive mouse position with a Python script (check PyAutoGUI if you want to do that).

That brings us to the formal specification of our generator library. First, it will initialize a byte array with cryptographic RNG, then it will fill the timestamp, and finally it will fill the user-created string. After the seed pool is filled, the library will let the developer create a key. Actually, they will be able to create as many private keys as they want, all secured by the collected entropy.

Initializing the pool

Here we put some bytes from cryptographic RNG and a timestamp. __seed_int and __seed_byte are two helper methods that insert the entropy into our pool array. Notice that we use 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

Seeding with input

Here we first put a timestamp and then the input string, character by character.

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)

Generating the private key

This part might look hard, but it’s actually very simple.

First, we need to generate 32-byte number using our pool. Unfortunately, we can’t just create our own random object and use it only for the key generation. Instead, there is a shared object that is used by any code that is running in one script.

What does that mean for us? It means that at each moment, anywhere in the code, one simple random.seed(0) can destroy all our collected entropy. We don’t want that. Thankfully, Python provides getstate and setstate methods. So, to save our entropy each time we generate a key, we remember the state we stopped at and set it next time we want to make a key.

Second, we just make sure that our key is in range (1, CURVE_ORDER). This is a requirement for all ECDSA private keys. The CURVE_ORDER is the order of the secp256k1 curve, which is FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141.

Finally, for convenience, we convert to hex, and strip the ‘0x’ part.

def generate_key(self): big_int = self.__generate_big_int() big_int = big_int % (self.CURVE_ORDER — 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

In action

Let’s try to use the library. Actually, it’s really simple: you can generate a private key in three lines of code!

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

You can see it yourself. The key is random and totally valid. Moreover, each time you run this code, you get different results.

Conclusion

As you can see, there are a lot of ways to generate private keys. They differ in simplicity and security.

Generating a private key is only a first step. The next step is extracting a public key and a wallet address that you can use to receive payments. The process of generating a wallet differs for Bitcoin and Ethereum, and I plan to write two more articles on that topic.

If you want to play with the code, I published it to this Github repository.

Kuriu kursą apie kriptovaliutas čia freeCodeCamp News. Pirmoji dalis yra išsamus „blockchain“ aprašymas.

Taip pat „Twitter“ paskelbiu atsitiktines mintis apie kriptografiją, todėl galbūt norėsite tai patikrinti.