【ビットコイン】base 58符号化


ビットコインソースのbase 58を参照する.hコードはopensslのbignumライブラリで実現された符号化関数であり、検証ツールとして使用される.
生成:
g++ -o base58encode -g base58encode.cc -lcrypto

ソース:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <openssl/bn.h>

#define DOMAIN_CHECK(c) ('0'<=(c)&&(c)<='9'||'a'<=(c)&&(c)<='f'||'A'<=(c)&&(c)<='F')

const char * BASE58TABLE="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

std::string base58encode(const std::string & hexstring)
{
	std::string result = "";
	BN_CTX * bnctx = BN_CTX_new();
	BN_CTX_init(bnctx);
	BIGNUM * bn = BN_new();
	BIGNUM * bn0= BN_new();
	BIGNUM * bn58=BN_new();
	BIGNUM * dv = BN_new();
	BIGNUM * rem= BN_new();
	BN_init(bn); 
	BN_init(bn0);
	BN_init(bn58);
	BN_init(dv);
	BN_init(rem);

	BN_hex2bn(&bn, hexstring.c_str());
	//printf("bn:%s
", BN_bn2dec(bn)); BN_hex2bn(&bn58, "3a");//58 BN_hex2bn(&bn0,"0"); while(BN_cmp(bn, bn0)>0){ BN_div(dv, rem, bn, bn58, bnctx); BN_copy(bn, dv); //printf("dv: %s
", BN_bn2dec(dv)); //printf("rem:%s
", BN_bn2dec(rem)); char base58char = BASE58TABLE[BN_get_word(rem)]; result += base58char; } std::string::iterator pbegin = result.begin(); std::string::iterator pend = result.end(); while(pbegin < pend) { char c = *pbegin; *(pbegin++) = *(--pend); *pend = c; } return result; } int main(int argc, char * argv []) { std::string hexstring = ""; FILE * fin = stdin; while(!feof(fin)) { char c = fgetc(fin); if (DOMAIN_CHECK(c)) hexstring +=c; } fprintf(stdout, "%s", base58encode(hexstring).c_str()); return 0; }

テスト:
echo -n 
00010966776006953D5567439E5E39F86A0D273BEED61967F6

| ./base58encode
印刷:6 UwLL 9 Risc 3 QfPqBUvKofHmBQ 7 wMtjvM
前面にプリアンブル0が2つあるので、アドレスは16 UwLL 9 Risc 3 QfPqBUvKofHmBQ 7 wMtjvMのはずです
参照アドレス生成中のコード:プリアンブル0の処理を追加し、最終的なビットコインアドレスを生成する
base 58プリアンブルバイトの定義:
Decimal version
Leading symbol
Use
Example
0
1
Bitcoin pubkey hash
17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem
5
3
Bitcoin script hash
3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX
111
m or n
Bitcoin testnet pubkey hash
mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn
128
5
Bitcoin Private key (for uncompressed pubkey)
5Hwgr3u458GLafKBgxtssHSPqJnYoGrSzgQsPwLFhLNYskDPyyA
128
K or L
Bitcoin Private key (for compressed pubkey)
L1aW4aubDFB7yfras2S1mN3bqg9nwySY8nkoLmJebSLD5BWv3ENZ
196
2
Testnet script hash
2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc
239
9
Testnet Private key (for uncompressed pubkey)
92Pg46rUhgTT7romnV7iGW6W1gbGdeezqdbJCzShkCsYNzyyNcc
239
c
Testnet Private key (for compressed pubkey)
cNJFgo1driFnPcBdBX8BrJrpxchBWXwXCvNH5SoSkdcF6JXXwHMm
公開鍵アドレスとは異なるプリアンブルの定義:
    // Compute the length of a pubkey with a given first byte.
    unsigned int static GetLen(unsigned char chHeader) {
        if (chHeader == 2 || chHeader == 3) //     
            return 33;
        if (chHeader == 4 || chHeader == 6 || chHeader == 7) //      
            return 65;
        return 0;
    }

ディスカッション:
1)アドレスプリアンブル0、すなわちbase 58の1について、これはこのように実現することができ、hexstringの各2文字はbyteであり、byte配列として書き、0の下から何個のbyteが0 x 00であるかを見て、何個のbyteが0 x 00であるかを前にして、一般アドレスのバージョン番号は0 x 00であるため、ほとんどが1の先頭のビットコインアドレスであることを見ることができる.
参照先:
https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses
https://en.bitcoin.it/wiki/List_of_address_prefixes
https://en.bitcoin.it/wiki/Base58Check_encoding