[블록체인 연구소] 블록체인 비밀키와 공개키, 그리고 주소. 너네 도대체 무슨 관계야?

Block Odyssey Tech Blog
11 min readAug 9, 2023

--

이번 시간에는 블록체인 비밀키와 공개키, 그리고 주소와의 관계를 알아보도록 하겠습니다.
블록체인 네트워크마다 차이가 존재하기 때문에 대표적인 비트코인을 예로 들어보도록 하겠습니다.

그럼 먼저 비트코인 주소가 어떻게 생성되는지 전체적인 관계를 간단히 알아보겠습니다.
일반적으로 아래와 같은 관계를 가집니다.

비밀키(Private Key) → 공개키(Public Key) → 주소(Address)

비밀키로 공개키를 만들 수 있고, 또 공개키로 주소를 만들 수 있습니다.
하지만 절대 반대의 경우는 불가능합니다.

주소로 공개키를 생성하거나 공개키로 비밀키를 생성하는 것이 불가능하다는 것이죠.
왜 불가능한지는 아래에서 더 자세히 알아보도록 하겠습니다.

먼저 비밀키는 어떻게 만들어질까요?

비밀키는 단순히 0 ~2²⁵⁶ 사이의 값 중 하나입니다.
컴퓨터가 읽을 수 있는 이진수로 살펴보면 0과 1로 이루어진 256비트 값이죠.

2진수(Binary)

1010000100010010100100000111111010000000101001011101101111011100100110001010100110100000111000111011010001101111010001111011001011001001001010011000110111010100000010010001001111101110101010100000111111001101111011111100000101001000001110101111110100011111

잠깐! 여기서, 의문을 가질 수 있습니다.

“무작위로 비밀키가 발급되고 2²⁵⁶의 범위가 정해져 있다면 언젠가는 겹쳐야 하는 거 아닌가?”

아쉽지만 반은 맞고 반을 틀렸습니다.
물론 언젠가 겹치는 경우가 발생할 수 있지만 가까운 미래에는 불가능에 가깝다고 이야기할 수 있습니다.

아래에서 더 자세히 설명하겠습니다.

2²⁵⁶이 얼마나 큰 숫자인지 감이 오지 않으시리라 생각합니다.
생각보다 크지 않다고 생각하실 수도 있는데, 실제로는 어마무시하게 큰 숫자입니다.

예를 통해 살펴보겠습니다.

2²⁵⁶은 10⁷⁷과 비슷한 크기의 수입니다.
아직 그다지 감이 오지 않으실 수도 있는데요.
이러면 어떨까요?

( UnsplashGuillermo Ferla )
  • 지구의 원자 수는 10⁵⁰
  • 태양계의 원자 수는 10⁵⁷
  • 은하수의 원자 수는 10⁶⁸
  • 우주의 원자 수는 10⁸⁰

비트코인에는 10억 개의 은하에 들어 있는 원자 수만큼이나 다른 비밀키가 존재하는 셈입니다.

여담으로 1천억 년 동안 매 10^-12초에 1조 번 계산하는 1테라(10¹²)개의 컴퓨터가 수행하는 총 계산량이 10⁵⁵ 미만의 계산량에 불과하다고도 합니다.

그럼 지금부터 이렇게 생성한 비밀키로 공개키를 생성하는 방식을 알아보도록 하겠습니다.

비밀키로 공개키를 생성할 때에는 유한체, 타원곡선과 같은 수학적인 지식이 요구되어 복잡합니다.
최대한 전반적인 내용을 쉽게 다루고자 하는데, 이 과정에서 생략되는 부분이 있다는 점 미리 말씀드립니다.

먼저 공개키를 생성하는 식부터 살펴보겠습니다.

공개키를 생성할 때는 타원곡선 디지털서명 알고리즘(ECDSA; Elliptic Curve Digital Signature Algorithm)을 사용합니다.

e (Private key) * G (A point of elliptic curves) = P (Public key)

비밀키 e와 타원곡선의 한 점인 G를 곱하면 공개키 P가 생성됩니다.
식으로만 보면 굉장히 간단해보입니다.
현재 비트코인이 사용하고 있는 타원곡선과 타원곡선 위의 한 점인 G의 좌표 또한 공개가 되어있죠.

현재 비트코인이 사용하고 있는 타원곡선은 secp256k1입니다.
하지만 그 전에 타원곡선이 무엇인지 살펴보겠습니다.
타원곡선은 아래와 같은 방정식으로 나타낼 수 있습니다.

y² = x³ + ax + b

또 아래와 같이 그래프로도 나타낼 수 있죠.

( https://ko.wikipedia.org/wiki/타원곡선 )

위 그래프는 실제 타원곡선 암호에서 사용하는 타원곡선과는 다른 형태입니다.
위 이미지는 실수체 위의 타원곡선이고, 비트코인에서 사용하는 타원곡선은 유한체 위의 타원곡선입니다.

유한체라는 개념이 다소 생소하실텐데요.
간단하게 말하면 유한한 집합을 가진 수 체계입니다.

아래 그림이 유한체 위의 타원곡선의 그래프입니다.

( Programming Bitcoin )

실수체 위의 타원곡선과는 다르게 연속되지 않고 산재되어 있는 모습입니다.

위에서 비트코인은 secp256k1 타원곡선을 사용한다고 언급했습니다.
secp256k1 타원곡선은 a = 0, b = 7이며 타원곡선 방정식에 대입하면 y² = x³ + 7과 같은 식으로 나타낼 수 있습니다.

또 secp256k1 타원곡선 위의 한 점 G는 (x, y)로 아래와 같이 나타낼 수 있죠.

G = (0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)

G.x = 0x79be667e f9dcbbac 55a06295 ce870b07 029bfcdb 2dce28d9 59f2815b 16f81798

G.y = 0x483ada77 26a3c465 5da4fbfc 0e1108a8 fd17b448 a6855419 9c47d08f fb10d4b8

그럼 이제 처음에 살펴본 아래 식을 계산할 수 있겠죠?

e (0 ~ 2²⁵⁶) * G (0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8) = P(Public key)

우리는 이전에 공개키로 비밀키를 알아낼 수 없다고 했습니다.
하지만 위 식만 보면 가능할 것 같기도 한데요.

다행히 실제로는 불가능합니다.
이산로그 문제로 인해 비밀키 e와 타원곡선 위의 한 점 G를 알 때 공개키 P를 구할 수 있지만 공개키 P와 타원곡선 위의 한 점 G를 알때는 비밀키 e를 구할 수 없습니다.

이산로그 문제란?

이산로그 문제는 a^x = b를 계산하는 것은 쉽지만 x = log{a}b를 만족하는 x를 구하기는 어렵다는 것에서 나온 문제입니다.

이를 스칼라 곱셈으로 증명할 수 있는데요.
스칼라 곱셈은 한 점을 수회 반복해서 더하는 연산입니다.
타원곡선 위의 한 점 G를 e번 만큼 더한다고 생각하면 됩니다.
유한체라는 유한한 집합을 가진 수로 이루어져 있기 때문에 무한으로 커지지 않고 그 결과 값은 타원곡선 위의 한 점으로 존재합니다.

스칼라 곱셈이 활용되는 이유는 타원곡선에서 스칼라 곱셈의 역산이 어렵기 때문입니다.
즉, 스칼라 곱셈의 역계산 문제가 바로 이산로그 문제입니다.
또한 스칼라 곱셈으로 계산한 결과는 실제 계산하지 않고는 그 값을 예측하기가 매우 어렵습니다.

이제 우리는 공개키 P를 구할 수 있습니다.
그렇다면 공개키는 어떤 형태일까요?

타원곡선 위의 한점 G (x, y)를 비밀키 e의 값만큼 수회 반복해서 더했기 때문에 공개키 P는 (x, y)의 형태를 띄게 됩니다.
공개키 P도 결국엔 타원곡선 위의 한점으로 (x, y) 좌표 형태인 것이죠.

하지만 (x, y) 좌표 형태는 읽기 어렵기 때문에 직렬화라는 과정을 통해 형태를 바꿔줍니다.
공개키를 직렬화하는 표준이 존재하는데 이를 SEC 형식이라고 합니다.
SEC 형식은 비압축과 압축으로 구분할 수 있습니다.

비압축 SEC 형식

1. 0x04의 1바이트 접두부로 시작

2. x 좌표를 32바이트 빅엔디언 정수로 표현

3. y 좌표를 32바이트 빅엔디언 정수로 표현


047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77

압축 SEC 형식

1. y 값이 짝수면 0x02, 홀수면 0x03인 1바이트 접두부로 시작

2. x 좌표를 32바이트 빅엔디언 정수로 표현


0349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278a

지금까지 비밀키로 공개키를 생성하는 방식을 알아봤습니다.

전체적인 흐름을 설명하려다 보니 생략된 부분이 많은데, 다음에 기회가 된다면 한 부분씩 더 자세히 다뤄보도록 하겠습니다.

지금부터는 실제 우리가 비트코인을 보낼 때 사용하는 주소가 어떻게 만들어지는지 알아보도록 하겠습니다.

복습을 짧게 해보자면 비트코인의 공개키는 타원곡선 위의 (x, y) 좌표 형식이고, 표준안인 SEC 형식으로 직렬화한다고 했습니다.
SEC 형식은 비압축과 압축으로 구분할 수 있습니다.

공개키 암호 체계에서는 공개키가 주소가 될 수 있습니다.
실제로 비트코인이 막 나왔던 시기에는 비압축 SEC 형식 공개키가 주소로 할당되었다고 합니다.
하지만 비압축 SEC 형식은 그 길이가 길고 눈으로 읽기 어렵다는 단점을 가지고 있습니다. (비압축 SEC 형식은 65바이트 130자, 압축 SEC 형식은 33바이트 66자)

그리하여 길이를 줄여 가독성을 높이고 보안성도 한 단계 높인 비트코인 주소 형식이 고안되었습니다.
비트코인 주소를 생성하는 방법은 아래와 같습니다.

  1. 메인넷 주소는 0x00으로 시작하고, 테스트넷 주소는 0x6f로 시작합니다.
  2. 비압축 또는 압축 SEC 형식을 hash160(sha256 + ripemd160) 해시함수에 넣어 출력을 얻습니다.
  3. 1의 접두 바이트와 2의 최종 해시 결과를 합칩니다.
  4. 3에서 얻은 결과를 hash256(sha256 + sha256)로 해시하고 그 결과에서 첫 4바이트를 체크섬으로 취합니다.
  5. 3의 결과 뒤에 4의 결과를 붙이고 이를 Base58로 부호화합니다.

예를 들면, 압축 SEC 공개키, 0349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278a로 테스트넷 주소를 만드는 과정은 아래와 같습니다.

  1. 테스트넷 주소는 0x6f로 시작합니다.
    → 6f
  2. 압축 SEC 공개키를 hash160 해시함수에 넣어 출력합니다.
    → hash160(0349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278a) = 9f095cb7c820d5357770c11cfd07636defe66766
  3. 1의 접두 바이트와 2의 최종 해시 결과를 합칩니다.
    → 6f + 9f095cb7c820d5357770c11cfd07636defe66766 = 6f9f095cb7c820d5357770c11cfd07636defe66766
  4. 3에서 얻은 결과를 hash256로 해시하고 그 결과에서 첫 4바이트를 체크섬으로 취합니다.
    → hash256(6f9f095cb7c820d5357770c11cfd07636defe66766) = [54ba5154]a78775831aca9e22282490d0e27f6d2def5f9751e941dfb6d520f33d
  5. 3의 결과 뒤에 4의 결과를 붙이고 이를 Base58로 부호화합니다.
    → Base58(6f9f095cb7c820d5357770c11cfd07636defe66766 + 54ba5154) = mv1rx3tjf32AgjQEa9LYGHkgDdpwHRMPCX

압축 SEC 공개키, 0349fc4e631e3624a545de3f89f5d8684c7b8138bd94bdd531d2e213bf016b278a로 만들어진 비트코인 테스트넷 주소는 [mv1rx3tjf32AgjQEa9LYGHkgDdpwHRMPCX] 입니다.

네, 이렇게 주소까지 만들어봤습니다.
잘 따라 오셨는지 모르겠네요.

지금까지 블록체인 비밀키와 공개키, 그리고 주소의 관계를 알아봤습니다.

조금 어려우셨을 수도 있을 것 같은데, 전반적인 흐름만이라도 얻어가셨으면 좋겠습니다.
내용에 궁금한 점이 있으시다면 언제든 댓글 남겨주시면 감사하겠습니다.

감사합니다.

--

--