박일환
목차
 블록체인의 개념
 비트코인의 구성요소
 비트코인 블록의 구조
 개인키(Private key), 공개키(Public key), 비트코인 주소(Address)
 키와 주소를 관리하는 지갑(Wallet)
 비트코인 트랜잭션
 scriptSig와 scriptPubKey의 생성방법과 유효성 검증방법
 비트코인의 합의 알고리즘 : PoW(Proof of Work)
 블록체인의 분기
블록체인 – 가치공유의 인터넷
 기존의 인터넷은 "정보"를 전달, 블록체인은 "가치"를 전달
 Alice가 Bob에게 1달러의 가치를 전달하는 경우
 인터넷 뱅킹을 통한 1달러 이체
 1달러의 디지털 상품권을 구입하여 전달
 인터넷상에서의 가치전달의 문제점
 중앙집중서버가 복구불가능상태로 파괴되거나 해킹된 경우 가치소멸
 상품권을 복제하여 이중지불 문제 발생
 블록체인을 통한 가치전달문제의 해결
 모든 거래정보가 블록의 형태로 저장되어 모든 사용자에게 배포되고 저장
 블록체인 고유의 합의 알고리즘을 통해 이중지불 문제 해결
비트코인의 가치이동
비트코인의 구성요소 - 1
비트코인의 구성요소 - 2
 Wallet
 각 사용자의 Private/Public 키를 생성하여 보관
 Public키는 Private키를 기반으로 생성되고 Public 키를 기반으로 Bitcoin 주소가 생성
 Transaction
 실제 비트코인의 이동이 발생하는 거래를 말하며, 거래의 단위는 UTXO이고, 각 거래는 각 사용자
의 키로 서명이 되어 지정된 사용자끼리만 거래가 가능
 Block
 각각의 블록은 헤더와 10분간 발생한 거래정보가 포함
 Network
 거래와 블록을 네트워크상의 모든 노드에게 전파하는 P2P 기반 네트워크
 Miner
 거래가 포함된 Block을 가지고, 이중지불 문제가 발생하지 않도록 PoW(Proof of Work : 작업증명)
알고리즘으로 블록을 연결하는 주체
비트코인의 해쉬(Hash) 함수 : SHA256
 어떤 길이의 입력값에 대해서도 동일한 길이의 출력값을 생성
 Hash(A) = 123…asd(32바이트 길이), Hash(ABC) = afd…35f(32바이트 길이)
 어떤 입력 X에 대해서 Hash(X) = Y 값을 쉽게 계산가능
 비트코인 작업증명의 결과물인 블록의 유효성 검증이 쉽게 됨
 Hash(X) = Y 인 경우, X값을 유추하는것이 불가능한 일방함수
 비트코인 PoW에서 nonce를 찾는 과정
 동일한 입력값에 대해서는 동일한 출력값을 생성하지만, 입력데이타가 변하면 완전히 새로운
출력값을 생성
 https://anders.com/blockchain/hash.html
해싱 데이터의 5가지 패턴
 독립해싱
 순차적 해싱
 반복해싱
 계층적 해싱
 결합해싱
비트코인에서 Hash 함수 사용
 RIPEMD160(SHA256(x))
 비트코인 주소 생성
 SHA256(SHA256(x))
 머클트리에서 트랜잭션의 해쉬 연산
 트랜잭션 ID 생성
 블록헤더의 해쉬 연산
 Double hash 연산을 하는 이유
 length-extension attacks 방지
 A값을 몰라도 hash(A)와 length(A)를 알면 hash(A||B)을 알수 있음
비트코인의 블록 – 블록정보
 Block explorer : https://www.blockchain.com/en/explorer
비트코인의 블록 - 블록헤더
비트코인의 블록 - 블록헤더
 Timestamp(블록이 생성된 시간) : 2018-03-01 08:11:49
 Bits(블록 생성의 난이도) : 392009692
 Version(프로토콜 버전) : 0x20000000
 Merkle Root(트랜잭션 ID를 머클트리 형태로 구성한 해시정보) :
b958fda3ce4d3cd0a41f01a6b00f6ae4e70f498a27f526cc5612f72450152d17
 Previois Block(이전 블록의 해시정보) :
00000000000000000029b633899beed322666cc0041fbdf471300d52e6de1887
 Nonce : 2170187189
머클트리
 특정거래가 블록내부에 포함되는지 여부를 검증하는데 효율적인 프로세스를 제공
 상향식으로 두개의 Hash값을 두번 해쉬(Double SHA256)하여 상위 Hash값 생성
 Hash(AB) = SHA256(SHA256(Hash(A) + Hash(B))
 이진 트리이기 때문에 짝수개의 리프노드가 필요하며 홀수개의 경우에는 마지막 노드를 복사하여 짝수
로 만들어서 사용
머클루트 계산
import hashlib
# Hash pairs of items recursively until a single value is obtained
def merkle(hashList):
if len(hashList) == 1:
return hashList[0]
newHashList = []
# Process pairs. For odd length, the last is skipped
for i in range(0, len(hashList)-1, 2):
newHashList.append(hash2(hashList[i], hashList[i+1]))
if len(hashList) % 2 == 1: # odd, hash last item twice
newHashList.append(hash2(hashList[-1], hashList[-1]))
return merkle(newHashList)
def hash2(a, b):
# Reverse inputs before and after hashing
# due to big-endian / little-endian nonsense
a1 = a.decode('hex')[::-1]
b1 = b.decode('hex')[::-1]
h = hashlib.sha256(hashlib.sha256(a1+b1).digest()).digest()
return h[::-1].encode('hex')
#
https://www.blockchain.com/en/btc/block/000000000003ba27aa200b1cecaad478d2b00432346c
3f1f3986da1afd33e506
txHashes = [
"8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87",
"fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4",
"6359f0868171b1d194cbee1af2f16ea598ae8fad666d9b012c8ed2b79a236ec4",
"e9a66845e05d5abc0ad04ec80f774a7e585c6e8db975962d069a522137b80c1d",
]
print merkle(txHashes)
비트코인의 블록 – 블록헤더 구조
비트코인의 블록 – 블록체인
 하나의 블록은 계산된 Hash 값과 블록헤더, 10분간 진행된 거래(Transaction) 내역이 포함
되며 이 블록이 연속된 체인형태로 구성.
대칭키 알고리즘
 암호화/복호화 속도가 비대칭키 암호 알고리즘보다 빠르다(최소10~최대1000배).
 암호문의 크기가 평문보다 크지 않다(암호화 시 데이터 증가가 없다).
 주로 데이터 통신의 암호화에 사용
비대칭키 알고리즘
 공개키로 암호화한 데이터는 개인키로만 복호화가 가능하다.
 개인키로 암호화한 데이터는 공개키로만 복호화가 가능하다.
 비트코인의 트랜잭션에서는 비대칭키 암호화 알고리즘으로 유효성 검증이 이루어진다.
https://anders.com/blockchain/public-private-keys/signatures.html
개인키(Private key)
 무작위로 추출한 단순한 숫자
 암호학적으로 안전한 의사난수생성기를 사용하여 생성되어야 함
 비트코인에서 개인키를 생성하는 작업은 1에서 2256 사이의 숫자를 선택하는것과 동일
 개인키는 256비트 길이의 숫자로 생성
유형 접두부 설명
Hex 없음
64개의 16진수
ex) 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD
WIF 5
Base58Check 엔코딩
ex) 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
WIF-압축형 K 또는 L
Base58Check 엔코딩, 인코딩전 접미부 0x01 추가
ex) KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
타원곡선암호화(Elliptic Curve Cryptography)
 공개키 암호화의 핵심은 고유의 트랩도어함수(Trapdoor function)
 A + B = C : Not Trapdoor function
 “Message” + public key = “s80s1s9sadjds9s” : Trapdoor function
 RSA대비 256비트의 ECC가 3072 비트의 RSA와 동일한 보안을 제공
타원곡선 덧셈함수 타원곡선 곱셈함수
공개키(Public key) - 1
 타원곡선 함수를 통해 Private 키로부터 계산. : OpenSSL 암호 라이브러리 사용
 K = 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD * G
 K = (x, y)
x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
K = k * G (K : Public 키, k : Private 키, G : 생성포인트 상수)
𝑦2 = 𝑥3 + 𝑎𝑥 + 𝑏
𝑦2
= 𝑥3
+ 7 : secp256k1(비트코인, 이더리움에서 사용하는 타원곡선)
: a = 0, b = 7
: G = 02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798
공개키(Public key) - 2
 비압축 공개키
: K = 04F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A↵
07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
 압축 공개키 :
: K = 03F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
: 압축 공개키는 02, 03 의 접두어를 가지게 됨
주소(Address)
 숫자와 문자로 구성된 문자열로 숫자 1로 시작
: 1thMirt546nngXqyPEz532S8fLwbozud8
 개인키 및 공개키 쌍을 보유한 소유주
 비트코인 거래의 대상
 A = RIPEMD160(SHA256(K)) : K = Public 키
Base58Check Encoding
Base58Check Encoding
 길이가 긴 숫자열을 압축해서 표현
 10진법 : 0에서 9까지의 10개의 숫자를 사용
 16진법 : 10개의 숫자와 6개의 부호를 사용
 Base64 : 소문자 26개, 대문자 26개, 숫자 10개, 특수문자 2개(+, /) 사용
 Base58 : Base64에서 0, O, l, I, +, / 를 제외
 오자나 데이터 입력오류 등에 대한 추가보안을 설정하기 위해 Checksum 추가
유형 버전 접두부 Base58 접두부 결과값
비트코인 주소 0x00 1
Pay-to-script-Hash 주소 0x05 3
비트코인 테스트넷 주소 0x6F m , n
개인키 WIF 0x80 5, K, L
BIF38 암호화 개인키 0x0142 6P
BIF32 확장 공개키 0x0488B21E xpub
BIF32 확장 개인키 0x0488ADE4 xprv
개인키, 공개키, 주소의 변환과정
http://royalforkblog.github.io/2014/08/11/graphical-address-generator/
생성 가능한 주소의 크기
 생성 가능한 비트코인 주소의 크기 : 2160
 1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,97
 지구상의 모래알의 수 : 263
 263개의 지구에 263개의 모래알이 있는경우의 수 : 2126
 2126 = 2160 의 0.0000000058 %
 2017년 기준 전세계 인구가 75억인 경우, 모든 사람은 각각 2127 개의 주소를 가질수 있음
Libbitcoin 라이브러리
 Bitcoin 어플리케이션을 제작하기위한 크로스 플랫폼 C++ 라이브러리
Libbitcoin 라이브러리
 Libbitcoin 라이브러리 설치 : https://github.com/libbitcoin/libbitcoin
 Secp256k1 라이브러리 설치 : https://github.com/libbitcoin/secp256k1
$ git clone
https://github.com/libbitcoin/secp256k1
$cd secp256k1
$ ./autogen.sh
$ ./configure
$ make
$ ./tests
$ sudo make install # optional
$ g++ version # g++ 버전 확인
# 만약 g++ 버전이 낮다면 업그레이드
$ sudo apt-get install g++-4.8
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
$ sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-4.8 50
$ sudo apt-get install build-essential autoconf automake libtool pkg-config
git
$ sudo apt-get install libboost-all-dev
$ wget
https://raw.githubusercontent.com/libbitcoin/libbitcoin/version3/install.sh
$ chmod +x install.sh
$ sudo ./install.sh
Libbitcoin 라이브러리 프로그래밍
#include <bitcoin/bitcoin.hpp>
using namespace bc;
int main()
{
// Extracting Satoshi's words from genesis block.
const auto block = bc::chain::block::genesis_mainnet();
const auto& coinbase = block.transactions().front();
const auto& input = coinbase.inputs().front();
BITCOIN_ASSERT_MSG(input.script().size() > 2u, "unexpected genesis");
const auto headline = input.script()[2].data();
std::string message(headline.begin(), headline.end());
bc::cout << message << std::endl;
return EXIT_SUCCESS;
}
$ g++ -std=c++11 -o satoshi satoshiwords.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin)
개인키, 공개키, 주소 생성
#include <bitcoin/bitcoin.hpp>
#include <string>
#include <iostream>
using namespace bc;
int main(void) {
data_chunk seed(16);
pseudo_random_fill(seed);
ec_secret secretKey = bitcoin_hash(seed);
std::string hexKey = encode_base16(secretKey);
std::cout << "secret key: " << hexKey << std::endl;
wallet::ec_private privateKey(secretKey);
std::cout << "Private key: " << privateKey.encoded() << std::endl;
wallet::ec_public publicKey = privateKey.to_public();
std::cout << "Public Key: " << publicKey.encoded() << std::endl;
wallet::payment_address paymentAddress = publicKey.to_payment_address();
std::cout << "Bitcoin address: " << paymentAddress.encoded() << std::endl;
return 0;
}
$ g++ -std=c++11 -o key key.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin)
개인키, 공개키, 주소 생성
지갑(Wallet)
 개인키(Private 키) 와 공개키(Public key)를 담는곳
 인터넷 연결유무에 따라 Hot wallet, Cold wallet으로 구분
 비트코인은 UTXO(Unspent Transaction Output)의 형태로 블록체인상에 여러 사용자에게
모두 공유되어 저장
 이와 같이 지갑은 실제 비트코인을 저장하는것이 아니고, 자신 소유임을 증명하기위한 개인
키와 공개키를 저장하는 곳
 지갑의 종류
 비결정적 지갑
 결정적 지갑
 계층 결정적 지갑
비결정적 지갑
 무작위로 선택된 Private 키가 저장되어있는 지갑
 여러개의 키 사이에 규칙이나 연속성이 없이 무작위
로 키가 생성
 지갑이 생성될때 100개의 개인키를 무작위로 생성
하여 사용하고 이후 모든키가 사용된후에 다시 무작
위로 새로운 키를 생성
 모든키를 백업하지못한 경우에 지갑이 손실되면 복
구를 할수가 없는 문제가 발생
 지갑의 손실을 방지하기 위해서는 주기적으로 지갑
의 모든키를 백업해야 함
결정적 지갑
 랜덤하게 발생된 Seed 에서 단방향 Hash 함수를 통해서 개인키를 연속적으로 생성
 Seed만 알고있으면 추출키 전부를 복원할수 있기 때문에 특정시기에 한번의 백업만 해도 됨
결정적 지갑 – 연상기호 코드워드 (BIP39)
 연상기호코드는 결정적 지갑을 얻기 위해 종자로 이용한 난수를 표현하는 영어 단어열
 연상기호 단어 생성과정
 128~256 비트의 random 값 A 생성
 SHA256(A) 값의 첫 몇비트를 check sum으로 생성
 check sum을 A 값의 끝부분에 추가
 A를 11비트로 나누어 24개의 인덱스를 생성하고, 미리 정해진 2048개의 단어로 구성된 배열의 인덱스로 사용
하여 단어열 생성
 PBKDF2 함수를 사용하여 512비트의 common seed 생성
 연상기호 코드의 엔트로피와 단어길이
엔트로피(비트) 체크섬(비트) 엔트로피+체크섬 단어 길이
128 4 132 12
160 5 165 15
192 6 198 18
224 7 231 21
256 8 264 24
결정적 지갑 – 연상기호 코드워드
계층결정적 지갑(HD Wallet) (BIP32, BIP44)
 단일 종자(Seed)로부터 많은 키를 쉽게 얻기 위해 개발
 부모키가 자식키열을 만들고, 각각의 자식키는 손자키 열을 만들수 있음
 유기적인 구조의 의미를 표현하기 위해 트리 구조가 사용될수 있음
 공개키에 대응하는 개인키에 접근하지 않고도 공개키열을 생성할수 있음
종자(Seed)로부터 마스터키와 체인코드 생성하기
 HD지갑은 128,256,512비트 크기의 무작위 숫자인 root seed로부터 생성됨
 Root seed로부터 HD지갑 전체를 복원할수 있음
 Root seed는 연상기호 단어열로 표현됨
개인 자식키 유도하기
 부모키로부터 자식키를 얻기 위해 자식키 유도(CHD) 함수를 사용
확장키
 키 유도함수는 세가지 입력값(키, 체인코드, 목표자식의 인덱스)을 기반으로 자식키를 생성
 키와 체인코드를 결합한것 : 256비트의 키와 256비트의 체인코드를 512비트로 결합
 확장 개인키 : 개인키와 체인코드의 결합, Base58Check 엔코딩시 ‘xprv’ 접두부
xprv9tyUQV64JT5qs3RSTJkXCWKMyUgoQp7F3hA1xzG6ZGu6u6Q9VMNjGr67Lctvy5P8oyaY
AL9CAWrUE9i6GoNMKUga5biW6Hx4tws2six3b9c
 확장 공개키 : 공개키와 체인코드의 결합, Base58Check 엔코딩시 ‘xpub’ 접두부
xpub67xpozcx8pe95XVuZLHXZeG6XWXHpGq6Qv5cmNfi7cS5mtjJ2tgypeQbBs2UAR6KECeeM
VKZBPLrtJunSDMstweyLXhRgPxdp14sk9tJPW9
공개 자식키 유도하기
 개인키없이 공개 부모키로부터 공개 자식키를 생성
 무한개의 공개키와 비트코인 주소를 생성할수 있지만 송금된 돈을 소비할수 없음
Libbitcoin을 사용하여 HD지갑의 키생성
#include <bitcoin/bitcoin.hpp>
#include <string.h>
#include <iostream>
using namespace bc;
int main(void)
{
data_chunk seedChunk(16);
pseudo_random_fill(seedChunk);
std::cout << "nHex Seed: " << std::endl;
std::cout << encode_base16(seedChunk)<< std::endl;
wallet::word_list writtenWord = wallet::create_mnemonic(seedChunk);
if(wallet::validate_mnemonic(writtenWord)){
for(auto i = writtenWord.begin(); i != writtenWord.end(); ++i)
std::cout << *i << ' ';
}else{
std::cout << "mnemonic invalid!" << std::endl;
}
wallet::hd_private privateKey(seedChunk);
std::cout << "nnMaster Private Key: " << std::endl;
std::cout << privateKey.encoded() << std::endl;
wallet::hd_key keys = privateKey.to_hd_key();
std::cout << "nHex Master Private Key: " << std::endl;
std::cout << encode_base16(keys) << std::endl;
wallet::hd_public publicKey = privateKey.to_public();
std::cout << "nMaster Public Key: " << std::endl;
std::cout << publicKey.encoded() << std::endl;
wallet::hd_private childPrivateKey = privateKey.derive_private(1);
std::cout << "nChild Private Key: " << std::endl;
std::cout << childPrivateKey.encoded() << std::endl;
wallet::hd_public childPublicKey = privateKey.derive_public(1);
std::cout << "nChild Public Key: " << std::endl;
std::cout << publicKey.encoded() << std::endl;
std::cout << "nPayment Adress: " << std::endl;
std::cout <<
wallet::ec_public(childPublicKey.point()).to_payment_address().encoded()
<< "n" << std::endl;
}
https://github.com/ihpark92/Libbitcoin_Tutorial/blob/master/HD_Key.cpp
HD지갑의 키생성
ihpark92@ubuntu:~/work$ ./HD_key
Hex Seed:
c6343e966440d61d17423e81bfef3746
shiver peanut pitch silk aspect attend fringe elephant like youth soccer mind
Master Private Key:
xprv9s21ZrQH143K2CspDbSR9pNddmpvjZWpGV4KoZ2bc9d3RgthSDLreyTb72UFwwZowQjTwBBLaRceNgLwdjL77SccLQuQsp6vB8rujhW1xEp
Hex Master Private Key:
0488ade40000000000000000000ec10abb36391b6aebb63d3697b8d1c61fd6f66d274b06945f9cc42c41cd40a000df61edf0d6426ebc85
f94e0668b053b1801f3ac40dcc7dd948d4ba329030d603731b412d
Master Public Key:
xpub661MyMwAqRbcEgxHKcyRWxKNBofR92EfdhyvbwSDAVA2JVDqykf7Cmn4xGoRNgqjSPh4SkXXzQ8GUr42KAUEr53q2N8bpfpu8tznqZWm5fM
Child Private Key:
xprv9vfdCPd3QdEeYdDEGBjV2gSVkdwcDLButpskBgm88hgKTQR6CaaQnKCrHhF2YSiKW652bazqYdLATouWi5fZaiYo4YRs1Y3TXF4Cr6Boxjd
Child Public Key:
xpub661MyMwAqRbcEgxHKcyRWxKNBofR92EfdhyvbwSDAVA2JVDqykf7Cmn4xGoRNgqjSPh4SkXXzQ8GUr42KAUEr53q2N8bpfpu8tznqZWm5fM
Payment Adress:
1Bngpmye1f91RDtStQAVS2b9NsbNYhhK1K
ihpark92@ubuntu:~/work$
비트코인의 거래(Transaction)
https://www.blockchain.com/en/explorer
일반적인 거래
 복식부기 형태의 거래
일반적인 거래
 한 거래의 출력값이 새로운 거래의 입력값이 되는 거래체인
거래의 종류
 하나의 입력값과 2개의 출력값이 있는 경우
 가장 일반적인 거래로 현실에서 거스름돈을 받는 형태
 B에게 비트코인 2를 전달하고 나머지 8을 거스름돈으로 받는 거래
거래의 종류
 다수의 입력값과 하나의 출력값이 있는 경우
 동전과 단위가 작은 지폐가 많은경우 큰 단위의 지폐 한장으로 교환하는 행위
 지불과정에서 잔액으로 받은 작은 단위의 금액을 정리하기 위해 지갑 어플리케이션에서 이
유형의 거래가 시행되기도 함
거래의 종류
 하나의 입력값과 다수의 출력값이 있는 경우
 기업체에서 다수의 직원에게 급여를 지불하는등 돈을 분배해야하는 경우
거래의 종류
 입력값이 없고 출력값만 있는 경우
 채굴에 성공한경우 채굴자에게 보상으로 비트코인을 제공하는 거래 : Coinbase 거래
UTXO(Unspent Transaction Output)
 블록체인상에서 거래의 단위
 거래의 출력값으로, 사용되지않고 공개키로 암호화되어 블록체인상에 저장되어 있는 단위
 암호화된 UTXO는 사용시점에 소유자의 개인키로 암호를 해제하여 거래의 입력값으로 사용
 자신 소유의 비트코인의 전체 잔액을 확인하고자 한다면, 지갑에 저장되어 있다고 생각되는
비트코인의 갯수를 확인하는것이 아니라, 블록체인상에 자신의 소유로 저장되어 있는 UTXO
의 출력값을 모두 합한것을 확인
비트코인 잔액조회 - UTXO의 총합
# get unspent outputs from blockchain API
import json
import requests
# example address
address = 1JBwfNy2oyhFCoNyLb4nnh2se7gA6DBU7B'
resp = requests.get('https://blockchain.info/unspent?active=%s' % address)
utxo_set = json.loads(resp.text)["unspent_outputs"]
for utxo in utxo_set:
print("%s:%d - %ld Satoshis" % (utxo['tx_hash'], utxo['tx_output_n'], utxo['value']))
비트코인 잔액조회 - Libbitcoin 사용
https://github.com/ihpark92/Libbitcoin_Tutorial/blob/master/BitcoinNetwork/Balance.cpp
#include <bitcoin/bitcoin.hpp>
#include <bitcoin/client.hpp>
#include <string.h>
#include <iostream>
using namespace bc;
uint64_t balancer(const chain::history::list& rows)
{
uint64_t unspent_balance = 0;
for(const auto& row: rows)
{
// spend unconfirmed (or no spend attempted)
if (row.spend.hash() == null_hash)
unspent_balance += row.value;
}
return unspent_balance;
}
void getBalance(wallet::payment_address address)
{
client::connection_type connection = {};
connection.retries = 3;
connection.timeout_seconds = 8;
connection.server =
config::endpoint("tcp://mainnet.libbitcoin.net:9091");
client::obelisk_client client(connection);
……
if(!client.connect(connection))
{
std::cout << "Fail" << std::endl;
} else {
std::cout << "Connection Succeeded" << std::endl;
}
client.blockchain_fetch_history3(on_error2, on_done, address);
client.wait();
}
int main()
{
wallet::payment_address addy("15QzCiznJXqihKmNTgcxwS8nf7sdSXBAE9");
getBalance(addy);
}
UTXO의 생성
 다른 주소에서 자신의 주소로 비트코인을 송금받는 경우
UTXO의 소멸
 다른 주소로 송금하기 위해 사용되는 경우
거래(Transaction)의 구조
크기 필드 설명
4 Byte Version 프로토콜 버전
1~9 Byte Input Count 입력값의 갯수
Variable Input 하나 이상의 입력값
1~9 Byte Output Count 출력값의 갯수
Variable Output 하나 이상의 출력값
4 Byte Locktime 블록에 추가되는 가장빠른시간
거래(Transaction)의 구조
{
"lock_time":0,
"ver":1,
"size":257,
"inputs":[
{
"sequence":4294967295,
"witness":"",
"prev_out":{
"spent":true,
"tx_index":581424,
"type":0,
"addr":"1E3GodQUs3pdW4SasKXNHAtfJZHGmUhUxe",
"value":1000000000,
"n":1,
"script":"76a9148f07a8d943b08ea22cd9e98d329d99025b45edfb88ac"
},
"script":"47304402206f9748d80344eb4ef6492248843f0f179f8275c30788adf3ddbcddaebc9fc0
8a02202f09fda4b5f7caf0e958889069e999d1fb9258b28c7b6a8484b108f5be08efc60141046128
6410eda379b4790c5ff7d3ebcd078821c1773ee8200ae90ef211efe3aadd48ab65e2c4b482c23ba
6db447d9cf6d63939e07b73f57898d69a7bd3f90f4a97"
}
],
"weight":1028,
"time":1388195590,
"tx_index":41376062,
"vin_sz":1,
"hash":"04905ff987ddd4cfe603b03cfb7ca50ee81d89d1f8f5f265c38f763eea4a21fd",
"vout_sz":2,
"relayed_by":"67.83.126.1",
"out":[
{
"spent":true,
"tx_index":41376062,
"type":0,
"addr":"1K8jp6ifZQZMT1WmJUKuh4RAJFtPAFGCHB",
"value":500000000,
"n":0,
"script":"76a914c6e8e9dd79b5d8fef5309eba6aadc5323bf6315f88ac"
},
{
"spent":true,
"tx_index":41376062,
"type":0,
"addr":"1Mdhkk4ofugGrtTCfJBiivzcGWRW4RWquF",
"value":500000000,
"n":1,
"script":"76a914e253829af94cfba03688ad705b6b9d519ec9d3d588ac"
}
]
},
https://blockchain.info/block-height/277316?format=json
거래의 입력과 출력의 관계
https://blockchain.info/block-height/499118?format=json https://blockchain.info/block-height/500000?format=json
{
"lock_time":0,
"ver":1,
"size":215,
"inputs":[
{
"sequence":4294967295,
"witness":"0247304402205f39ccbab38b644acea0776d18cb63ce3e37428cbac06dc23b59c61607aef6
9102206b8610827e9cb853ea0ba38983662034bd3575cc1ab118fb66d6a98066fa0bed01210304c0156
3d46e38264283b99bb352b46e69bf132431f102d4bd9a9d8dab075e7f",
"prev_out":{
"spent":true,
"tx_index":311962649,
"type":0,
"addr":"3FfQGY7jqsADC7uTVqF3vKQzeNPiBPTqt4",
"value":34676070,
"n":0,
"script":"a914994394dbd20b7752e272458c738ae9b7666271b787"
},
"script":"1600142b2296c588ec413cebd19c3cbc04ea830ead6e78"
}
],
"weight":533,
"time":1513194393,
"tx_index":311967252,
"vin_sz":1,
"hash":"fe6c48bbfdc025670f4db0340650ba5a50f9307b091d9aaa19aa44291961c69f",
"hash":"503e4e9824282eb06f1a328484e2b367b5f4f93a405d6e7b97261bafabfb53d5",
"vout_sz":2,
"relayed_by":"0.0.0.0",
"out":[
{
"spent":true,
"tx_index":311962649,
"type":0,
"addr":"3FfQGY7jqsADC7uTVqF3vKQzeNPiBPTqt4",
"value":34676070,
"n":0,
"script":"a914994394dbd20b7752e272458c738ae9b7666271b787"
},
{
"spent":true,
"tx_index":311962649,
"type":0,
"addr":"1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD",
"value":31129454,
"n":1,
"script":"76a914ed5600751fea259a0f8c8bec09a626e7e4450e7a88ac"
}
]
거래 입력값과 출력값
필드 설명
Transaction Hash 소비될 UTXO를 담고있는 거래에 대한 ID (TxID)
Output Index 소비될 UTXO의 인덱스 번호
Unlocking Script Length 해제 스크립트 길이
Unlocking Script(ScriptSig) UTXO의 소비조건을 충족하는 스크립트
Sequence Number 사용하지않음, 0xFFFFFFFF로 설정
 Input
 Output
필드 설명
value 사토시 단위의 거래금액(1사토시는 1억분의 1 비트코인)
Locking script length 잠금 스크립트 길이
Locking Script
(ScriptPubKey)
출력값을 소비하는데 필요한 조건
거래 스크립트
 비트코인 거래 유효화 엔진에서 거래의 유효성을 확인하기 위해 사용되는 스크립트
 잠금 스크립트(scriptPubKey)와 해제 스크립트(scriptSig)
 스택(stack)을 사용하여 계산되어짐
 조건부 흐름제어기능 이외에는 루프나 복잡한 흐름제어기능을 가지고 있지않음
 거래 스크립트의 5가지 표준
 Pay-to-public-key-hash(P2PKH), 공개키, 다중서명, pay-to-script-hash(P2SH), 데이타출력
(OP_RETURN)
잠금 스크립트(scriptPubKey) 생성하기
 DUP + HASH160 + <pubKeyHash> + EQUALVERIFY + CHECKSIG
 76 + a9 + length + pubKeyHash + 88 + ac
 pubKeyHash = Base58Decode(1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD)
 00ED5600751FEA259A0F8C8BEC09A626E7E4450E7A2F6DA14A
 76 + a9 + 14 + ED5600751FEA259A0F8C8BEC09A626E7E4450E7A + 88 + ac
 76a914ED5600751FEA259A0F8C8BEC09A626E7E4450E7A88ac
"addr":"1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD",
"value":31129454,
"n":1,
"script":"76a914ed5600751fea259a0f8c8bec09a626e7e4450e7a88ac"
해제 스크립트(scriptSig) 생성하기
 scriptSig를 제외한 트랜잭션 템플릿 작성  이전출력의 scriptPubKey를 사용하여 서명
해제 스크립트(scriptSig) 생성하기
 16진수 트랜잭션 메시지와 private key를 사용하여 signature 생성
 생성된 signature
304402201c3be71e1794621cbe3a7adec1af25f818f238f5796d47152137eba710f2174a02204f8
fe667b696e30012ef4e56ac96afb830bddffee3b15d2e474066ab3aa39bad
import hashlib, ecdsa, binascii
from ecdsa import SigningKey, SECP256k1
mhex =
‘0100000001416e9b4555180aaa0c417067a46607bc58c96f0131b2f41f7d0fb665eab03a7e000000001976a91499b1ebcfc11a13df5161aba81
60460fe1601d54188acffffffff01204e0000000000001976a914e81d742e2c3c7acd4c29de090fc2c4d4120b2bf888ac0000000001000000’
txHash = hashlib.sha256(hashlib.sha256(mhex.decode('hex')).digest()).hexdigest()
privkey = '3cd0560f5b27591916c643a0b7aa69d03839380a738d2e912990dcc573715d2c'
signingkey = ecdsa.SigningKey.from_string(privkey.decode('hex'), curve=ecdsa.SECP256k1)
SIG = signingkey.sign_digest(txhash, sigencode=ecdsa.util.sigencode_der_canonize)
binascii.hexlify(SIG)
해제 스크립트(scriptSig) 생성하기
 생성된 signatur와 public key를 사용하여 scriptSig 구성
PUSHDATA Opcode 0x47
: 스택에 푸쉬될 바이트수, sigHash 포함
R, S는 32, 33 바이트가 될수 있음
압축공개키(02, 03), 비압축 공개키(04)
해제 스크립트(scriptSig) 생성하기
 최종 완성된 트랜잭션
0100000001416e9b4555180aaa0c417067a46
607bc58c96f0131b2f41f7d0fb665eab03a7e0
00000006a47304402201c3be71e1794621cbe
3a7adec1af25f818f238f5796d47152137eba7
10f2174a02204f8fe667b696e30012ef4e56ac
96afb830bddffee3b15d2e474066ab3aa39bad
012103bf350d2821375158a608b51e3e898e5
07fe47f2d2e8c774de4a9a7edecf74edaffffffff
01204e0000000000001976a914e81d742e2c
3c7acd4c29de090fc2c4d4120b2bf888ac0000
0000
Pay-to-public-key-hash(P2PKH) 스크립트 연산
Pay-to-public-key-hash(P2PKH) 스크립트 연산
Libbitcoin 라이브러리로 Raw transaction 생성하기
 https://github.com/ihpark92/Libbitcoin_T
utorial/blob/master/BitcoinNetwork/rawT
X.cpp
 https://github.com/ihpark92/Libbitcoin_T
utorial/blob/master/BitcoinNetwork/HD_
Wallet_Testnet.cpp
Libbitcoin 라이브러리로 Raw transaction 생성하기
Libbitcoin 라이브러리로 Raw transaction 생성하기
비트코인 노드의 기능
 Wallet
 지갑기능
 지갑은 사용자의 개인키와 공개키를 관리하고 거래에 사용되는 주소를 생성하는 기능을 담당
 Miner
 작업증명(Proof of Work : PoW) 알고리즘을 사용하여 10분간의 유효한 거래를 블록으로 생성하고
메인체인에 연결하는 기능
 Full Blockchain
 최초의 블럭인 제네시스블록과 가장 최신의 블록까지 포함한 완전한 블록체인 복사본을 보유
 Network Routing
 블록체인상의 P2P 네트워크 전송기능
비트코인 노드의 종류
 Reference Client
 모든 노드를 포함한 완전한 네트워크의 형태. Bitcoin Core가 여기에 해당
 Full Blockchain Node
 네트워크 라우팅 기능과 모든 블록체인 데이타를 가진 형태
비트코인 노드의 종류
 Solo Miner
 지갑기능은 제외하고 채굴에 특화된 형태의 노드
 Lightweight wallet(SPV : Simplified Payment Verification)
 지갑기능과 네트워크 라우팅기능만 포함된 노드로 전체 블록체인 데이타는 없이 단순히 거래와 유
효성 검증만 가능한 노드
SPV 노드의 유효성 검증
 풀노드의 경우, 전체 거래정보를 기반으로 UTXO를 검증하여 거래에 유효한지를 판단
 SPV노드는 전체 블록을 다운로드하지않고, 블록헤더만 다운로드 하기 때문에 전체블록 대비 1000분
의 1정도의 작은 용량만 차지
 거래정보가 없이 블록헤더만을 가지고 있기 때문에, 거래를 위해 블록체인상의 블록의 높이 대신 깊이
를 참조해서 거래를 검증
SPV 노드의 유효성 검증을 위한 블룸필터
 인근의 풀노드에게 헤더와 거래정보를 요청하여 거래의 유효성을 검증하여 거래를 진행
 헤더와 거래정보를 요청하는 과정에서 자신의 정보가 노출되어 익명성이 위배
 SPV 노드는 익명성을 유지하기 위해서 블룸필터를 추가하여 거래에 사용
 N개의 해쉬함수와 M개의 1비트 배열로 구성
 N개의 해쉬함수는 1에서 M 사이의 출력값을 가지고, 해당 출력값에 해당하는 인덱스의 비트배열을 1
로 설정
 N개의 해쉬함수에 대한 출력결과로 M비트배열은 N개가 1로 설정
블룸필터의 동작원리 - 필터생성
블룸필터의 동작원리 - 패턴검증
SPV노드의 거래를 검증하기 위한 머클패스
 거래 K와 머클패스로 제공된 Hash(L)을 사용하여 Hash(KL)을 계산
 머클패스로 제공된 Hash(IJ)와 계산된 Hash(KL)을 사용하여 Hash(IJHL) 계산
 계산된 Hash(IJKL)과 머클패스로 제공된 Hash(MNOP)를 사용하여 Hash(IJKLMNOP) 계산
 머클패스로 제공된 Hash(ABCDEFGH)와 계산된 Hash(IJKLMNOP)를 사용하여 Hash(ABCDEFGHIJKLMNOP)를
계산
 계산된 Hash(ABCDEFGHIJKLMNOP)와 헤더에 포함된 머클루트를 비교하여 동일한 값이면 거래 K가 블록에 포함
되어있음이 증명됨
머클트리의 효율성
 블록헤더(블록당 80 바이트)만 다운로드 받고, 수십 기가바이트가 될지도 모르는 블록체인 데이터를 저
장하거나 전송할 필요없이 풀노드로부터 작은 크기의 머클패스만 전송받아 거래의 포함여부를 확인할
수 있음
거래건수 블록의 대략적크기 경로크기(해쉬) 경로크기(바이트)
16건 4 KB 4 Hash 128 Byte
512건 128 KB 9 Hash 288 Byte
2,048건 512 KB 11 Hash 352 Byte
65,535건 16 MB 16 Hash 512 Byte
비트코인의 마이닝
 채굴(Mining)은 10분마다 새로운 비트코인을 생산하는 과정
 최초에 비트코인의 제네시스 블록이 생성된 시점에는 새로운 블록이 생성될때마다 50개의 비트코인이
보상으로 제공
 통화의 인플레이션을 방지하기 위해 비트코인은 4년마다(정확히는 210,000블록마다) 그 생산량이 절
반으로 줄어듬
거래의 유효성 검증
 거래의 구문과 데이터 구조가 정확해야 한다.
 입력값이나 출력값 목록이 비어있지 않아야 한다.
 바이트 단위의 거래 크기가 MAX_BLOCK_SIZE보다 작다.
 출력값 금액과 노드의 총 금액이 허용된 가치범위(0~2100만)내에 있어야 한다.
 입력값중 해시값은 0, N값은 -1이어서는 안된다.
 nLOCKTime은 INT_MAX보다 작거나 동일해야 한다.
 바이트 단위의 거래 크기가 100보다 크거나 동일해야 한다.
 거래에 담겨있는 서명작업 건수가 서명작업 한도내에 있어야 한다.
 해제스크립트는 스택상부에 숫자를 추가할수만 있고, 잠금 스크립트는 isStandard 형태와 일치해야 한다.
 풀이나 메인 브렌치에 있는 블록에 짝을 이루는 거래가 존재해야 한다.
 각각의 입력값에 대해, 참조 출력값이 풀 내의 어떠한 거래 내부에 존재한다면 해당거래는 거부되어야 한다.
 입력값에 해당하는 참조거래가 없는경우 고아거래 풀에 추가하라.
 각각의 입력값에 대해 참조 출력값이 코인베이스 출력이라면 최소 COINBASE_MATURITY(100) 승인을 받아야한다.
 각각의 입력값에 대한 참조 출력값이 존재해야 하고, 이미 소비되었으면 안된다.
 참조출력 거래에서 입력값을 가져올때 입력값 금액과 입력값 총액이 허용된 가치범위내에 있어야 한다.
 입력값 금액이 출력값 총액보다 작은 경우 해당 거래를 거절하라.
 거래 수수료가 비어있는 블록에 들어가기에 너무 작을때는 해당 거래를 거절하라.
 각 입력값에 대한 해제 스크립트는 그에 해당하는 출력값 잠금 스크립트에 대해 검증해야 한다.
블록에 거래 추가하기
 채굴노드는 먼저 검증된 거래가 들어있는 메모리풀(Memory pool) 또는 거래풀(Transaction pool)에서 조건에 맞
는 거래들을 선별하여 블록을 구성
 거래풀은 거래들이 블록내에 포함될수 있을때까지 기다리는 장소
 수수료와 우선순위로 메모리풀에서 거래가 선택되어짐 : 우선순위 = sum(거래수수료 * 거래나이) / 거래크기
 블록내부의 거래공간중 첫 50kbyte는 우선순위가 높은 거래들에게 할당됨
블록의 헤더 구성하기
크기 필드 설명
4 바이트 버전 버전 번호
32 바이트 이전블록 해시 체인내 이전블록의 해시에 대한 참조
32 바이트 머클 루트 거래의 머클트리의 루트에 대한 해시
4 바이트 타임스탬프 블록의 대략적인 생성시간
4 바이트 난이도 목표 블록의 작업증명 알고리즘에 대한 난이도 목표
4 바이트 논스 작업증명 알고리즘에 사용되는 카운터
작업증명(PoW:Proof of Work) 알고리즘
 해시 알고리즘은 임의의 길이를 가진 데이터 입력값을 가지고 고정된 길이의 결정적 결과값을 생산
 특정 입력값에 대한 해시 결과값은 항상 동일하고 쉽게 계산가능하며 어떤 노드에서도 검증가능
 특정 출력값에 대한 입력값의 추측이 불가능하여, 무작위 대입을 통해서만 원하는 출력값을 얻을수 있음
 SHA256 을 사용하여 출력값은 256비트 길이의 출력값 생성
 Nonce를 변화시켜가며 난이도 목표값보다 작은 출력값이 생성될때까지 SHA256 연산을 반복
 난이도 목표값보다 작은값이 발견된경우 블록채굴에 성공하여 채굴된 블록을 전파
작업증명(PoW:Proof of Work) 알고리즘
 Nonce 값의 데이터 크기는 4바이트
 nonce로 표현가능한 최대값은 42억
 nonce를 찾기위해 블록헤더를 hash 연산시 42억번의 연산이 수행되면 0으로 초기화가 됨
 즉, 42억번의 연산후에는 hash 연산의 초기화가 필요함
 merkle root 값을 변경하여 다시 nonce를 0으로 초기화후 PoW 연산 수행
 Coinbase 거래의 처음 8바이트(Extra nonce)를 추가로 사용
 1초에 296 개의 횟수까지 계산가능
블록의 작업증명 난이도 목표값
 target = coefficient * 2(8 ∗ 𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡 −3 )
 Bits : 419668748 = 0x1903a30c :
=> exponent = 0x19, coefficient = 0x03a30c
 target = 0x03a30c * 2**(0x08 * (0x19 - 0x03))
=> target = 0x03a30c * 2**(0x08 * 0x16)
=> target = 0x03a30c * 2**0xB0
=> target = 238348 * 2176
 target =
22,829,202,948,393,929,850,749,706,076,701,368,331,0
72,452,018,388,575,715,328
 target
= 0x0000000000000003A30C0000000000000000000000
0000000000000000000000
 2주마다(2016블록) 새롭게 계산
블록해쉬 구하기
https://blockchain.info/block-height/277316?format=json
import hashlib
import struct
little_endian = lambda value: struct.pack('<L', value).hex()
reverse_order_pair = lambda value: ''.join([value[i - 2:i] for i in range(len(value), 0, -2)])
# https://blockchain.info/block-height/277316?format=json
block_info = {
'version' : 2,
'prev_hash' : '0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569',
'merkle_root' : 'c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e',
'time' : 1388185914,
'bits' : 419668748,
'nonce' : 924591752,
}
convert_block_info = {}
# convert version, time, bits, nonce to little endian format
convert_block_info['version'] = little_endian(block_info['version'])
convert_block_info['time'] = little_endian(block_info['time'])
convert_block_info['bits'] = little_endian(block_info['bits'])
convert_block_info['nonce'] = little_endian(block_info['nonce'])
# reverse order of prev block hash, merkle root
convert_block_info['prev_hash'] = reverse_order_pair(block_info['prev_hash'])
convert_block_info['merkle_root'] = reverse_order_pair(block_info['merkle_root'])
# mix 6 block header info to one hex value
header_hex = convert_block_info['version'] + convert_block_info['prev_hash'] + 
convert_block_info['merkle_root'] + convert_block_info['time'] + 
convert_block_info['bits'] + convert_block_info['nonce']
# convert hex value to bin
header_bin = bytes.fromhex(header_hex)
# double hash
hash = hashlib.sha256(hashlib.sha256(header_bin).digest()).digest()
# reverse order and convert to hex
result_header_hex = hash[::-1].hex()
print(result_header_hex)
채굴 블록의 유효성 검증
 해당 블록의 데이터 구조는 문법적으로 유효하다.
 해당 블록 헤더 해시는 작업증명을 시행하는 목표 난이도보다 작다.
 해당 블록의 타임스탬프는 (시간오류를 고려해서) 향후 2시간 이내다.
 해당 블록의 크기는 허용할수 있는 한도내에 있다.
 제일 첫 거래는 코인베이스 생성거래이다.
 블록내의 모든 거래는 거래 유효성 검증과정에 이상이 없는 유효한 거래이어야 한다.
블록체인의 분기 - 1
 파란색 블록을 가장 최상위 블록으로 가지고 있는 블록체인을 나타내고 있으며, 모든 노드가 동일한 파란블록을 부
모블록으로 가지고 있음
블록체인의 분기 - 2
 캐나다에서 빨간색 블록이 생성되어 전파가 되고, 호주에서 초록색 블록이 생성되어 전파가 되고 있으며 두개 블록
은 모두 동일한 파란색 블록을 부모블록으로 하여 전파
블록체인의 분기 - 3
 각자 생성된 블록이 모든노드에 전파가 완료되면 다음 그림과 같이 빨간색 블록과 초록색 블록이 마지막 블록으로
이루어진 두개의 블록체인으로 분기가 발생
 초록색 블록으로 확장된 노드에서는 뒤늦게 도착한 빨간색 블록은 무시하게 되고, 마찬가지로 빨간색 블록으로 확장
된 노드는 뒤늦게 도착한 초록색 블록은 무시하게 됨
블록체인의 분기 - 4
 초록색 블록을 부모블록으로 가지는 노드에서 새롭게 분홍색 블록을 생성하여 전파를 시작
블록체인의 분기 - 5
 초록색 블록을 부모블록으로 가지는 노드는 정상적으로 확장이 진행되지만, 빨간색 블록을 부모로 가지는 노드는 2개
의 블록체인으로 분기
 파란블록->빨간블록으로 이루어진 블록체인과, 파란블록->초록블록->분홍블록 으로 이루어진 2개의 블록으로 분기
 분기가 발생하게 되는 경우 가장많은수의 블록으로 구성된 체인이 그만큼 유효한 작업증명이 이루어졌다고 판단하여
하기 예에서는 파란색->초록색->분홍색 블록으로 구성된 체인을 메인체인으로 선택하게 되고, 빨간색 블록에 포함되
어 있던 거래는 다시 거래풀에 들어가 새로운 블록생성을 위해 대기

Blockchain 1st bitcoin_core

  • 1.
  • 2.
    목차  블록체인의 개념 비트코인의 구성요소  비트코인 블록의 구조  개인키(Private key), 공개키(Public key), 비트코인 주소(Address)  키와 주소를 관리하는 지갑(Wallet)  비트코인 트랜잭션  scriptSig와 scriptPubKey의 생성방법과 유효성 검증방법  비트코인의 합의 알고리즘 : PoW(Proof of Work)  블록체인의 분기
  • 3.
    블록체인 – 가치공유의인터넷  기존의 인터넷은 "정보"를 전달, 블록체인은 "가치"를 전달  Alice가 Bob에게 1달러의 가치를 전달하는 경우  인터넷 뱅킹을 통한 1달러 이체  1달러의 디지털 상품권을 구입하여 전달  인터넷상에서의 가치전달의 문제점  중앙집중서버가 복구불가능상태로 파괴되거나 해킹된 경우 가치소멸  상품권을 복제하여 이중지불 문제 발생  블록체인을 통한 가치전달문제의 해결  모든 거래정보가 블록의 형태로 저장되어 모든 사용자에게 배포되고 저장  블록체인 고유의 합의 알고리즘을 통해 이중지불 문제 해결
  • 4.
  • 5.
  • 6.
    비트코인의 구성요소 -2  Wallet  각 사용자의 Private/Public 키를 생성하여 보관  Public키는 Private키를 기반으로 생성되고 Public 키를 기반으로 Bitcoin 주소가 생성  Transaction  실제 비트코인의 이동이 발생하는 거래를 말하며, 거래의 단위는 UTXO이고, 각 거래는 각 사용자 의 키로 서명이 되어 지정된 사용자끼리만 거래가 가능  Block  각각의 블록은 헤더와 10분간 발생한 거래정보가 포함  Network  거래와 블록을 네트워크상의 모든 노드에게 전파하는 P2P 기반 네트워크  Miner  거래가 포함된 Block을 가지고, 이중지불 문제가 발생하지 않도록 PoW(Proof of Work : 작업증명) 알고리즘으로 블록을 연결하는 주체
  • 7.
    비트코인의 해쉬(Hash) 함수: SHA256  어떤 길이의 입력값에 대해서도 동일한 길이의 출력값을 생성  Hash(A) = 123…asd(32바이트 길이), Hash(ABC) = afd…35f(32바이트 길이)  어떤 입력 X에 대해서 Hash(X) = Y 값을 쉽게 계산가능  비트코인 작업증명의 결과물인 블록의 유효성 검증이 쉽게 됨  Hash(X) = Y 인 경우, X값을 유추하는것이 불가능한 일방함수  비트코인 PoW에서 nonce를 찾는 과정  동일한 입력값에 대해서는 동일한 출력값을 생성하지만, 입력데이타가 변하면 완전히 새로운 출력값을 생성  https://anders.com/blockchain/hash.html
  • 8.
    해싱 데이터의 5가지패턴  독립해싱  순차적 해싱  반복해싱  계층적 해싱  결합해싱
  • 9.
    비트코인에서 Hash 함수사용  RIPEMD160(SHA256(x))  비트코인 주소 생성  SHA256(SHA256(x))  머클트리에서 트랜잭션의 해쉬 연산  트랜잭션 ID 생성  블록헤더의 해쉬 연산  Double hash 연산을 하는 이유  length-extension attacks 방지  A값을 몰라도 hash(A)와 length(A)를 알면 hash(A||B)을 알수 있음
  • 10.
    비트코인의 블록 –블록정보  Block explorer : https://www.blockchain.com/en/explorer
  • 11.
  • 12.
    비트코인의 블록 -블록헤더  Timestamp(블록이 생성된 시간) : 2018-03-01 08:11:49  Bits(블록 생성의 난이도) : 392009692  Version(프로토콜 버전) : 0x20000000  Merkle Root(트랜잭션 ID를 머클트리 형태로 구성한 해시정보) : b958fda3ce4d3cd0a41f01a6b00f6ae4e70f498a27f526cc5612f72450152d17  Previois Block(이전 블록의 해시정보) : 00000000000000000029b633899beed322666cc0041fbdf471300d52e6de1887  Nonce : 2170187189
  • 13.
    머클트리  특정거래가 블록내부에포함되는지 여부를 검증하는데 효율적인 프로세스를 제공  상향식으로 두개의 Hash값을 두번 해쉬(Double SHA256)하여 상위 Hash값 생성  Hash(AB) = SHA256(SHA256(Hash(A) + Hash(B))  이진 트리이기 때문에 짝수개의 리프노드가 필요하며 홀수개의 경우에는 마지막 노드를 복사하여 짝수 로 만들어서 사용
  • 14.
    머클루트 계산 import hashlib #Hash pairs of items recursively until a single value is obtained def merkle(hashList): if len(hashList) == 1: return hashList[0] newHashList = [] # Process pairs. For odd length, the last is skipped for i in range(0, len(hashList)-1, 2): newHashList.append(hash2(hashList[i], hashList[i+1])) if len(hashList) % 2 == 1: # odd, hash last item twice newHashList.append(hash2(hashList[-1], hashList[-1])) return merkle(newHashList) def hash2(a, b): # Reverse inputs before and after hashing # due to big-endian / little-endian nonsense a1 = a.decode('hex')[::-1] b1 = b.decode('hex')[::-1] h = hashlib.sha256(hashlib.sha256(a1+b1).digest()).digest() return h[::-1].encode('hex') # https://www.blockchain.com/en/btc/block/000000000003ba27aa200b1cecaad478d2b00432346c 3f1f3986da1afd33e506 txHashes = [ "8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87", "fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4", "6359f0868171b1d194cbee1af2f16ea598ae8fad666d9b012c8ed2b79a236ec4", "e9a66845e05d5abc0ad04ec80f774a7e585c6e8db975962d069a522137b80c1d", ] print merkle(txHashes)
  • 15.
    비트코인의 블록 –블록헤더 구조
  • 16.
    비트코인의 블록 –블록체인  하나의 블록은 계산된 Hash 값과 블록헤더, 10분간 진행된 거래(Transaction) 내역이 포함 되며 이 블록이 연속된 체인형태로 구성.
  • 17.
    대칭키 알고리즘  암호화/복호화속도가 비대칭키 암호 알고리즘보다 빠르다(최소10~최대1000배).  암호문의 크기가 평문보다 크지 않다(암호화 시 데이터 증가가 없다).  주로 데이터 통신의 암호화에 사용
  • 18.
    비대칭키 알고리즘  공개키로암호화한 데이터는 개인키로만 복호화가 가능하다.  개인키로 암호화한 데이터는 공개키로만 복호화가 가능하다.  비트코인의 트랜잭션에서는 비대칭키 암호화 알고리즘으로 유효성 검증이 이루어진다. https://anders.com/blockchain/public-private-keys/signatures.html
  • 19.
    개인키(Private key)  무작위로추출한 단순한 숫자  암호학적으로 안전한 의사난수생성기를 사용하여 생성되어야 함  비트코인에서 개인키를 생성하는 작업은 1에서 2256 사이의 숫자를 선택하는것과 동일  개인키는 256비트 길이의 숫자로 생성 유형 접두부 설명 Hex 없음 64개의 16진수 ex) 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD WIF 5 Base58Check 엔코딩 ex) 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn WIF-압축형 K 또는 L Base58Check 엔코딩, 인코딩전 접미부 0x01 추가 ex) KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
  • 20.
    타원곡선암호화(Elliptic Curve Cryptography) 공개키 암호화의 핵심은 고유의 트랩도어함수(Trapdoor function)  A + B = C : Not Trapdoor function  “Message” + public key = “s80s1s9sadjds9s” : Trapdoor function  RSA대비 256비트의 ECC가 3072 비트의 RSA와 동일한 보안을 제공 타원곡선 덧셈함수 타원곡선 곱셈함수
  • 21.
    공개키(Public key) -1  타원곡선 함수를 통해 Private 키로부터 계산. : OpenSSL 암호 라이브러리 사용  K = 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD * G  K = (x, y) x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB K = k * G (K : Public 키, k : Private 키, G : 생성포인트 상수) 𝑦2 = 𝑥3 + 𝑎𝑥 + 𝑏 𝑦2 = 𝑥3 + 7 : secp256k1(비트코인, 이더리움에서 사용하는 타원곡선) : a = 0, b = 7 : G = 02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798
  • 22.
    공개키(Public key) -2  비압축 공개키 : K = 04F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A↵ 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB  압축 공개키 : : K = 03F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A : 압축 공개키는 02, 03 의 접두어를 가지게 됨
  • 23.
    주소(Address)  숫자와 문자로구성된 문자열로 숫자 1로 시작 : 1thMirt546nngXqyPEz532S8fLwbozud8  개인키 및 공개키 쌍을 보유한 소유주  비트코인 거래의 대상  A = RIPEMD160(SHA256(K)) : K = Public 키
  • 24.
  • 25.
    Base58Check Encoding  길이가긴 숫자열을 압축해서 표현  10진법 : 0에서 9까지의 10개의 숫자를 사용  16진법 : 10개의 숫자와 6개의 부호를 사용  Base64 : 소문자 26개, 대문자 26개, 숫자 10개, 특수문자 2개(+, /) 사용  Base58 : Base64에서 0, O, l, I, +, / 를 제외  오자나 데이터 입력오류 등에 대한 추가보안을 설정하기 위해 Checksum 추가 유형 버전 접두부 Base58 접두부 결과값 비트코인 주소 0x00 1 Pay-to-script-Hash 주소 0x05 3 비트코인 테스트넷 주소 0x6F m , n 개인키 WIF 0x80 5, K, L BIF38 암호화 개인키 0x0142 6P BIF32 확장 공개키 0x0488B21E xpub BIF32 확장 개인키 0x0488ADE4 xprv
  • 26.
    개인키, 공개키, 주소의변환과정 http://royalforkblog.github.io/2014/08/11/graphical-address-generator/
  • 27.
    생성 가능한 주소의크기  생성 가능한 비트코인 주소의 크기 : 2160  1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,97  지구상의 모래알의 수 : 263  263개의 지구에 263개의 모래알이 있는경우의 수 : 2126  2126 = 2160 의 0.0000000058 %  2017년 기준 전세계 인구가 75억인 경우, 모든 사람은 각각 2127 개의 주소를 가질수 있음
  • 28.
    Libbitcoin 라이브러리  Bitcoin어플리케이션을 제작하기위한 크로스 플랫폼 C++ 라이브러리
  • 29.
    Libbitcoin 라이브러리  Libbitcoin라이브러리 설치 : https://github.com/libbitcoin/libbitcoin  Secp256k1 라이브러리 설치 : https://github.com/libbitcoin/secp256k1 $ git clone https://github.com/libbitcoin/secp256k1 $cd secp256k1 $ ./autogen.sh $ ./configure $ make $ ./tests $ sudo make install # optional $ g++ version # g++ 버전 확인 # 만약 g++ 버전이 낮다면 업그레이드 $ sudo apt-get install g++-4.8 $ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50 $ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50 $ sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-4.8 50 $ sudo apt-get install build-essential autoconf automake libtool pkg-config git $ sudo apt-get install libboost-all-dev $ wget https://raw.githubusercontent.com/libbitcoin/libbitcoin/version3/install.sh $ chmod +x install.sh $ sudo ./install.sh
  • 30.
    Libbitcoin 라이브러리 프로그래밍 #include<bitcoin/bitcoin.hpp> using namespace bc; int main() { // Extracting Satoshi's words from genesis block. const auto block = bc::chain::block::genesis_mainnet(); const auto& coinbase = block.transactions().front(); const auto& input = coinbase.inputs().front(); BITCOIN_ASSERT_MSG(input.script().size() > 2u, "unexpected genesis"); const auto headline = input.script()[2].data(); std::string message(headline.begin(), headline.end()); bc::cout << message << std::endl; return EXIT_SUCCESS; } $ g++ -std=c++11 -o satoshi satoshiwords.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin)
  • 31.
    개인키, 공개키, 주소생성 #include <bitcoin/bitcoin.hpp> #include <string> #include <iostream> using namespace bc; int main(void) { data_chunk seed(16); pseudo_random_fill(seed); ec_secret secretKey = bitcoin_hash(seed); std::string hexKey = encode_base16(secretKey); std::cout << "secret key: " << hexKey << std::endl; wallet::ec_private privateKey(secretKey); std::cout << "Private key: " << privateKey.encoded() << std::endl; wallet::ec_public publicKey = privateKey.to_public(); std::cout << "Public Key: " << publicKey.encoded() << std::endl; wallet::payment_address paymentAddress = publicKey.to_payment_address(); std::cout << "Bitcoin address: " << paymentAddress.encoded() << std::endl; return 0; } $ g++ -std=c++11 -o key key.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin)
  • 32.
  • 33.
    지갑(Wallet)  개인키(Private 키)와 공개키(Public key)를 담는곳  인터넷 연결유무에 따라 Hot wallet, Cold wallet으로 구분  비트코인은 UTXO(Unspent Transaction Output)의 형태로 블록체인상에 여러 사용자에게 모두 공유되어 저장  이와 같이 지갑은 실제 비트코인을 저장하는것이 아니고, 자신 소유임을 증명하기위한 개인 키와 공개키를 저장하는 곳  지갑의 종류  비결정적 지갑  결정적 지갑  계층 결정적 지갑
  • 34.
    비결정적 지갑  무작위로선택된 Private 키가 저장되어있는 지갑  여러개의 키 사이에 규칙이나 연속성이 없이 무작위 로 키가 생성  지갑이 생성될때 100개의 개인키를 무작위로 생성 하여 사용하고 이후 모든키가 사용된후에 다시 무작 위로 새로운 키를 생성  모든키를 백업하지못한 경우에 지갑이 손실되면 복 구를 할수가 없는 문제가 발생  지갑의 손실을 방지하기 위해서는 주기적으로 지갑 의 모든키를 백업해야 함
  • 35.
    결정적 지갑  랜덤하게발생된 Seed 에서 단방향 Hash 함수를 통해서 개인키를 연속적으로 생성  Seed만 알고있으면 추출키 전부를 복원할수 있기 때문에 특정시기에 한번의 백업만 해도 됨
  • 36.
    결정적 지갑 –연상기호 코드워드 (BIP39)  연상기호코드는 결정적 지갑을 얻기 위해 종자로 이용한 난수를 표현하는 영어 단어열  연상기호 단어 생성과정  128~256 비트의 random 값 A 생성  SHA256(A) 값의 첫 몇비트를 check sum으로 생성  check sum을 A 값의 끝부분에 추가  A를 11비트로 나누어 24개의 인덱스를 생성하고, 미리 정해진 2048개의 단어로 구성된 배열의 인덱스로 사용 하여 단어열 생성  PBKDF2 함수를 사용하여 512비트의 common seed 생성  연상기호 코드의 엔트로피와 단어길이 엔트로피(비트) 체크섬(비트) 엔트로피+체크섬 단어 길이 128 4 132 12 160 5 165 15 192 6 198 18 224 7 231 21 256 8 264 24
  • 37.
    결정적 지갑 –연상기호 코드워드
  • 38.
    계층결정적 지갑(HD Wallet)(BIP32, BIP44)  단일 종자(Seed)로부터 많은 키를 쉽게 얻기 위해 개발  부모키가 자식키열을 만들고, 각각의 자식키는 손자키 열을 만들수 있음  유기적인 구조의 의미를 표현하기 위해 트리 구조가 사용될수 있음  공개키에 대응하는 개인키에 접근하지 않고도 공개키열을 생성할수 있음
  • 39.
    종자(Seed)로부터 마스터키와 체인코드생성하기  HD지갑은 128,256,512비트 크기의 무작위 숫자인 root seed로부터 생성됨  Root seed로부터 HD지갑 전체를 복원할수 있음  Root seed는 연상기호 단어열로 표현됨
  • 40.
    개인 자식키 유도하기 부모키로부터 자식키를 얻기 위해 자식키 유도(CHD) 함수를 사용
  • 41.
    확장키  키 유도함수는세가지 입력값(키, 체인코드, 목표자식의 인덱스)을 기반으로 자식키를 생성  키와 체인코드를 결합한것 : 256비트의 키와 256비트의 체인코드를 512비트로 결합  확장 개인키 : 개인키와 체인코드의 결합, Base58Check 엔코딩시 ‘xprv’ 접두부 xprv9tyUQV64JT5qs3RSTJkXCWKMyUgoQp7F3hA1xzG6ZGu6u6Q9VMNjGr67Lctvy5P8oyaY AL9CAWrUE9i6GoNMKUga5biW6Hx4tws2six3b9c  확장 공개키 : 공개키와 체인코드의 결합, Base58Check 엔코딩시 ‘xpub’ 접두부 xpub67xpozcx8pe95XVuZLHXZeG6XWXHpGq6Qv5cmNfi7cS5mtjJ2tgypeQbBs2UAR6KECeeM VKZBPLrtJunSDMstweyLXhRgPxdp14sk9tJPW9
  • 42.
    공개 자식키 유도하기 개인키없이 공개 부모키로부터 공개 자식키를 생성  무한개의 공개키와 비트코인 주소를 생성할수 있지만 송금된 돈을 소비할수 없음
  • 43.
    Libbitcoin을 사용하여 HD지갑의키생성 #include <bitcoin/bitcoin.hpp> #include <string.h> #include <iostream> using namespace bc; int main(void) { data_chunk seedChunk(16); pseudo_random_fill(seedChunk); std::cout << "nHex Seed: " << std::endl; std::cout << encode_base16(seedChunk)<< std::endl; wallet::word_list writtenWord = wallet::create_mnemonic(seedChunk); if(wallet::validate_mnemonic(writtenWord)){ for(auto i = writtenWord.begin(); i != writtenWord.end(); ++i) std::cout << *i << ' '; }else{ std::cout << "mnemonic invalid!" << std::endl; } wallet::hd_private privateKey(seedChunk); std::cout << "nnMaster Private Key: " << std::endl; std::cout << privateKey.encoded() << std::endl; wallet::hd_key keys = privateKey.to_hd_key(); std::cout << "nHex Master Private Key: " << std::endl; std::cout << encode_base16(keys) << std::endl; wallet::hd_public publicKey = privateKey.to_public(); std::cout << "nMaster Public Key: " << std::endl; std::cout << publicKey.encoded() << std::endl; wallet::hd_private childPrivateKey = privateKey.derive_private(1); std::cout << "nChild Private Key: " << std::endl; std::cout << childPrivateKey.encoded() << std::endl; wallet::hd_public childPublicKey = privateKey.derive_public(1); std::cout << "nChild Public Key: " << std::endl; std::cout << publicKey.encoded() << std::endl; std::cout << "nPayment Adress: " << std::endl; std::cout << wallet::ec_public(childPublicKey.point()).to_payment_address().encoded() << "n" << std::endl; } https://github.com/ihpark92/Libbitcoin_Tutorial/blob/master/HD_Key.cpp
  • 44.
    HD지갑의 키생성 ihpark92@ubuntu:~/work$ ./HD_key HexSeed: c6343e966440d61d17423e81bfef3746 shiver peanut pitch silk aspect attend fringe elephant like youth soccer mind Master Private Key: xprv9s21ZrQH143K2CspDbSR9pNddmpvjZWpGV4KoZ2bc9d3RgthSDLreyTb72UFwwZowQjTwBBLaRceNgLwdjL77SccLQuQsp6vB8rujhW1xEp Hex Master Private Key: 0488ade40000000000000000000ec10abb36391b6aebb63d3697b8d1c61fd6f66d274b06945f9cc42c41cd40a000df61edf0d6426ebc85 f94e0668b053b1801f3ac40dcc7dd948d4ba329030d603731b412d Master Public Key: xpub661MyMwAqRbcEgxHKcyRWxKNBofR92EfdhyvbwSDAVA2JVDqykf7Cmn4xGoRNgqjSPh4SkXXzQ8GUr42KAUEr53q2N8bpfpu8tznqZWm5fM Child Private Key: xprv9vfdCPd3QdEeYdDEGBjV2gSVkdwcDLButpskBgm88hgKTQR6CaaQnKCrHhF2YSiKW652bazqYdLATouWi5fZaiYo4YRs1Y3TXF4Cr6Boxjd Child Public Key: xpub661MyMwAqRbcEgxHKcyRWxKNBofR92EfdhyvbwSDAVA2JVDqykf7Cmn4xGoRNgqjSPh4SkXXzQ8GUr42KAUEr53q2N8bpfpu8tznqZWm5fM Payment Adress: 1Bngpmye1f91RDtStQAVS2b9NsbNYhhK1K ihpark92@ubuntu:~/work$
  • 45.
  • 46.
  • 47.
    일반적인 거래  한거래의 출력값이 새로운 거래의 입력값이 되는 거래체인
  • 48.
    거래의 종류  하나의입력값과 2개의 출력값이 있는 경우  가장 일반적인 거래로 현실에서 거스름돈을 받는 형태  B에게 비트코인 2를 전달하고 나머지 8을 거스름돈으로 받는 거래
  • 49.
    거래의 종류  다수의입력값과 하나의 출력값이 있는 경우  동전과 단위가 작은 지폐가 많은경우 큰 단위의 지폐 한장으로 교환하는 행위  지불과정에서 잔액으로 받은 작은 단위의 금액을 정리하기 위해 지갑 어플리케이션에서 이 유형의 거래가 시행되기도 함
  • 50.
    거래의 종류  하나의입력값과 다수의 출력값이 있는 경우  기업체에서 다수의 직원에게 급여를 지불하는등 돈을 분배해야하는 경우
  • 51.
    거래의 종류  입력값이없고 출력값만 있는 경우  채굴에 성공한경우 채굴자에게 보상으로 비트코인을 제공하는 거래 : Coinbase 거래
  • 52.
    UTXO(Unspent Transaction Output) 블록체인상에서 거래의 단위  거래의 출력값으로, 사용되지않고 공개키로 암호화되어 블록체인상에 저장되어 있는 단위  암호화된 UTXO는 사용시점에 소유자의 개인키로 암호를 해제하여 거래의 입력값으로 사용  자신 소유의 비트코인의 전체 잔액을 확인하고자 한다면, 지갑에 저장되어 있다고 생각되는 비트코인의 갯수를 확인하는것이 아니라, 블록체인상에 자신의 소유로 저장되어 있는 UTXO 의 출력값을 모두 합한것을 확인
  • 53.
    비트코인 잔액조회 -UTXO의 총합 # get unspent outputs from blockchain API import json import requests # example address address = 1JBwfNy2oyhFCoNyLb4nnh2se7gA6DBU7B' resp = requests.get('https://blockchain.info/unspent?active=%s' % address) utxo_set = json.loads(resp.text)["unspent_outputs"] for utxo in utxo_set: print("%s:%d - %ld Satoshis" % (utxo['tx_hash'], utxo['tx_output_n'], utxo['value']))
  • 54.
    비트코인 잔액조회 -Libbitcoin 사용 https://github.com/ihpark92/Libbitcoin_Tutorial/blob/master/BitcoinNetwork/Balance.cpp #include <bitcoin/bitcoin.hpp> #include <bitcoin/client.hpp> #include <string.h> #include <iostream> using namespace bc; uint64_t balancer(const chain::history::list& rows) { uint64_t unspent_balance = 0; for(const auto& row: rows) { // spend unconfirmed (or no spend attempted) if (row.spend.hash() == null_hash) unspent_balance += row.value; } return unspent_balance; } void getBalance(wallet::payment_address address) { client::connection_type connection = {}; connection.retries = 3; connection.timeout_seconds = 8; connection.server = config::endpoint("tcp://mainnet.libbitcoin.net:9091"); client::obelisk_client client(connection); …… if(!client.connect(connection)) { std::cout << "Fail" << std::endl; } else { std::cout << "Connection Succeeded" << std::endl; } client.blockchain_fetch_history3(on_error2, on_done, address); client.wait(); } int main() { wallet::payment_address addy("15QzCiznJXqihKmNTgcxwS8nf7sdSXBAE9"); getBalance(addy); }
  • 55.
    UTXO의 생성  다른주소에서 자신의 주소로 비트코인을 송금받는 경우
  • 56.
    UTXO의 소멸  다른주소로 송금하기 위해 사용되는 경우
  • 57.
    거래(Transaction)의 구조 크기 필드설명 4 Byte Version 프로토콜 버전 1~9 Byte Input Count 입력값의 갯수 Variable Input 하나 이상의 입력값 1~9 Byte Output Count 출력값의 갯수 Variable Output 하나 이상의 출력값 4 Byte Locktime 블록에 추가되는 가장빠른시간
  • 58.
    거래(Transaction)의 구조 { "lock_time":0, "ver":1, "size":257, "inputs":[ { "sequence":4294967295, "witness":"", "prev_out":{ "spent":true, "tx_index":581424, "type":0, "addr":"1E3GodQUs3pdW4SasKXNHAtfJZHGmUhUxe", "value":1000000000, "n":1, "script":"76a9148f07a8d943b08ea22cd9e98d329d99025b45edfb88ac" }, "script":"47304402206f9748d80344eb4ef6492248843f0f179f8275c30788adf3ddbcddaebc9fc0 8a02202f09fda4b5f7caf0e958889069e999d1fb9258b28c7b6a8484b108f5be08efc60141046128 6410eda379b4790c5ff7d3ebcd078821c1773ee8200ae90ef211efe3aadd48ab65e2c4b482c23ba 6db447d9cf6d63939e07b73f57898d69a7bd3f90f4a97" } ], "weight":1028, "time":1388195590, "tx_index":41376062, "vin_sz":1, "hash":"04905ff987ddd4cfe603b03cfb7ca50ee81d89d1f8f5f265c38f763eea4a21fd", "vout_sz":2, "relayed_by":"67.83.126.1", "out":[ { "spent":true, "tx_index":41376062, "type":0, "addr":"1K8jp6ifZQZMT1WmJUKuh4RAJFtPAFGCHB", "value":500000000, "n":0, "script":"76a914c6e8e9dd79b5d8fef5309eba6aadc5323bf6315f88ac" }, { "spent":true, "tx_index":41376062, "type":0, "addr":"1Mdhkk4ofugGrtTCfJBiivzcGWRW4RWquF", "value":500000000, "n":1, "script":"76a914e253829af94cfba03688ad705b6b9d519ec9d3d588ac" } ] }, https://blockchain.info/block-height/277316?format=json
  • 59.
    거래의 입력과 출력의관계 https://blockchain.info/block-height/499118?format=json https://blockchain.info/block-height/500000?format=json { "lock_time":0, "ver":1, "size":215, "inputs":[ { "sequence":4294967295, "witness":"0247304402205f39ccbab38b644acea0776d18cb63ce3e37428cbac06dc23b59c61607aef6 9102206b8610827e9cb853ea0ba38983662034bd3575cc1ab118fb66d6a98066fa0bed01210304c0156 3d46e38264283b99bb352b46e69bf132431f102d4bd9a9d8dab075e7f", "prev_out":{ "spent":true, "tx_index":311962649, "type":0, "addr":"3FfQGY7jqsADC7uTVqF3vKQzeNPiBPTqt4", "value":34676070, "n":0, "script":"a914994394dbd20b7752e272458c738ae9b7666271b787" }, "script":"1600142b2296c588ec413cebd19c3cbc04ea830ead6e78" } ], "weight":533, "time":1513194393, "tx_index":311967252, "vin_sz":1, "hash":"fe6c48bbfdc025670f4db0340650ba5a50f9307b091d9aaa19aa44291961c69f", "hash":"503e4e9824282eb06f1a328484e2b367b5f4f93a405d6e7b97261bafabfb53d5", "vout_sz":2, "relayed_by":"0.0.0.0", "out":[ { "spent":true, "tx_index":311962649, "type":0, "addr":"3FfQGY7jqsADC7uTVqF3vKQzeNPiBPTqt4", "value":34676070, "n":0, "script":"a914994394dbd20b7752e272458c738ae9b7666271b787" }, { "spent":true, "tx_index":311962649, "type":0, "addr":"1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD", "value":31129454, "n":1, "script":"76a914ed5600751fea259a0f8c8bec09a626e7e4450e7a88ac" } ]
  • 60.
    거래 입력값과 출력값 필드설명 Transaction Hash 소비될 UTXO를 담고있는 거래에 대한 ID (TxID) Output Index 소비될 UTXO의 인덱스 번호 Unlocking Script Length 해제 스크립트 길이 Unlocking Script(ScriptSig) UTXO의 소비조건을 충족하는 스크립트 Sequence Number 사용하지않음, 0xFFFFFFFF로 설정  Input  Output 필드 설명 value 사토시 단위의 거래금액(1사토시는 1억분의 1 비트코인) Locking script length 잠금 스크립트 길이 Locking Script (ScriptPubKey) 출력값을 소비하는데 필요한 조건
  • 61.
    거래 스크립트  비트코인거래 유효화 엔진에서 거래의 유효성을 확인하기 위해 사용되는 스크립트  잠금 스크립트(scriptPubKey)와 해제 스크립트(scriptSig)  스택(stack)을 사용하여 계산되어짐  조건부 흐름제어기능 이외에는 루프나 복잡한 흐름제어기능을 가지고 있지않음  거래 스크립트의 5가지 표준  Pay-to-public-key-hash(P2PKH), 공개키, 다중서명, pay-to-script-hash(P2SH), 데이타출력 (OP_RETURN)
  • 62.
    잠금 스크립트(scriptPubKey) 생성하기 DUP + HASH160 + <pubKeyHash> + EQUALVERIFY + CHECKSIG  76 + a9 + length + pubKeyHash + 88 + ac  pubKeyHash = Base58Decode(1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD)  00ED5600751FEA259A0F8C8BEC09A626E7E4450E7A2F6DA14A  76 + a9 + 14 + ED5600751FEA259A0F8C8BEC09A626E7E4450E7A + 88 + ac  76a914ED5600751FEA259A0F8C8BEC09A626E7E4450E7A88ac "addr":"1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD", "value":31129454, "n":1, "script":"76a914ed5600751fea259a0f8c8bec09a626e7e4450e7a88ac"
  • 63.
    해제 스크립트(scriptSig) 생성하기 scriptSig를 제외한 트랜잭션 템플릿 작성  이전출력의 scriptPubKey를 사용하여 서명
  • 64.
    해제 스크립트(scriptSig) 생성하기 16진수 트랜잭션 메시지와 private key를 사용하여 signature 생성  생성된 signature 304402201c3be71e1794621cbe3a7adec1af25f818f238f5796d47152137eba710f2174a02204f8 fe667b696e30012ef4e56ac96afb830bddffee3b15d2e474066ab3aa39bad import hashlib, ecdsa, binascii from ecdsa import SigningKey, SECP256k1 mhex = ‘0100000001416e9b4555180aaa0c417067a46607bc58c96f0131b2f41f7d0fb665eab03a7e000000001976a91499b1ebcfc11a13df5161aba81 60460fe1601d54188acffffffff01204e0000000000001976a914e81d742e2c3c7acd4c29de090fc2c4d4120b2bf888ac0000000001000000’ txHash = hashlib.sha256(hashlib.sha256(mhex.decode('hex')).digest()).hexdigest() privkey = '3cd0560f5b27591916c643a0b7aa69d03839380a738d2e912990dcc573715d2c' signingkey = ecdsa.SigningKey.from_string(privkey.decode('hex'), curve=ecdsa.SECP256k1) SIG = signingkey.sign_digest(txhash, sigencode=ecdsa.util.sigencode_der_canonize) binascii.hexlify(SIG)
  • 65.
    해제 스크립트(scriptSig) 생성하기 생성된 signatur와 public key를 사용하여 scriptSig 구성 PUSHDATA Opcode 0x47 : 스택에 푸쉬될 바이트수, sigHash 포함 R, S는 32, 33 바이트가 될수 있음 압축공개키(02, 03), 비압축 공개키(04)
  • 66.
    해제 스크립트(scriptSig) 생성하기 최종 완성된 트랜잭션 0100000001416e9b4555180aaa0c417067a46 607bc58c96f0131b2f41f7d0fb665eab03a7e0 00000006a47304402201c3be71e1794621cbe 3a7adec1af25f818f238f5796d47152137eba7 10f2174a02204f8fe667b696e30012ef4e56ac 96afb830bddffee3b15d2e474066ab3aa39bad 012103bf350d2821375158a608b51e3e898e5 07fe47f2d2e8c774de4a9a7edecf74edaffffffff 01204e0000000000001976a914e81d742e2c 3c7acd4c29de090fc2c4d4120b2bf888ac0000 0000
  • 67.
  • 68.
  • 69.
    Libbitcoin 라이브러리로 Rawtransaction 생성하기  https://github.com/ihpark92/Libbitcoin_T utorial/blob/master/BitcoinNetwork/rawT X.cpp  https://github.com/ihpark92/Libbitcoin_T utorial/blob/master/BitcoinNetwork/HD_ Wallet_Testnet.cpp
  • 70.
    Libbitcoin 라이브러리로 Rawtransaction 생성하기
  • 71.
    Libbitcoin 라이브러리로 Rawtransaction 생성하기
  • 72.
    비트코인 노드의 기능 Wallet  지갑기능  지갑은 사용자의 개인키와 공개키를 관리하고 거래에 사용되는 주소를 생성하는 기능을 담당  Miner  작업증명(Proof of Work : PoW) 알고리즘을 사용하여 10분간의 유효한 거래를 블록으로 생성하고 메인체인에 연결하는 기능  Full Blockchain  최초의 블럭인 제네시스블록과 가장 최신의 블록까지 포함한 완전한 블록체인 복사본을 보유  Network Routing  블록체인상의 P2P 네트워크 전송기능
  • 73.
    비트코인 노드의 종류 Reference Client  모든 노드를 포함한 완전한 네트워크의 형태. Bitcoin Core가 여기에 해당  Full Blockchain Node  네트워크 라우팅 기능과 모든 블록체인 데이타를 가진 형태
  • 74.
    비트코인 노드의 종류 Solo Miner  지갑기능은 제외하고 채굴에 특화된 형태의 노드  Lightweight wallet(SPV : Simplified Payment Verification)  지갑기능과 네트워크 라우팅기능만 포함된 노드로 전체 블록체인 데이타는 없이 단순히 거래와 유 효성 검증만 가능한 노드
  • 75.
    SPV 노드의 유효성검증  풀노드의 경우, 전체 거래정보를 기반으로 UTXO를 검증하여 거래에 유효한지를 판단  SPV노드는 전체 블록을 다운로드하지않고, 블록헤더만 다운로드 하기 때문에 전체블록 대비 1000분 의 1정도의 작은 용량만 차지  거래정보가 없이 블록헤더만을 가지고 있기 때문에, 거래를 위해 블록체인상의 블록의 높이 대신 깊이 를 참조해서 거래를 검증
  • 76.
    SPV 노드의 유효성검증을 위한 블룸필터  인근의 풀노드에게 헤더와 거래정보를 요청하여 거래의 유효성을 검증하여 거래를 진행  헤더와 거래정보를 요청하는 과정에서 자신의 정보가 노출되어 익명성이 위배  SPV 노드는 익명성을 유지하기 위해서 블룸필터를 추가하여 거래에 사용  N개의 해쉬함수와 M개의 1비트 배열로 구성  N개의 해쉬함수는 1에서 M 사이의 출력값을 가지고, 해당 출력값에 해당하는 인덱스의 비트배열을 1 로 설정  N개의 해쉬함수에 대한 출력결과로 M비트배열은 N개가 1로 설정
  • 77.
  • 78.
  • 79.
    SPV노드의 거래를 검증하기위한 머클패스  거래 K와 머클패스로 제공된 Hash(L)을 사용하여 Hash(KL)을 계산  머클패스로 제공된 Hash(IJ)와 계산된 Hash(KL)을 사용하여 Hash(IJHL) 계산  계산된 Hash(IJKL)과 머클패스로 제공된 Hash(MNOP)를 사용하여 Hash(IJKLMNOP) 계산  머클패스로 제공된 Hash(ABCDEFGH)와 계산된 Hash(IJKLMNOP)를 사용하여 Hash(ABCDEFGHIJKLMNOP)를 계산  계산된 Hash(ABCDEFGHIJKLMNOP)와 헤더에 포함된 머클루트를 비교하여 동일한 값이면 거래 K가 블록에 포함 되어있음이 증명됨
  • 80.
    머클트리의 효율성  블록헤더(블록당80 바이트)만 다운로드 받고, 수십 기가바이트가 될지도 모르는 블록체인 데이터를 저 장하거나 전송할 필요없이 풀노드로부터 작은 크기의 머클패스만 전송받아 거래의 포함여부를 확인할 수 있음 거래건수 블록의 대략적크기 경로크기(해쉬) 경로크기(바이트) 16건 4 KB 4 Hash 128 Byte 512건 128 KB 9 Hash 288 Byte 2,048건 512 KB 11 Hash 352 Byte 65,535건 16 MB 16 Hash 512 Byte
  • 81.
    비트코인의 마이닝  채굴(Mining)은10분마다 새로운 비트코인을 생산하는 과정  최초에 비트코인의 제네시스 블록이 생성된 시점에는 새로운 블록이 생성될때마다 50개의 비트코인이 보상으로 제공  통화의 인플레이션을 방지하기 위해 비트코인은 4년마다(정확히는 210,000블록마다) 그 생산량이 절 반으로 줄어듬
  • 82.
    거래의 유효성 검증 거래의 구문과 데이터 구조가 정확해야 한다.  입력값이나 출력값 목록이 비어있지 않아야 한다.  바이트 단위의 거래 크기가 MAX_BLOCK_SIZE보다 작다.  출력값 금액과 노드의 총 금액이 허용된 가치범위(0~2100만)내에 있어야 한다.  입력값중 해시값은 0, N값은 -1이어서는 안된다.  nLOCKTime은 INT_MAX보다 작거나 동일해야 한다.  바이트 단위의 거래 크기가 100보다 크거나 동일해야 한다.  거래에 담겨있는 서명작업 건수가 서명작업 한도내에 있어야 한다.  해제스크립트는 스택상부에 숫자를 추가할수만 있고, 잠금 스크립트는 isStandard 형태와 일치해야 한다.  풀이나 메인 브렌치에 있는 블록에 짝을 이루는 거래가 존재해야 한다.  각각의 입력값에 대해, 참조 출력값이 풀 내의 어떠한 거래 내부에 존재한다면 해당거래는 거부되어야 한다.  입력값에 해당하는 참조거래가 없는경우 고아거래 풀에 추가하라.  각각의 입력값에 대해 참조 출력값이 코인베이스 출력이라면 최소 COINBASE_MATURITY(100) 승인을 받아야한다.  각각의 입력값에 대한 참조 출력값이 존재해야 하고, 이미 소비되었으면 안된다.  참조출력 거래에서 입력값을 가져올때 입력값 금액과 입력값 총액이 허용된 가치범위내에 있어야 한다.  입력값 금액이 출력값 총액보다 작은 경우 해당 거래를 거절하라.  거래 수수료가 비어있는 블록에 들어가기에 너무 작을때는 해당 거래를 거절하라.  각 입력값에 대한 해제 스크립트는 그에 해당하는 출력값 잠금 스크립트에 대해 검증해야 한다.
  • 83.
    블록에 거래 추가하기 채굴노드는 먼저 검증된 거래가 들어있는 메모리풀(Memory pool) 또는 거래풀(Transaction pool)에서 조건에 맞 는 거래들을 선별하여 블록을 구성  거래풀은 거래들이 블록내에 포함될수 있을때까지 기다리는 장소  수수료와 우선순위로 메모리풀에서 거래가 선택되어짐 : 우선순위 = sum(거래수수료 * 거래나이) / 거래크기  블록내부의 거래공간중 첫 50kbyte는 우선순위가 높은 거래들에게 할당됨
  • 84.
    블록의 헤더 구성하기 크기필드 설명 4 바이트 버전 버전 번호 32 바이트 이전블록 해시 체인내 이전블록의 해시에 대한 참조 32 바이트 머클 루트 거래의 머클트리의 루트에 대한 해시 4 바이트 타임스탬프 블록의 대략적인 생성시간 4 바이트 난이도 목표 블록의 작업증명 알고리즘에 대한 난이도 목표 4 바이트 논스 작업증명 알고리즘에 사용되는 카운터
  • 85.
    작업증명(PoW:Proof of Work)알고리즘  해시 알고리즘은 임의의 길이를 가진 데이터 입력값을 가지고 고정된 길이의 결정적 결과값을 생산  특정 입력값에 대한 해시 결과값은 항상 동일하고 쉽게 계산가능하며 어떤 노드에서도 검증가능  특정 출력값에 대한 입력값의 추측이 불가능하여, 무작위 대입을 통해서만 원하는 출력값을 얻을수 있음  SHA256 을 사용하여 출력값은 256비트 길이의 출력값 생성  Nonce를 변화시켜가며 난이도 목표값보다 작은 출력값이 생성될때까지 SHA256 연산을 반복  난이도 목표값보다 작은값이 발견된경우 블록채굴에 성공하여 채굴된 블록을 전파
  • 86.
    작업증명(PoW:Proof of Work)알고리즘  Nonce 값의 데이터 크기는 4바이트  nonce로 표현가능한 최대값은 42억  nonce를 찾기위해 블록헤더를 hash 연산시 42억번의 연산이 수행되면 0으로 초기화가 됨  즉, 42억번의 연산후에는 hash 연산의 초기화가 필요함  merkle root 값을 변경하여 다시 nonce를 0으로 초기화후 PoW 연산 수행  Coinbase 거래의 처음 8바이트(Extra nonce)를 추가로 사용  1초에 296 개의 횟수까지 계산가능
  • 87.
    블록의 작업증명 난이도목표값  target = coefficient * 2(8 ∗ 𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡 −3 )  Bits : 419668748 = 0x1903a30c : => exponent = 0x19, coefficient = 0x03a30c  target = 0x03a30c * 2**(0x08 * (0x19 - 0x03)) => target = 0x03a30c * 2**(0x08 * 0x16) => target = 0x03a30c * 2**0xB0 => target = 238348 * 2176  target = 22,829,202,948,393,929,850,749,706,076,701,368,331,0 72,452,018,388,575,715,328  target = 0x0000000000000003A30C0000000000000000000000 0000000000000000000000  2주마다(2016블록) 새롭게 계산
  • 88.
    블록해쉬 구하기 https://blockchain.info/block-height/277316?format=json import hashlib importstruct little_endian = lambda value: struct.pack('<L', value).hex() reverse_order_pair = lambda value: ''.join([value[i - 2:i] for i in range(len(value), 0, -2)]) # https://blockchain.info/block-height/277316?format=json block_info = { 'version' : 2, 'prev_hash' : '0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569', 'merkle_root' : 'c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e', 'time' : 1388185914, 'bits' : 419668748, 'nonce' : 924591752, } convert_block_info = {} # convert version, time, bits, nonce to little endian format convert_block_info['version'] = little_endian(block_info['version']) convert_block_info['time'] = little_endian(block_info['time']) convert_block_info['bits'] = little_endian(block_info['bits']) convert_block_info['nonce'] = little_endian(block_info['nonce']) # reverse order of prev block hash, merkle root convert_block_info['prev_hash'] = reverse_order_pair(block_info['prev_hash']) convert_block_info['merkle_root'] = reverse_order_pair(block_info['merkle_root']) # mix 6 block header info to one hex value header_hex = convert_block_info['version'] + convert_block_info['prev_hash'] + convert_block_info['merkle_root'] + convert_block_info['time'] + convert_block_info['bits'] + convert_block_info['nonce'] # convert hex value to bin header_bin = bytes.fromhex(header_hex) # double hash hash = hashlib.sha256(hashlib.sha256(header_bin).digest()).digest() # reverse order and convert to hex result_header_hex = hash[::-1].hex() print(result_header_hex)
  • 89.
    채굴 블록의 유효성검증  해당 블록의 데이터 구조는 문법적으로 유효하다.  해당 블록 헤더 해시는 작업증명을 시행하는 목표 난이도보다 작다.  해당 블록의 타임스탬프는 (시간오류를 고려해서) 향후 2시간 이내다.  해당 블록의 크기는 허용할수 있는 한도내에 있다.  제일 첫 거래는 코인베이스 생성거래이다.  블록내의 모든 거래는 거래 유효성 검증과정에 이상이 없는 유효한 거래이어야 한다.
  • 90.
    블록체인의 분기 -1  파란색 블록을 가장 최상위 블록으로 가지고 있는 블록체인을 나타내고 있으며, 모든 노드가 동일한 파란블록을 부 모블록으로 가지고 있음
  • 91.
    블록체인의 분기 -2  캐나다에서 빨간색 블록이 생성되어 전파가 되고, 호주에서 초록색 블록이 생성되어 전파가 되고 있으며 두개 블록 은 모두 동일한 파란색 블록을 부모블록으로 하여 전파
  • 92.
    블록체인의 분기 -3  각자 생성된 블록이 모든노드에 전파가 완료되면 다음 그림과 같이 빨간색 블록과 초록색 블록이 마지막 블록으로 이루어진 두개의 블록체인으로 분기가 발생  초록색 블록으로 확장된 노드에서는 뒤늦게 도착한 빨간색 블록은 무시하게 되고, 마찬가지로 빨간색 블록으로 확장 된 노드는 뒤늦게 도착한 초록색 블록은 무시하게 됨
  • 93.
    블록체인의 분기 -4  초록색 블록을 부모블록으로 가지는 노드에서 새롭게 분홍색 블록을 생성하여 전파를 시작
  • 94.
    블록체인의 분기 -5  초록색 블록을 부모블록으로 가지는 노드는 정상적으로 확장이 진행되지만, 빨간색 블록을 부모로 가지는 노드는 2개 의 블록체인으로 분기  파란블록->빨간블록으로 이루어진 블록체인과, 파란블록->초록블록->분홍블록 으로 이루어진 2개의 블록으로 분기  분기가 발생하게 되는 경우 가장많은수의 블록으로 구성된 체인이 그만큼 유효한 작업증명이 이루어졌다고 판단하여 하기 예에서는 파란색->초록색->분홍색 블록으로 구성된 체인을 메인체인으로 선택하게 되고, 빨간색 블록에 포함되 어 있던 거래는 다시 거래풀에 들어가 새로운 블록생성을 위해 대기