BIP-32/44: Heirarki Deterministik (HD)BIP-32 menjelaskan cara menurunkan kunci parent -> kunci child
BIP-44 menjelaskan hierarki untuk aplikasi dompet "standar"
Kedua proposal pengembangan ini adalah satu rangkaian standar sehingga umumnya aplikasi yang mendukung BIP-32/44 yang kemudian ditambah dengan BIP-39 (BIP-32/39/44) dapat saling support. Misalnya kunci/backup yang dibuat mycelium dapat direstore menggunakan coinomi, trezor, dll., dan sebaliknya.
Latar belakang diciptakan dompet HDSebelum adanya dompet HD, pengguna kesulitan untuk bisa tetap anonim. Pada waktu itu, alamat bitcoin digunakan berulang kali karena setiap alamat membutuhkan satu privkey yang harus disimpan baik-baik oleh pengguna. Pengguna yang mencoba menggunakan alamat baru setiap kali transaksi pun kesulitan dalam mengelola alamat-alamat dan privkey-privkey pada alamat-alamat tersebut. Dengan adanya dompet HD, pengguna hanya perlu membackup master (root) privkey, dan pengguna sudah dapat menggunakan seluruh alamat child yang dihasilkan dari kunci parent tersebut.
Yang dijelaskan pada pembahasan iniAne ingin menjelaskan bagian yang jarang dijumpai pada tutorial-tutorial, yaitu bagaimana mekanisme perhitungan dompet HD tersebut untuk dapat menghasilkan privkey dan
alamat bitcoin (silahkan dicoba sendiri dan tanyakan ke sini kalau stuck) menggunakan cara se-newbie mungkin!
Dari frasa BIP-39 dapat diturunkan:Seed:
035ac5b79ff38a1df6add5dc03ac591cc774469826be79d859e21a4db56104cc77244445e5e31d85b982b6da86c783e39f597d9cd2b7b24c7d95550dd89fa0f7
Account Extended Privkey (m/44'/0'/0'):
xprv9xgKdgeSz3mxJGWGpTU7qtgD7x8H2ooVYxxawePdt7Dga3V2m28jLqwSawCXa6xAzK1oLioN2FXWD8uik8YnA37t15SyvCkFULYcopnM1ny
#1 Menghitung BIP-39 SeedPada pembahasan lalu kita tahu bahwa untuk menurunkan kunci-kunci kita membutuhkan titik awal yang disebut dengan seed. Untuk dapat mendapatkan seed dari frasa mnemonic kita perlu menggunakan Password-Based Key Derivation Function 2 (PBKDF2) yang bertujuan untuk memperkuat seed dari serangan brute force.
Perhatikan snippet berikut:
<?php
$password = "symptom display melt eight where universe prison vacuum convince garbage glance fork";
$iterations = 2048;
$salt = "mnemonic";
$hash = hash_pbkdf2("sha512", $password, $salt, $iterations);
echo $hash;
?>
Hasilnya:
035ac5b79ff38a1df6add5dc03ac591cc774469826be79d859e21a4db56104cc77244445e5e31d85b982b6da86c783e39f597d9cd2b7b24c7d95550dd89fa0f7
Agan dapat menggunakan bahasa pemrograman apapun untuk melakukan komputasi pbkdf2, ane menggunakan php karena kebetulan sering utak-atik wordpress.
$salt = "mnemonic" . $passphrase;
karena ane tidak memakai passphrase maka $salt hanya berisi string "mnemonic".
#2 Menghitung Root (Master) PrivKeyRoot atau master privkey ini merupakan privkey pertama yang akan kita hitung. Privkey dengan kedalaman 0 (m) ini dapat kita turunkan sampai ke kedalaman 5 (m/44'/0'/0'/0/0) atau lebih. Kedalaman inilah yang disebut dengan hierarki. Sebagai contoh pada pembahasan ini kita akan menurunkan sampai kedalaman 3 (m/44'/0'/0') atau yang disebut dengan account extended key.
Hierarki:
m / purpose' / coin_type' / account' / change / address_index
purpose': 44' atau hex 0x8000002C karena BIP-44
coin_type': 0' atau hex 0x80000000 karena bitcoin
account': 0' atau hex 0x80000000 menandakan sebagai akun pertama
Tanda petik ' merupakan tanda hardened yang berarti angka 0 dimulai dari 0x80000000
Untuk menghitung master privkey, ada 3 tahap yaitu (1) HMAC-SHA512; (2) melengkapi data; (3) serialisasi
(1) HMAC-SHA512
<?php
$hashdata = pack("H*" , $hash);
$chaindata = "Bitcoin seed";
$hash_m = hash_hmac("sha512" , $hashdata, $chaindata);
$hash_m_l = substr($hash_m, 0, 64);
$hash_m_r = substr($hash_m, 64, 64);
?>
Algoritma HMAC-SHA512 menggunakan input seed dan string "Bitcoin seed" untuk membuat 512 bit output. 512 bit output ini kita bagi dua menjadi 256bit hash kiri dan 256 bit hash kanan. Hash kiri merupakan hex privkey dan hash kanan adalah chain code.
(2) Melengkapi Data
<?php
$data_m = array(
'network' => '0488ade4',
'depth' => '00',
'fingerprint' => '00000000',
'i' => '00000000',
'chain_code' => $hash_m_r,
'key' => '00'.$hash_m_l,
);
?>
Network "0488ade4" yang merupakan bitcoin private mainnet, depth "00" yang berarti kedalaman level 0 (pertama), dan 'fingerprint' serta 'i' kita kosongkan dahulu.
(3) Serialisasi
<?php
$xprivkey_m = implode($data_m);
$checksum_m = hash('sha256', pack("H*", hash('sha256', pack("H*", $xprivkey_m))));
$checksum_m = substr($checksum_m, 0, 8);
$xprivkey_m = $xprivkey_m . $checksum_m;
$base58 = new StephenHill\Base58();
echo $base58->encode(pack("H*", $xprivkey_m))."<br>";
?>
Setelah semua data diserialkan, lalu dihash SHA-256 dua kali, selanjutnya checksum 4 byte ditambahkan pada akhir data serial dan diubah ke dalam base58.
Hasilnya (m):
xprv9s21ZrQH143K25iSTiafu7Nby5AtknABvMMRm2WBAdhY4AW29V7CVs1BHgvF9snNy3oaWz4h5joCk8jcMJo4tjcwa57nq6v6usHwXxRo5QM
#3 Menurunkan Child Key atau Child key derivation (CKD)Untuk menurunkan child key dari master key caranya hampir sama seperti #2, akan tetapi kita harus menghitung 'fingerprint' dan juga
parse256(IL) + kpar (mod n)
untuk diisikan pada 'key'.
(1) HMAC-SHA512
<?php
$hashdata = pack("H*", "00" . $hash_m_l . "8000002C");
$chaindata = pack("H*", $hash_m_r);
$hash_m_44 = hash_hmac("sha512" , $hashdata, $chaindata);
$hash_m_44_l = substr($hash_m_44, 0, 64);
$hash_m_44_r = substr($hash_m_44, 64, 64);
?>
Algoritma HMAC-SHA512 menggunakan input hash kiri, 'i', dan hash kanan parent untuk membuat 512 bit output. 512 bit output ini kita bagi dua menjadi 256bit hash kiri dan 256 bit hash kanan. Hash kiri merupakan data yang akan digunakan untuk perhitungan
parse256(IL) + kpar (mod n)
dan hash kanan adalah chain code.
(2) Melengkapi data
<?php
$bitcoinECDSA->setPrivateKey($hash_m_l);
$finger_m = $bitcoinECDSA->getPubKey();
$finger_m = hash('ripemd160', pack("H*", hash('sha256', pack("H*", $finger_m))));
$finger_m = substr($finger_m, 0, 8);
$math = EccFactory::getAdapter();
$g = EccFactory::getSecgCurves($math)->generator256k1();
$n = $g->getOrder();
$Il_dec = $math->hexDec($hash_m_44_l);
$private_key_dec = $math->hexDec($hash_m_l);
$key_dec = $math->mod($math->add($Il_dec, $private_key_dec), $n);
$keym44 = str_pad(BitcoinLib::hex_encode($key_dec), 64, '0', STR_PAD_LEFT);
$data_m_44 = array(
'network' => '0488ade4',
'depth' => '01',
'fingerprint' => $finger_m,
'i' => '8000002C',
'chain_code' => $hash_m_44_r,
'key' => '00'.$keym44,
);
?>
Pertama kita hitung 'fingerprint' dengan menggunakan HASH-160 dari pubkey parent, ekstrak hanya 4 byte pertama saja. Kemudian kita tidak dapat menggunakan hash kiri saja untuk diinput ke 'key', tapi harus ditambah dengan
+ kpar (mod n)
'depth' bertambah 01 karena kedalaman level bertambah, 'i' diisi dengan 0x8000002C sebagai penanda 44'
(3) Serialisasi
<?php
$xprivkey_m_44 = implode($data_m_44);
$checksum_m_44 = hash('sha256', pack("H*", hash('sha256', pack("H*", $xprivkey_m_44))));
$checksum_m_44 = substr($checksum_m_44, 0, 8);
$xprivkey_m_44 = $xprivkey_m_44 . $checksum_m_44;
$base58 = new StephenHill\Base58();
echo $base58->encode(pack("H*", $xprivkey_m_44))."<br>";
?>
Hasilnya (m/44'):
xprv9ve7i3PwihGn2M2iPMHQqGY9CKx4NdmAe3WtwirJ2bjQUu3yKMztYR6LA9FEC77JE38R6fh8uabGM5d2JxdTJ5bZuuRzKDiLLUxeorP4LMb
Unduh Script PHP ane di
https://pastebin.com/TBCexuLF untuk menghitung sampai m/44'/0'/0'
Catatan: semua contoh pada script merupakan hardened key, untuk yang non-hardened metodenya akan sedikit berbeda.
Selamat mencoba!
Referensi:https://github.com/bitcoin/bips/blob/master/bip-0032.mediawikihttps://github.com/bitcoin/bips/blob/master/bip-0044.mediawikihttps://github.com/bitcoinbook/bitcoinbook/blob/develop/ch05.asciidocOnline tools:https://iancoleman.io/bip39/http://bip32.org/PHP library:https://github.com/stephen-hill/base58php/https://github.com/BitcoinPHP/BitcoinECDSA.phphttps://github.com/phpecc/phpecchttps://github.com/Bit-Wasp/bitcoin-lib-php