비트코인에서 개인키, 공개키, 주소를 생성하는 방식

Asterisk
7 min readAug 22, 2018

--

비트코인에서 발생하는 모든 트랜젝션은 공개 키 암호화 방식을 사용하여 서명하며, 유효한 서명으로 검증되지 않는 트랜젝션은 인정되지 않습니다.
공개키 암호화 방식은 개인키와 그에 대응되는 공개키의 쌍으로 이루어집니다.

개인키

개인키는 비밀키라고도 하며, 256비트 길이의 램덤 생성된 숫자입니다. 보통 다음과 같이 64자리의 16진수로 표현됩니다.

1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD

개인키로 서명한 트랜젝션을 공개키로 검증하는 방식을 통해서 트랜젝션의 발생 주체를 검증하기 때문에, 개인키가 외부에 노출될 경우 타인이 임의로 생성한 트랜젝션에 유효한 서명을 할 수 있게 됩니다. 이말은 곧 해당 개인키로 통제되는 모든 자산을 잃을 수 있다는 것을 의미합니다.

공개키

비트코인은 개인키로부터 공개키를 생성하는데에 secp256k1이라는 표준에 정의된 타원 곡선과 상수 집합을 사용합니다.

Koblitz curve secp256k1 : Y² = X³ + 7

Koblitz 곡선 secp256k1의 도메인 파라메터 T = (p, a, b, G, n, h)는 아래와 같이 정의되어있습니다.

p : FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFC2F
a : 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
b : 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000007
G : 02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798
n : FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
h : 01

타원곡선을 이용하여 개인키로부터 공개키를 연산하는 과정에서 스칼라 곱 연산이 등장하는데, 여기서의 합 연산과 곱 연산은 우리가 아는 일반적인 그것과 다릅니다.
타원곡선이 지니는 기하학적 성질을 이용하여 합 연산을 정의한 뒤, 그것의 n번 수행하는 것을 곱 연산으로 정의합니다. 물론 실제 연산을 위해서 대수식으로 표현하는 과정(= 대수기하)이 필요합니다.
이 부분은 아무리봐도 쉽게 설명할 순 없을거같고,
자세한 연산과정을 알고 싶으신 분들은 제가 참고했던 Elliptic Curve Cryptography: a gentle introduction 를 읽어보시는걸 추천드립니다.

개인키는 다음과 같이 곱 연산을 통해 개인키로부터 연산됩니다.

K = k * G (K : 공개키, k : 개인키, G : 생성자 포인트)
위의 설명과 같이 여기서의 곱하기 연산(*)은 G를 k번 더한 값을 의미합니다.

k = 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD 일 때,

K
= 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD * G
= ( x , y )
= ( F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A, 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB)

위의 두 개의 좌표 쌍은 아래와 같이 520비트 길이의 하나의 공개키로 표현됩니다.
= 04+ x좌표 + y좌표
=04F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB

G(생성자 포인트)는 항상 모든 비트코인 사용자에 대해 동일하기 때문에 G에 k(개인키)를 곱하면 항상 동일한 K(공개키)를 생성합니다. 하지만 타원곡선에서 곱하기 연산(*)은 단방향 연산이기 때문에 k(개인키)를 통해 K(공개키)를 구할 수는 있지만 그 반대는 불가능합니다. (곱하기 연산은 가능하지만, 나누기 연산은 불가능합니다.)

다시말해, 개인키의 소유자는 공개키를 쉽게 생성할 수 있고 개인키의 소유자가 아닌 사람이 공유된 공개키로 개인키를 생성하는 것은 불가능합니다.
이러한 속성은 비트코인의 모든 거래와 소유권을 증명하는 위조불가능하고 안전한 디지털 서명의 기초가됩니다.

위의 과정을 통해 공개키가 완성된 것 같지만,
현재 비트코인에서는 트랜젝션의 크기를 줄이기 위해 압축된 공개키 방식을 적용하여 사용하고 있습니다.
압축 공개키 방식은 x좌표를 알면 방정식 y² mod p = (x³ + 7) mod p를 풀어 y 좌표를 계산할 수 있는 성질을 이용합니다. 이를 통해 공개키를 구성하는 요소 중 x좌표만 저장하고 y좌표는 생략하여 키의 크기를 256비트만큼 줄일 수 있습니다.

= 04+ x좌표 + y좌표
=04F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
=(y가 홀수일때02, 짝수일때03) + x좌표
=03F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A

최종적으로,
개인키 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD로부터 그에 대응되는 공개키 03F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A를 얻어낼 수 있습니다.

주소

비트코인의 주소는 공개키를 Double Hash(SHA-256, RIPEMD-160)한 뒤 Base58Check 인코딩을 적용하여 만들어집니다.

Base58Check 인코딩에서는 payload에 버전 prefix를 붙인 뒤 SHA-256 Hash를 2번 적용한 결과의 첫 4바이트를 checksum으로 사용합니다.

Figure 6. Base58Check encoding (https://github.com/bitcoinbook)

공개키에서 주소를 생성하는 과정 역시 해시함수(단방향 연산)가 적용되어있기 때문에 반대로 주소를 바탕으로 공개키를 구하는 것은 불가능합니다.

이러한 과정을 거쳐서 구해진 1thMirt546nngXqyPEz532S8fLwbozud8가 최종적으로 비트코인을 송금받을 수 있는 주소가 됩니다.

--

--