C#

비트코인 주소 생성

C# : 비트코인 주소를 생성하는 방법

비트코인 주소는 1 또는 3으로 시작한다. 만약 1로 시작하면 (예: 1PJ2er3A8sh2M7S9tGuhxRmRizTM2fCHqU), 그것은 P2PKH (Pay to Pubkey Hash) 주소 포맷이다. 만약 3으로 시작하면, 이는 P2SH (Pay to script hash) 주소 포맷으로 불리운다. 여기서는 Public Key로부터 비트코인 주소를 생성하는 P2PKH 주소에 대해 살펴본다.

비트코인 주소는 20 바이트 길이의 해시인데, Public Key로 부터 만들어 진다. 주소는 압축된 Public Key 혹은 압축되지 않은 Public Key로부터 만들어 질 수 있는데, Bitcoin v0.6 이상에서는 압축된 Public Key 를 사용한다. 압축된 Public Key는 33 바이트로서 이는 여러 정해진 단계를 거쳐 20 바이트 해시로 변형되게 된다.

다음은 Public Key를 비트코인 주소로 변형하는 단계들이다.

  • 스텝 1. Public Key를 SHA256 로 해시한다
  • 스텝 2. 전단계 결과에 대해 RIPEMD-160 해시를 수행한다
  • 스텝 3. 전단계 결과 앞에 1 바이트 Version Byte를 추가한다 (Main Network인 경우 0x00)
  • 스텝 4. Checksum을 계산함. 스텝3 결과에 SHA256 해시를 두번 실행 (더블해싱) 한 후 첫번째 4개의 바이트를 체크섬으로 한다
  • 스텝 5. 스텝3의 결과 마지막에 Checksum을 추가한다
  • 스텝 6. 마지막으로 전단계 결과에 Base58check 인코딩을 수행한다

/*
using System;
using System.Security.Cryptography;
using Org.BouncyCastle.Math;
using Base58Check;
*/

// Sample public key
string sPubKey = "03CEA90F438580ED05F3A9D976EB31783D7AE3825D7C1E499E31F4F9DF5243E392";
BigInteger pubKey = new BigInteger(sPubKey, 16);
byte[] publicKey = pubKey.ToByteArray();

// (1) SHA256 hash
var sha256 = SHA256.Create();
var shaHash = sha256.ComputeHash(publicKey);

// (2) RIPEMD160 hash
var ripemd160 = RIPEMD160.Create();
var mdHash = ripemd160.ComputeHash(shaHash);

// (3) Prefix version byte
var xmdHash = new byte[mdHash.Length + 1];
xmdHash[0] = 0x00; // Main network (0x00), Testnet3 (0x6f)
Array.Copy(mdHash, 0, xmdHash, 1, mdHash.Length);

// (4) Calc checksum
var doubleHash = sha256.ComputeHash(sha256.ComputeHash(xmdHash));
var checksum = new byte[4];
Array.Copy(doubleHash, 0, checksum, 0, 4); // the first 4 bytes

// (5) Add checksum at th end of Step 3
// 25 bytes binary Bitcoin address
var binAddr = new byte[25];
Array.Copy(xmdHash, 0, binAddr, 0, 21);
Array.Copy(checksum, 0, binAddr, 21, 4);

// (6) Base58check encoding
string address = Base58CheckEncoding.EncodePlain(binAddr);

Console.WriteLine(address); 
// Output: 1PJ2er3A8sh2M7S9tGuhxRmRizTM2fCHqU

위 코드이 마지막 단계에서 BASE58CHECK 인코딩을 수행하는데, Base58Check 라는 오픈소스 라이브러리를 사용하였는데, 이는 아래와 같이 Nuget을 통해 설치할 수 있다.
PM> Install-Package Base58Check

Hash160

Public Key가 비트코인 주소로 일단 변경되면, 이러한 변환이 해시 메카니즘에 의해 일어나기 때문에, 주소는 다시 원래의 Public Key 바이트 배열로 변경될 수 없다.

비트코인은 내부적으로 이러한 문자형태의 비트코인 주소를 직접사용하지 않는다. 대신 비트코인은 위의 스텝2에서 산출된 Public Key의 hash160 바이트 배열을 사용하게 된다. 즉, Public Key에 대한 hash160은 RIPEMD-160(SHA256(publcKey))의 결과라 할 수 있다. Public Key의 hash160은 내부적으로 블럭체인이나 비트코인 트랜잭션 안에서 사용된다.

아래 코드는 비트코인 주소 문자열을 Public Key의 hash160으로 변환하는 방법을 소개한 것이다.

public static byte[] GetHash160FromAddress(string address)
{
    byte[] addrBytes = Base58CheckEncoding.DecodePlain(address);
    byte[] hash160 = new byte[20];
    Array.Copy(addrBytes, 1, hash160, 0, 20);
    return hash160;
}

byte[] hash160 = GetHash160FromAddress("mgzQkAs8XACLdE1GRx6RzaSFoGkw9RCXnT");
// hash160: 10296FB42C5FB397A88E3170A03ACA3A55A63583
본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.

Previous Next Print