Author

Topic: Paano Binubuo ang Bitcoin Address? Intindihin natin ang Matematika sa likod nito (Read 267 times)

full member
Activity: 1624
Merit: 163
Madaming matututunan, ang kaso, ang daming technical terms na hindi ko alam kaya nalito ako habang nag babasa haha. Pero overall, good read sa mga gusto talagang matuto.
hero member
Activity: 1120
Merit: 553
Filipino Translator 🇵🇭

Ito ay pagsasalin lamang. Ang orihinal na thead ay makikita sa pamamagitan ng pag-click sa link na nasa itaas.


Paano Binubuo ang mga Bitcoin Address


Saklaw lamang ng thread na ito ang P2PKH address halimbawa ang address ng bitcoin na nagsisimula sa '1', na kilala rin bilang Legacy Address. Gagawa din si webtricks ng isa pang thread sa hinaharap tungkol sa kung paano lumikha ng P2SH o Bech32 address.

Ok! Magsimula na tayo sa talakayan. Upang magamit ang Bitcoin, ang user ay karaniwang nangangailangan ng dalawang bagay: Private Key at Bitcoin Address. Ang Bitcoin Address ay isang identifier na ganito ang hitsura: 18J6ai34uzGofUuzbiwhXJzKzdx1efDBqA. Dapat ibahagi ito ng sender sa nagpadala upang makatanggap ng bayad. Samantalang ang private key ay isang key kung saan ang user ay dapat mag-input sa wallet upang ma-access ang natanggap na pondo.

Maaaring alam mo na ang sinabi ko sa itaas. Ngunit naisip mo ba kung paano nabuo ang pares ng mga key na ito? Mag-dive deep muna tayo sa paksa at lumikha ng ating sariling code para sa pagbuo ng key pair. Ang pangunahin at pinakamahalagang sangkap ng Bitcoin Address ay Private Key. Talakayin muna natin ito:



Private Key

Sa madaling salita, alin man ay maaaring maging private key kung matutugunan nito ang dalawang kundisyon. Unang kundisyon, hindi ito dapat maging 0. Pangalawa, dapat itong mas mababa kaysa sa halaga ng N na tinukoy ng SECG para sa secp256k1 curve. Gayunpaman, ang value ng N ay napakalaki, napakalaki kaya halos bawat 256-bits na numero ay maituturing na private key.

Ngayon ang lumitaw na tanong ay kung paano makabubuo ng private key. Tulad ng sinabi ko sa simula na ang anuman ay maaaring maging private key. Halimbawa, ang string na ito: "Ako ay isang string upang makabuo ng private key" ay maaaring ma-convert sa private key. Ang kailangan mo lang gawin, upang mai-convert ang string na ito sa 256-bits na value at suriin kung mas mababa ito kaysa sa N.

Ngunit iminungkahi ba na bumuo ng private key sa ganitong paraan? Sa totoo lang hindi! Hindi na bago ang sabi-sabi na ang tao ay ang worst random generator. Kung gumagamit tayo ng pasadyang mga string o numero na tulad nito, maaaring posible na ang ibang tao ay gumagamit ng eksaktong parehong string na maaaring magresulta sa kompromiso ng private key. Kaya mas mahusay na maging ligtas kaysa sa magsisi at umaasa lamang sa mga random na generator upang makabuo ng private key.

Ngunit muling lumitaw ang isa pang problema. Karamihan sa mga generator tulad ng Math library ng Javascript (Math.random () function) ay gumagamit ng mga nakapirming pattern upang makabuo ng random na numero. Kaya ang user ng naturang mga generator ay makakagawa ng mas maraming mga miseries kaysa mga key. : D

Kaya ano ang pinaka-malupet na solusyon? Ang pinakamahusay na paraan ay ang paggamit ng mga key na nabuo ng mga wallet ngunit kung nais mong independiyenteng pag-dive sa paghahanap, gumamit ng ligtas na mga generator na tulad nito: strong pseudorandom generator.



Sapat na nasabi sa mga private key, pumunta na tayo sa bitaddress.org at bumuo ng isang address. Una ay gagawa tayo ng address sa bitaddress.org at pagkatapos ay subukan nating lumikha ng pareho sa pamamagitan ng ating sariling code upang malaman ang matematika sa likod ng key generation.

Narito ang key pair na nabuo ko. Maaari mong makita na mayroong higit sa isang format para sa parehong public key at private key. Pag-usapan natin ang mga ito nang maikli bago tumalon sa bahagi ng coding:


1. Public Address

Ito ang P2PKH format ng bitcoin address. Malawakang ginagamit ito para sa pagpapadala / pagtanggap ng mga bitcoin. Ang Public Key sa sandaling nabuo sa pamamagitan ng Elliptic curve cryptography na pagkatapos ay hinash gamit ang sha-256 at ripemd-160 algorithm at kalaunan ang checksum na nakalakip sa dulo ng hash na bumubuo ng public address. Susubukan nating makamit iyon mamaya sa thread na ito gamit ang totoong code.

2. WIF Private Key

Ang WIF o Wallet Import Format ay ang format ng private key kung saan ang mga wallet tulad ng Electrum import private key. Kung i-pepaste mo ang bare hex ng private key ay hindi na bubukas ang Electrum wallet. Kailangan mong i-convert ang private key sa WIF format upang magamit ito sa wallet. Isusulat natin ang code upang ma-convert din ang private key sa WIF.

3. Uncompressed Public Key

Ok! Hindi ko pa napapaliwanag ang kung paano nabuo ang public key. Ang proseso ay talagang kumplikado. Gagamit tayo ng isang espesyal na generator point na tinatawag bilang G sa pamamagitan ng SECG na matatagpuan sa secp256k1 curve. Halimbawa ang isa sa elliptic curve. Pagkatapos ay paparamihin natin ang generator point na may private key. Ang nagreresulta ng multiplication ay magbibigay sa atin ng dalawang coordinate, ang isa ay X at ang isa ay Y. Ang Uncompressed Public Key ay walang iba kundi: 04 + X + Y. Kaya't ang unang dalawang bilang ng public key ay 04 na nangangahulugang ang key ay uncompressed. Ang susunod na 64 character (32 bytes dahil sa bawat 2 character ng hex ay makakabuo ka ng 1 byte) ay ang X coordinate at huling 64 character (32 byte) ay Y coordinate. Ang kabuuang haba ng uncompressed na public key ay 130 o 65 bytes.

4. Compressed Public Key

Sapgkat, posible na makahanap ng Y coordinate kung ibinigay ang X coordinate. Kaya't sa pangkalahatan ay inilalagay natin ang Y coordinate mula sa ating public key. Samakatuwid, ang huling 64 na character ay tinatanggal. Bilang resulta, ang compressed na public key ay binubuo ng 66 na character (32 bytes). Ang unang dalawang character ay maaaring maging alinman sa 02 o 03 (sa halip na 04) at ang susunod na 64 na character (32 bytes) ay X coordinate. Kung ang value ng Y coordinate ay even kung gayon ay 02 ang ginamit. Kung ang value ng Y coordinate ay odd kung gayon ay 03 ang ginamit. Sa larawan sa itaas, ang value ng Y-coordinate ay odd kaya mayroon tayong 03 sa ating susi.

5. Private Key Hexadecimal Form

Tulad ng napag-usapan natin nang mas maaga ang private key ay dapat na 256-bits o 32 bytes (8 bits = 1 byte) na kung saan ay cinoconvert sa hexadecimal form ay may 64 na character. Kaya maaari mong mai-convert ang anumang value sa hex at ito ay sa 64 character. Ito ay madaling gamitin para sa ating bitcoin code dahil gagamitin natin ang hex form ng private key upang simulan ang pagbuo ng key pair. Kaya tulad ng sinabi ko kanina na maaari pa nating gamitin ang mga string tulad ng "Ako ay isang string upang makabuo ng private key" upang makabuo ng private key, kaya narito ang lihim. Una nating i-coconvert ang gayong mga string sa hex at pagkatapos ay gagamitin ang 64 na character ng hex upang makabuo ng key pair.

6. Private Key Base64 Form

Hindi masyadong popular ang format ng private key. Ngunit maaari pa rin nating ma-encode / mabasa ang ating private key sa Base64 gamit ang native conversion.

Sapat na para sa mag-ummpisa. Ngayon mag-dive tayo nang diretso sa code at bumuo ng key sa itaas.



Dahil fan ako ng Javascript (dahil sa palagay ko ito ang pinakamadaling programming language at maaaring magamit sa full-stack development), gumagamit ako ng JS sa Node. JS environment para sa gabay na ito. Ngunit kung komportable ka sa ibang language ay madali mong maiintindihan JS code sa iyong code. Sa huli, kung hindi ka komportable sa pag-code ng lahat ay iwanan mo na iyon, basahin na lamang ang teksto at mga larawan sa ibaba at ipinapangako kong magkakaroon ka ng pinakamahusay na ideya kung paano nabuo ang mga key.

Bago simulan ihanda natin ang setup. Ang unang hakbang ay ang paggawa ng isang folder. Sa loob ng folder lumikha ng isang file na may extension ng .js. Ang pangalan ng file ay maaaring maging tulad ng index.js o app.js.
Susunod na hakbang ay ang pag-download ng node.js sa iyong computer. Napakadaling i-download ang node.js, ito ay katulad ng pag-download ng anumang iba pang software ng computer. Susunod na hakbang ay ang pag-download ng ilang code editor, iminumungkahi ko ang Visual Studio Code (madaling gamitin na IDE).

Kapag tapos na ang mga hakbang sa itaas, buksan ang folder sa Visual Studio Code at magtungo sa iyong terminal. May inbuilt terminal sa Visual Studio Code, maaari mo ring gamitin iyon. Kung hindi, maaari mong gamitin ang native terminal ng Mac o Windows ngunit siguraduhing binuksan mo ang folder sa terminal. Kapag binuksan ang folder sa parehong Visual Studio Code at terminal, patakbuhin ang sumusunod na mga utos sa terminal upang mai-install ang 2 dependencies para sa proyekto:

Code:
npm init -y
npm i ripemd160 --save
npm i bs58 --save

Kailangan namin ng tatlong mga function ng hashing sa ating code lalo na ang sha256, ripemd160 at base58 bukod sa elliptic curve cryptography. Ang sha256 ay mayroon na sa native library ng nodejs ng crypto. Maaari nating i-code ang alinman sa iba pang dalawa nang sarili natin o i-import na lamang ang mga ito. Para sa pagiging simple ng gabay na ito, ininstall natin ang ripemd160 at bs58 npm packages sa itaas at gagamitin ito sa ating code. Na-verify ko na ang source code ng parehong package at ito ay ganap na ligtas na gamitin sa code na ito.

Ngayon simulan natin ang totoong kasiyahan. Buksan ang iyong file at magsimula sa code. Ang code ay nasa chronological order. Ang code ng Hakbang 1 ay pupunta sa tuktok ng file at code ng hakbang 2 ay magsisimula kung saan natapos ang hakbang ng isang code at so on:

Hakbang 1. Paglikha ng hashing function

Code:
const crypto = require('crypto');
const RIPEMD160 = require('ripemd160');
const BS58 = require('bs58');

const sha256 = input => crypto.createHash('sha256').update(input).digest();

const ripemd160 = input => new RIPEMD160().update(input).digest();

const bs58 = input => BS58.encode(input);

Ok! Sa unang tatlong linya ng code, na-import natin ang code ng lahat ng tatlong mga function ng hashing sa ating file. Susunod, gumawa tayo ng mga function para sa mga ito. Hindi mandatory na lumikha ng mga functions ngunit sa kasong ito kailangan nating isulat nang paulit-ulit ang buong code tuwing kailangan nating mag-hash ng isang bagay. Halimbawa, kung hindi natin isusulat ang tatlong mga function na ito sa tuwing kailangan nating lumikha ng sha256 hash ng isang bagay ay kailangan nating isulat ang crypto.createHash('sha256').update(something).digest() ngunit may code sa itaas, kailangan nating isulat ang  sha256(something) para sa susunod. Ayos ba? Magtungo na tayo.

Hakbang 2. Paglikha ng Elliptic curve Function


Code:
const generateECPoints = privateKey => {

    const Pcurve = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');

    const Gx = BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240');
    const Gy = BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424');

    const G = [Gx, Gy];

    const modInverse = (a, n) => {

        a = (a % n + n) % n

        const dArray = [];
        let b = n;

        while(b) {
        [a, b] = [b, a % b];
        dArray.push({a, b});
        }

        if (a !== BigInt(1)) {
        return null;
        }

        let x = BigInt(1);
        let y = BigInt(0);

        for(let i = dArray.length - 2; i >= 0; --i) {
        [x, y] = [y,  x - y * BigInt(dArray[i].a / dArray[i].b)];
        }

        return (y % n + n) % n;
    }

    const modOf = (a,b) => {
        const r = ((a % b) + b)% b;
        return r;
    }

    const ECAdd = (a,b) => {
        const lamAdd = modOf((b[1] - a[1]) * BigInt(modInverse(b[0] - a[0], Pcurve)), Pcurve);
        const x = modOf((lamAdd*lamAdd - a[0] - b[0]), Pcurve);
        const y = modOf((lamAdd*(a[0] - x) - a[1]), Pcurve);
        return [x, y];
    }

    const ECDouble = a => {
        const lamda = modOf(((BigInt(3)*a[0]*a[0])*(modInverse(BigInt(2)*a[1], Pcurve))), Pcurve);
        const x = modOf((lamda*lamda - BigInt(2)*a[0]), Pcurve);
        const y = modOf((lamda*(a[0] - x) - a[1]), Pcurve);
        return [x, y];
    };

    const ECMultiply = (genPoint, pvtKey) => {
        const scalarBinary = BigInt('0x'+pvtKey).toString(2);
        let GP = genPoint;

        for (let i=1; i < scalarBinary.length; i++) {
            GP = ECDouble(GP)
            if (scalarBinary[i] === '1') {
                GP = ECAdd(GP, genPoint);
            }
        }
        return GP;
    }
    
    return ECMultiply(G, privateKey);
}

Ang nasa itaas na code ay ang aking bersyon ng Elliptic curve Multiplication. Ito marahil ay purong Javascript coding lamang ng elliptic curve na makikita mo sa buong internet. Sa palagay ko ay hindi naaangkop na maipaliwanag ang buong code sa itaas sa thread na ito bilang pangunahing motibo ng thread na ito ay upang makabuo ng key pair. Kaya't sa ngayon gamitin ang code sa itaas na ito ng ganito. Gumagawa si webtricks ng hiwalay na thread para sa Elliptic Curve Cryptography pagkatapos ng 3-4 na araw at ipapaliwanag nito ang parehong code sa itaas sa thread na iyon.

Hakbang 3. Pagbuo ng X at Y coordinates ng Public Key mula sa itaas na function at Private Key

Code:
const privateKey = "6EBD5FAB742ED0734B37C63BD2A3CE8797FE4AC63C9A99781F8BEDDF6307094E";
const publicKey = generateECPoints(privateKey);

Sa hakbang na ito kinuha natin anghex value ng private key (ika-5 item mula sa imahe) at inilagay ito sa function ng generatorECPoints tulad ng nilikha sa Hakbang 2. Ito ay magbibigay sa atin ng X at Y coordinates ng Public Key na magiging ganito:
[26552980488606060638326679080566574626825610331305555186819497546906082384636n, 106820354128014061768597493909158935631153585355120117243602895828064095418195n]

Maaari mong mapansin ang n sa huling bahagi ng bawat coordinate. Ang ibig sabihin ng n na ito ay nakikipag-ugnayan sa labis na malalaking numero dito, na kilala bilang mga Big Integers sa Javascript. Gayundin maaari mong mapansin na ang mga coordinate na ito ay hindi tumutugma sa X at Y sa imahe sa itaas. Buweno, nakabuo na tayo ng mga numero para sa ngayon. Kailangan nating i-convert ito sa mga hexadecimals upang makakuha ng hindi uncompressed key compressed key. Gawin natin iyon sa susunod na hakbang.

Hakbang 4. Paglikha ng Compressed at Uncompressed Public Key

Code:
const checkKey = key => key.length < 64 ? '0'.repeat(64 - key.length) : key;

const publicKeyX = checkKey(publicKey[0].toString(16));
const publicKeyY = checkKey(publicKey[1].toString(16));

const uncompressedKey = '04'+publicKeyX+publicKeyY;

let compressedKey;
if (publicKey[1]%BigInt(2)===BigInt(1)) {
  compressedKey = '03'+publicKeyX;
} else {
  compressedKey = '02'+publicKeyX;
}

Bingo! Nakamit na natin ang unang target. Nilikha natin ang uncompressed at compressed na public key. Sa code sa itaas, gumawa muna tayo ng checkKey function. Ang function na ito ay gumagawa ng isang kawili-wiling bagay. Maaaring posible na habang habang cinoconvert ang X at Y coordinates mula sa numero patungong hexadecimal na ang resulta ng haba ng X at Y ay hindi 64. Ngunit tulad ng napag-usapan natin dati na ang haba ng hindi uncompressed ay 130 kung saan ang unang dalawang character ay 04 kung gayon ay 64 ang character ng X at pagkatapos ay 64 din ang Y. Kaya't ito ay void, magdaragdag tayo ng ng mga zero kung ang haba ay mas mababa kaysa sa 64. Halimbawa, kung ang haba ng X ay 63 na character, magdagdag tayo ng isang 0 upang gawin itong 64.

Pagkatapos ay tutukuyin natin ang hexadecimal na value ng X coordinate bilang publicKeyX at Y bilang publicKeyY. Maaari mong makita na ginagamit natin ang toString(16) sa pangalawa at pangatlong linya. Ang code na ito ay nagko-convert ng numero sa hex at pagkatapos ng pangkalahatang wrapper ng checkkey ay sinusuri kung ang haba ay mas mababa sa 64 pagkatapos magdagdag ng 0, kung hindi ay ibabalik ang parehong key.

Pagkatapos ay tutukuyin natin ang uncompressed key bilang uncompressedKey at pagkatapos ay ang compressed key bilang 03+X kung Y ay odd at 02+X kung Y ay even.


Hakbang 5. Bumubuo ng P2PKH Key

Bago magsimula sa code pag-usapan natin ang proseso ng pagbuo ng P2PKH key. Ito ay upang mapansin na ang uncompressed at compressed key na nabuo natin sa hakbang 4 ay hindi tiyak sa Bitcoin. Mayroong maraming iba pang mga serbisyo tulad ng Gmail o Facebook ang gumagamit ng Elliptic curve cryptography upang lumikha ng public/private keys. Gayunpaman, ang hakbang na ito ay nag-coconvert ng ating public key sa format na tinukoy ng Bitcoin sa P2PKH. Ang sumusunod ay pictorial representation ng proseso.



Kaya magsimula tayo sa hindi uncompressed key tulad ng nabuo sa hakbang 4 (maaari rin tayong magsimula sa mga compressed key na bubuo ng iba't ibang P2PKH address ngunit maaaring magamit nang palitan at kabilang sa parehong private key). Susunod na isinasagawa natin ay ang sha256 sa uncompressed key. Pagkatapos ng ripemd160 hashing sa nakaraan. Pagkatapos ay nagdagdag tayo ng 00 sa harap ng nakaraang hash. Ito ang 21-byte ng ating binary address. Upang mabuo ang susunod na 4-bytes binary address. Kailangan nating magsagawa ng double sha256 hashing sa unang 21 byte. Kunin ang unang 4 byte ng nagreresulta ng hash gaya ng unang walong character ng nagresulta ng hash at idagdag ito sa dulo ng 21 bytes. Sa wakas nakuha na natin ang 25-byte Binary address at kailangan na nating i-convert ito sa Base58 code. Ngayon tingnan natin ang pang-pinal na code.
 
Code:
const keyHex = Buffer.from(uncompressedKey, 'hex');
const ripedHashedKey = ripemd160(sha256(keyHex));
const mainRipeKeyString = '00'+ripedHashedKey.toString('hex');
const mainRipeKey = Buffer.from(mainRipeKeyString, 'hex');
const doubleHashedKey = sha256(sha256(mainRipeKey)).toString('hex');
const checkSum = doubleHashedKey.substr(0, 8);
const binaryAddress = Buffer.from(mainRipeKeyString+checkSum, 'hex');
const publicAddress = bs58(binaryAddress);

Ang nasa itaas na code ay walang iba kundi ang parehong 8 hakbang na detalyado ko sa larawan sa itaas. Bingo! Matagumpay nating nabuo ang aming Bitcoin Address. Ngayon lumipat tayo sa pangwakas na hakbang at bumuo tayo ng ating WIF private key mula sa hexadecimal private key.

Hakbang 6. Bumubuo ng WIF mula sa Private Key

Katulad sa nakaraang diskarte, pag-usapan natin ang proseso bago aktwal na lumipat sa code. Ang pagbuo ng WIF mula sa private key ay talagang mas simple kaysa sa nakaraang hakbang. Ang pag-convert ng raw hex private key sa WIF ay talagang mayroong maraming pakinabang. Una ito ay mas maliit at mas simple kaysa sa raw hex. Pangalawa mayroon itong inbuilt-checksum upang mapatunayan na may bisa ang private key. Tingnan natin ang nakalarawan na representasyon.



Ang unang hakbang ay simple, kumukuha tayo ng hexadecimal form ng private key at nagdagdag ng 80 sa harap nito. Tandaan na ang lahat ng mga karagdagan na ginagawa natin sa buong code ay hindi talaga mga numero. Ang mga ito ay hex code, halimbawa, ang 80 dito kapag na-convert sa desimal na form ay 128. Ok sa susunod, nagsasagawa tayo ng dobleng rounds ng sha256 hashing. Pagkatapos ay kumuha muna ng tayo ng 4 bytes ng resultant hex at idagdag ang mga ito sa dulo ng pinalawak na hex ng private key. Sa wakas naisagawa na natin ang Base58 hashing sa resulta at nakuha natin ang ating WIF key. Oras ng code:

Code:
const pvtKeyExtended = "80"+privateKey;
const extended = Buffer.from(pvtKeyExtended, 'hex');
const hashedExtended = sha256(sha256(extended)).toString('hex');
const checksum = hashedExtended.substr(0, 8);
const finalHex = pvtKeyExtended+checksum;
const WIF = bs58(Buffer.from(finalHex, 'hex'));

Walang espesyal sa code sa oras na ito. Ginagawa lamang natin ang lahat ng anim na hakbang tulad ng nabanggit sa larawan sa itaas. Kung mayroon kang anumang pagdududa tungkol sa anumang code, maaari kang magtanong sa thread o mag-PM sa akin.

Magaling! Natapos na natin ang proseso at nabuo ang ating Bitcoin Address kasama ang WIF Key. Mahusay, ngayon subukan natin ang code sa susunod.
Jump to: