본문으로 바로가기

이전에 작성한 코드들은 코드상에서 일방적으로 개인키와 공개키를 생성하였습니다.

이번에는 대화형 메뉴를 출력하여 사용자 입력을 받아 키를 생성하는 지갑을 만들어 보도록 하겠습니다.


하기 샘플코드는 하기의 Tutorial을 참고로 하여 사용하였습니다.

http://aaronjaramillo.org/libbitcoin-interactive-hd-keychain


이번에 작성하는 프로그램은 지갑의 전체기능을 수행하는것이 아니고 단순히 키만 생성하는 것으로 지갑이라기보다는 열쇠고리라고 표현할수 있습니다.

대화형 프로그램을 만들기 위해 키를 생성하기 위한 단순한 클래스를 먼저 작성할것이고, 클래스에서는 다음의 기능을 제공하게 됩니다.


- 연상기호 코드

- 마스터 개인키

- 마스터 개인키로부터 유도된 자식 개인키

- 자식 개인키로부터 생성된 주소

- 자식주소의 범위

- 모든키를 한번에 생성


최종 작성된 코드는 다음의 github 에서 다운로드 받을수 있습니다.

https://github.com/ihpark92/Libbitcoin_Tutorial


먼저 다음과 같이 libbitcoin 을 포함하도록 작성합니다.


#include <bitcoin/bitcoin.hpp>
#include <string.h>
#include <iostream>
using namespace bc;


HD_Wallet 클래스를 정의하고 다음과 같이 2개의 생성자를 작성합니다.

첫번째 생성자는 의사난수생성기를 사용하여 생성된 난수를 사용하여 연상기호 단어열을 만들고, 해당 단어열을 사용하여 seed를 생성하여, 개인키와 공개키를 생성합니다.

두번째 생성자는 이미 만들어진 연상기호 단어열을 사용하여 seed를 생성하고 개인키와 공개키를 생성합니다.

연상기호 코드의 생성원리에 대해서는 기존 포스팅의 결정적 지갑에서 연상기호 코의 생성과정을 참고하시기 바랍니다.


이와같은 동작을 위해서 클래스는 하기와같이 랜덤값과, seed, 연상기호 단여열, 개인키, 공개키의 멤버를 가지고 있습니다.


class HD_Wallet
{
public:
// Constructor
HD_Wallet(const data_chunk Userentropy)
{
entropy = Userentropy;
mnemonic = wallet::create_mnemonic(entropy);
seed = to_chunk(wallet::decode_mnemonic(mnemonic));
privateKey = wallet::hd_private(seed);
publicKey = privateKey.to_public();
}
HD_Wallet(const wallet::word_list mnemonicSeed)
{
seed = to_chunk(wallet::decode_mnemonic(mnemonicSeed));
mnemonic = mnemonicSeed;
privateKey = wallet::hd_private(seed);
publicKey = privateKey.to_public();
}
private:
// Members
data_chunk entropy;
data_chunk seed;
wallet::word_list mnemonic;
wallet::hd_private privateKey;
wallet::hd_public publicKey;


다음에는  자식키 생성을 위한 인덱스값을 인자로 받아서 유도된 자식키의 개인키와 공개키, 주소를 생성하는 매쏘드입니다.

인덱스는 마스터 개인키를 사용하여 유도되는 자식의 인덱스로, 계층결정적 지갑에서는 이와같이 계층별로 인덱스를 늘려가며, 자식키, 손자키를 생성할수 있습니다.


public:
// Child key
wallet::hd_private childPrivateKey(int index)
{
return privateKey.derive_private(index);
}
wallet::hd_public childPublicKey(int index)
{
return publicKey.derive_public(index);
}
wallet::payment_address childAddress(int index)
{
return wallet::ec_public(childPublicKey(index).point()).to_payment_address();
}


다음은 각 키값을 화면상에 출력하기 위한 매쏘드들을 정의합니다.


// Display
void displayPrivateKey()
{
std::cout << "\nPrivate Key:" << privateKey.encoded() << std::endl;
}
void displayChildPrivateKey(int index)
{
std::cout << "\nChild Key: " << childPrivateKey(index).encoded() << std::endl;
}
void displayAddress(int index)
{
std::cout << "\nAddress: " << childAddress(index).encoded() << std::endl;
}
void addressRange(int start, int end)
{
while(start != end)
{
displayAddress(start);
start++;
}
}


다음은 seed값을 사용하여 생성된 연상기호 단어열을 출력하는 매쏘드입니다.


void displayMnemonic()
{
if(wallet::validate_mnemonic(mnemonic))
{
std::string mnemonicString = join(mnemonic);
std::cout << "\n" << mnemonicString << std::endl;
}else{
std::cout << "mnemonic invalid!" << std::endl;
}
}


마지막으로 생성된 클래스의 모든 정보를 출력하는 매쏘드입니다.

하기 매쏘드를 통해서 연상기로 단어열과 마스터 개인키, 유도된 자식의 개인키와 주소를 출력하게 됩니다.


void dumpKeys()
{
displayMnemonic();
displayPrivateKey();
displayChildPrivateKey(1);
displayAddress(1);
}