이 글을 이해하기 위해 컴퓨터 공학 지식이 일부 필요할 수 있습니다.
Address and Signature
불특정 다수로 구성되어 있는 Blockchain Network 에서, '나' 라는 존재를 어떻게 증명할 수 있을까요? '나' 혹은 '소유자' 라는 존재를 증명할 수 없다면, '소유 자산' 도 존재하지 않게 됩니다.
따라서, Blockchain 에서 거래가 성립하기 위해서는, '나' 라는 존재를 증명할 방법이 필요합니다. 여기에서 Address 및 Signature 시스템이 등장합니다.
Public-key cryptography
Address 및 Signature 는 전통적 컴퓨터 공학의 Public-key cryptography 를 사용하여 구현됩니다.
Public-key cryptography 는 주로 수학적 난제를 이용하여 암호화 혹은 해싱을 하는 기술입니다.
- 답 (Private Key) 을 알고 있는 경우에는 빠르게 처리할 수 있지만,
- 답을 모르는 경우에는 문제를 풀기 위해 큰 비용이 필요해서 현재의 컴퓨팅 파워로는 해결하기 어려운 문제를 활용합니다.
예) Rivest–Shamir–Adleman (RSA)
- 서로 다른 소인수 p와 q를 선택합니다
- φ = (p−1)(q−1)
- e = φ와 서로소
- ed를 φ로 나눴을 때 나머지가 1이 되는 d를 찾습니다.
- Public key 는 (e, p, q), Private Key 는 (d, p, q) 입니다.
이름 그대로, Public Key 는 누구나 알 수 있게 공개되며, Private Key 는 소유자만이 보관합니다. 크게 2가지 방식으로 사용되는데,
- Public Key 로 암호화 된 데이터는 Private Key 의 소유자만이 읽을 수 있습니다.
- 소유자만이 데이터를 Private Key 로 서명 (Sign) 할 수 있으며, Public Key 로 이 서명이 유효한지 확인할 수 있습니다.
블록체인에서는 주로 Elliptic Curve Digital Signature Algorithm (ECDSA) 를 Address 와 Signature 에 사용합니다.
Hash
Hash Algorithm (Hash Function)는 임의의 데이터를 가지고, 특정한 함수를 통해 고정된 길이의 데이터로 치환합니다. 유명한 Hash 함수로는 Message-Digest Algorithm(MD) 나 Secure Hash Algorithm(SHA) 가 있습니다.
Hash 를 하는 이유는 다양하지만, 대표적으로 아래와 같은 이유가 있습니다.
- 특정한 데이터가 유효한지 검증하고 싶은 경우 (Check Sum). 데이터가 변조되면 실질적으로 같은 Hash 값이 나오지 않습니다.
- 고정된 길이 (혹은 짧은 길이) 로 치환하고 싶은 경우.
Address
Address 는 Public Key 의 변형이며, Private Key 를 가지고 Sign 을 할 수 있다면, 해당 Address 의 소유자라고 할 수 있습니다.
- Bitcoin 은 여러 Address Format 을 사용하는데, 이 Format 은 Bitcoin 이 사용하는 Script (P2PK, P2PKH, P2SH, P2WPKH, .. ) 에 따라 달라집니다.
- Script 에 대해서는 다른 문서에서 설명합니다.
- Ethereum 의 경우에는 단일 Address Format 을 사용합니다.
public byte[] getPubKeyHash() {
if (pubKeyHash == null)
pubKeyHash = Utils.sha256hash160(this.pub.getEncoded());
return pubKeyHash;
}
(ECKey.java in BitcoinJ)
public String toBase58() {
return Base58.encodeChecked(getVersion(), bytes);
}
(LegacyAddress.java in BitcoinJ)
public static String encodeChecked(int version, byte[] payload) {
if (version < 0 || version > 255)
throw new IllegalArgumentException("Version not in range.");
// A stringified buffer is:
// 1 byte version + data bytes + 4 bytes check code (a truncated hash)
byte[] addressBytes = new byte[1 + payload.length + 4];
addressBytes[0] = (byte) version;
System.arraycopy(payload, 0, addressBytes, 1, payload.length);
byte[] checksum = Sha256Hash.hashTwice(addressBytes, 0, payload.length + 1);
System.arraycopy(checksum, 0, addressBytes, payload.length + 1, 4);
return Base58.encode(addressBytes);
}
(Base58.java in BitcoinJ)
P2PKH Script 에서, Public Key 로 부터 Address 를 만드는 과정은 아래를 따릅니다.
- Public Key 에 대해 sha256 Hash 를 구합니다.
- (1)에 대해 ripemd160 Hash 를 구합니다.
- (2)에 대해 버전 및 체크섬 해시 정보가 포함된 데이터를 구합니다.
- 첫 1 Byte 는 버전 정보이며, 네트워크 혹은 Address Format 에 따라 결정 됩니다.
- 그 다음 20 Byte (160 Bit) 만큼, payload (ripemd160 hash 된) 가 나타납니다.
- 마지막 4 Byte 는 SHA256 해시이며, 위에서 만들어진 21 Byte 를 가지고 해시를 2회 구합니다.
- 25 Byte 길이를 가지는 Address.
- (3)에 대해 Base58 인코딩을 합니다. 최종적으로 유저에게 노출되는 Address 가 됩니다.
특정한 프로젝트에서 파생된 Blockchain 은 원본 프로젝트의 Address 시스템을 따라가는 경우가 많습니다.
Ethereum 및 그 파생 프로젝트의 경우, 서로 다른 Network 라고 봐야 함에도, Address 가 호환되기 때문에, 유저들이 혼동하는 경우가 자주 발생합니다.
Transaction and Signature
Bitcoin 을 기준으로, Address 는 'Hash 된' Public Key 이기 때문에, 엄밀히 말하면 Public Key 가 아닙니다. 따라서 실제 Transaction (거래) 를 작성하는 시점에, Address 의 소유자는 Public Key 를 같이 공개합니다.
Public Key 가 공개되면, Address 는 Public Key 로 부터 만들어 졌으므로, Blockchain Network 참여자들은 동일한 방법으로 이를 검증할 수 있습니다.
Public Key 가 유효하다면, Private Key 를 가진 소유주는 Blockchain Network 참여자들에게, 자신이 자산을 소유하고 있음을 Public-key cryptography 를 통해 증명할 수 있습니다.
Reference
- Rivest, R.; Shamir, A.; Adleman, L. (February 1978). "A Method for Obtaining Digital Signatures and Public-Key Cryptosystems"
- Diffie, W.; Hellman, M.E. (November 1976). "New directions in cryptography"
- BitcoinJ, Apache License 2.0
- List of address prefixes