1. Bitcoin
1-1. Bitcoin 이란?
- 2009 년 사토시 나카모토에 의해 고안된 대표적인 Public 블록체인 시스템
- 화폐 단위 : BTC
- Bitcoin 알고리즘에 의해 생성
- 트랜잭션을 통해 참여자간의 화폐의 이동을 구현
- block 의 body 에 저장
- 분산 P2P 네트워크
- 특정 서버에 의해 관리되는 것이 아님
- 참여, 탈퇴가 자유로운 탈중앙화된 시스템
- 오픈소스
- 참여하는 노드들이 수행하는 프로토콜을 정의
- 트랜잭션과 블록의 생성과 검증 규칙을 정의
- 신규 화폐의 생성 알고리즘을 정의
1-2. Bitcoint 특징
1-2-1. 주요 특징
- 소유권과 신원 증명을 위한 암호화 - SHA-256 사용
- ECDSA 기반의 전자 서명 알고리즘
- 블록 체인의 동일성을 유지하기 위한 Proof of Work 정책 구현
- Full node로 구성된 Bitcoin 네트워크에서 동작
1-2-2. Bitcoin 발행
- Mining(채굴) 에 의해 발행
- 현재 평균 10분마다 새로운 블록이 생성됨
- 발행은 최대 2,100 만개
2. Bitcoin 의 키, 주소
2-1. 키
- ECDSA 기반의 전자 서명 알고리즘을 사용
- 타원곡선을 이용한 개인 키와 공개 키를 사용
- Chapter 2 에서 미리 학습했던 내용들을 그대로 가짐
- Bitcoin 에서의 공개 키
- 전체 65-byte = 520-bit 의 크기
- prefix 8-bit + x좌표 256-bit + y좌표 256-bit
- 전체 65-byte = 520-bit 의 크기
2-1-1. Bitcoin 에서 트랜잭션
만약 트랜잭션이 의 수가 많아진다면?? ( 트랜잭션의 수 = T(n) )
→ 필요한 공간 = $T(n)*65\ byte$
→ 필요한 공간이 크기에 저장할 수 있는 $T(n)$ 의 수가 제한적
→ 공개 키 기반으로 하지만 조금 더 짧은 주소가 필요함
2-2. 주소
- 숫자와 문자로 구성된 문자열
- 본인에게로 송금할 때 사용하는 주소
- 지갑의 주소
2-2-1. 그래서 어떤 주소를 사용?
- Public key hash
- Hash160( 공개 키 )
- Base58Check( public key hash )
- 마지막으로 Base58Check 로 변환
- “bc1” 로 시작하는 Bech32 형태로도 많이 사용하나 여기선 위의 단계들을 중심으로 공부할 예정
2-3. 공개 키 → Bitcoin 주소 변환 과정
2-3-1. Hash160
SHA256, RIPEMD160 을 거쳐 160-bit 의 해시 값을 얻는 과정
→ 이 과정의 결과가 Public Key Hash
2-3-2. Base58Check Encode
Base58check 인코딩
→ 최종 Bitcoin 주소
2-4. Base58Check Encoding
- 9개의 숫자 + 24개의 대문자 + 25개의 소문자 = 58개의 문자로 구성
- (0, O), (I, l) 유사하게 생긴 문자들은 제외시킴
- prefix
- 8bit(4byte) 의 version byte 추가
- 비트코인 주소 : 0x00 (1)
- checksum
- error check
- 8bit(4byte) 의 크기
3. Bitcoin Transaction
화폐의 흐름을 의미
→ Bitcoin 에서는 화폐의 단위로 BTC, satoshi 2가지를 사용
3-1. Transaction 입력과 출력
- 입력 : 화폐를 인출할 Bitcoin Tx 의 id
- 출력 : 화폐를 전달할 Bitcoin 주소
- Tx fee : 블록체인에 등록할 miner 에게 지급할 요금
- 입력 금액의 합 - 출력 금액의 합
3-1-1. Transaction 체인
- 한 트랜잭션의 output 은 다른 트랜잭션의 input 으로 사용
- input 과 output 은 n:1, 1:n 다양한 조합이 가능
3-1-2. Spent, Unspent
- Spent : output 이 다른 트랜잭션의 input 으로 사용되어 더 이상 사용할 수 있는 권한이 사라짐
- Unspent : 다른 트랜잭션의 input 으로 사용되지 않아 주인이 사용할 수 있는 권한을 가짐
3-2. UTXO
- Unspent Transaction Outputs
- 다른 트랜잭션의 입력에 연결되지 않은 출력들
- 특정 사용자의 잔고 : 사용자의 주소로 output 인 UTXO 들의 합
- UTXO 는 일부만을 사용하는 것은 불가능 → 잔액이라는 개념은 없음
- 전부를 사용 or 아예 사용x
3-2-1. 이중 지불
- 은행과 같이 중앙 관리 시스템이 존재하는 경우
- 일을 동시에 처리하는 것이 아닌 들어온 순서대로 처리
- 이중으로 지급되는 문제를 막을 수 있음
3-2-2. UTXO 이중 지불
- UTXO를 여러 개의 트랜잭션의 입력으로 사용
- 트랜잭션과 블록 검증 단계에서 반드시 걸러야 함
3-3. Transaction Output
트랜잭션의 출력부에는 두 가지의 핵심 내용이 포함
- 금액 : output 으로 보내게 될 금액을 저장
- scriptPubKey
- public key hash 가 저장되어있음
- Bitcoin 주소를 가리킴
- BSL 명령어들이 저장되어있음
- OP_DUP, OP_HASH160, OP_EQUALVERIFY, …
- Locking script 로 칭함
- public key hash 가 저장되어있음
3-4. Transaction Input
트랜잭션의 입력부에는 크게 세 가지의 핵심 내용이 포함
- 트랜잭션 id
- 출력 index
- 해당 트랜잭션에서 몇 번째의 출력(UTXO) 인지를 알려줌
- scriptSig
- 두 가지의 전자 서명이 저장되어있음
- Bitcoin 은 ECDSA 기반의 전자 서명
- public key 가 저장되어있음
- Unlocking script 로 칭함
- 두 가지의 전자 서명이 저장되어있음
3-5. BSL
3-5-1. Bitcoin Script Language
- Bitcoin 에서 사용하는 Stack 기반의 프로그래밍 언어
- 피연산자의 경우 push
- 연산자의 경우 필요한 만큼 피연산자 pop
- 입력부의 Unlocking script 가
- 정확 = 최종 스택에는 TRUE
- 부정확 = 최종 스택에는 FALSE
- Bitcoin 네트워크의 모든 노드들이 트랜잭션을 검증하며, 검증된 트랜잭션만 블록체인에 저장
- Turing incomplete
- 반복문의 기능은 존재하지 않음
3-5-2. P2PKH
- Pay to Public Key Hash
- Bitcoin 트랜잭션들이 사용하는 방법
3-5-3. Script 구성
입력부가 참조하는 UTXO 출력부의 Locking script + 입력부의 Unlocking script
Locking script
$$ \{\ <signature>,\ <public\ key>\ \} $$
- signature : 전자 서명
- public key : 공개 키
Unlocking script
$$ \{\ dup,\ hash160,\ <public\ key\ hash>,\ equalverify,\ checksig\ \} $$
- dup : 복제 명령어
- hash160 : sha256, ripemd160 수행 명령어
- public key hash : 공개 키 해시
- equalverify : 동일한지 비교
- checksig : 서명 검증
3-5-4. P2PKH 검증
signature, public key 피연산자 push
public key 복제
복제된 public key 로 hash160 (sha256, ripemd160) 수행
public key hash push
hash160 을 거친 public key hash 와 같은지 비교
최종적으로 전자 서명 검증
→ 검증에 성공했다면 TRUE
→ 검증에 실패했다면 FALSE
4. Bitcoin 네트워크
Bitcoin 프로토콜을 실행하는 노드들의 탈중앙화된 네트워크
4-1. Bitcoin 노드의 역할
모든 노드들이 역할을 모두 수행하지는 않음
- 라우팅 기능
- 트랜잭션과 블록을 검증 & 전파
- peer 와의 연결 유지
- 블록체인 저장
- 전체 일부 블록체인 DB 를 저장
- 채굴
- 새로운 블록을 추가 → PoW 수행
- 지갑 서비스
- 사용자의 화폐 관리, 키와 주소 관리, 트랜잭션 생성…
4-2. Bitcoin 노드의 종류
- Bitcoin core
- 모든 역할을 수행하는 노드
- Full node 로 칭함
- Lightweight wallet
- 라우팅 기능 + 지갑 서비스
- 블록의 헤더만 저장
- SPV ( Simplified Payment Verification ) 노드로 칭함
- Solo miner
- 라우팅 기능 + 블록체인 저장 + 채굴
- 채굴이 주 목적
- Mining nodes
- 채굴만 포함
4-2-1. Full node ↔ SPV node
💡 SPV node C, D
Transaction T : C 가 D 에게 화폐 전송
Block B : T 를 포함하는 블록
- C 가 T 생성 & Bitcoin 네트워크로 전파
- D 가 T 수신
- T 를 트랜잭션 pool 에 저장
- 후에, 채굴자에 의해 T 를 포함하는 블록이 체인에 등록되어야 T 의 실행이 완료
- 채굴자가 PoW 수행을 성공
- D 를 Bitcoin 네트워크로 전파
- 모든 Full node 들은 D 를 검증
- 검증에 통과했다면 자신의 체인에 추가
- D 는 Full node 들로부터 T 가 B 에 등록되었는지 확인 요청
- 이때, 어떤 T 인지는 알려주고싶지 않음
- Bloom Filter 사용
4-3. Bloom Filter
집합에 해당 원소가 포함되는지 확인할 수 있는 자료구조
4-3-1. Bitcoin Bloom Filter
- N bit 의 배열 + M 개의 해시 함수로 구성
- 해시 함수는 1 과 N 사이의 값을 반환
Bloom Filter 초기 설정
- 필터가 가지고 있는 원소들을 해싱
- 결과에 해당하는 인덱스에 값을 1 로 set
Bloom Filter 를 이용한 확인
- 전달받은 원소로 해싱
- 결과에 해당하는 인덱스의 값들이 모두
- 1이라면 → TRUE 반환
- 하나라도 1이 아니라면 → FALSE 반환
4-3-2. 특징
- 실제 집합에 포함되지 않는 원소라도 포함되어있다고 결과가 나올 수 있음
- 집합에 이미 존재하는 값들 덕분에 우연하게 모두 1로 set 된 경우
- N 과 M 이 커지면
- 우연하게 겹칠 확률이 작아지기 때문에 정확성은 높아짐
- 그러나 정확히 어떤 원소들이 포함되어있는지 확인이 가능하기에 보안성은 낮아짐
- N 또는 M 이 작아지면
- 우연하게 겹칠 확률이 높아지기 때문에 정확성은 낮아짐
- 그러나 정확히 어떤 원소들이 포함되어있는지 확인이 어렵기에 보안성은 높아짐
5. 블록체인 구조
- 트랜잭션을 포함한 블록들의 연결 리스트
- 역방향으로 연결
- 이전 블록의 헤더에 대한 해시 포인터로 연결
- 블록 ID
- 기본 ID : 블록의 헤더에 대한 해시
- 대체 ID : 블록체인에서의 위치 ( Block height )
5-1. 블록의 헤더
필드 사이즈 설명
Version | 4 byte | 적용할 블록 검증 규칙을 적어둔 블록 버전 |
Previous block header hash | 32 byte | 이전 블록 헤더에 대한 해시 |
Merkle root hash | 32 byte | Metkle tree root 에 대한 해시 |
Timestamp | 4 byte | 블록이 생성된 시간 |
Difficulty target | 4 byte | PoW 알고리즘이 수행되는 난이도 |
Nonce | 4 byte | PoW 알고리즘의 성공조건 |
5-2. Merkle Tree
- 블록의 바디 부분의 무결성을 보장하기 위함
- Binary Hash Tree 구조
- 기본적으로 각 노드들은 sha256 을 두번 수행
- $root\ node\ :\ Merkle\ root\ hash$
- $leaf\ node\ :\ sha256(sha256(T))$
- $!(leaf \ node)\ :\ sha256(sha256(lchild(H)+rchild(H)))$
- 자식이 하나라면 복사
5-2-1. 장점
- 블록 바디의 모든 트랜잭션들의 무결성을 쉽게 검증 & 보장
- 단순히 루트의 해시 값만 저장하기에 저장 공간이 작음
- 단순하고 빠른 계산
5-3. Merkle Path
- 특정 트랜잭션이 포함되어 있는지 확인하는 방법
- root 까지 가는 경로를 밟으며 확인
5-3-1. 트랜잭션 검증
- Full node 로 받은 Merkle Block 에 저장되어있는 Transaction count 를 통해 트리 구조 생성
- Merkle Block 에 저장되어있는 Flags & Hash 값들을 이용해 검증
- Flags 의 bit 값을 이용해 검증 진행
- bit == 1 && !(leaf) : 해시 계산
- bit == 1 && leaf : 리스트에서 해시 값 가져옴
- Bloom Filter 를 통과한 트랜잭션
- 검증하고자 하는 트랜잭션
- bit == 0 && !(leaf) : 리스트에서 해시 값 가져옴
- bit == 0 && leaf : 리스트에서 해시 값 가져옴
- Bloom Filter 를 통과하지 못한 트랜잭션
- 검증하고자 하는 트랜잭션의 짝
5-3-2. 실제 검증 과정
- Transaction count = 7
- Hash = 총 4개 ( 검증하고자 하는 트랜잭션 Hash 1개 + 검증에 필요한 트랜잭션 Hash 3개 )
- H1 ~ H4
- 검증하고자 하는 트랜잭션 = C
- Flags = 11011000 가정
1 ( bit == 1 && !(leaf) ) → 해시 계산
- 1번 과 2번이 필요 → 1번으로 이동
1 ( bit == 1 && !(leaf) ) → 해시 계산
- 3번 과 4번이 필요 → 3번으로 이동
0 ( bit == 0 && !(leaf) ) → 리스트에서 해시 값
- H1 저장
- 4번으로 이동
1 ( bit == 1 && !(leaf) ) → 해시 계산
- 5번 과 6번이 필요 → 5번으로 이동
1 ( bit == 1 && leaf ) → 리스트에서 해시 값
- Bloom Filter 를 통과한 트랜잭션 → 검증하고자 하는 트랜잭션
- H2 저장
- 6번으로 이동
0 ( bit == 0 && leaf ) → 리스트에서 해시 값
- Bloom Filter 를 통과하지 못한 트랜잭션 → 검증하고자 하는 트랜잭션의 짝
- H3 저장
- H2 와 H3 으로 4번 계산
- H1 와 4번 으로 1번 계산
- 2번으로 이동
0 ( bit == 0 && !(leaf) ) → 리스트에서 해시 값
- H4 저장
- 1번 과 H4 로 root 계산
- 검증 가능