본문 바로가기

Blockchain/Ethereum

암호학 - 마스터링 이더리움

개요

암호학은 수학의 한 분야로 이더리움의 기반 기술

암호화는 비밀 작성에 그치는 것이 아니며, 비밀을 드러내지 않고 지식을 증명(디지털 서명)하거나, 데이터의 진위성(해시를 통한 디지털 지문)을 증명할 수 있음이더리움 플랫폼과 노드 간 통신은 암호화되어 있지 않아 모두가 들여다 볼 수 있어 합의에 도달할 수 있음

향후에는 영 지식 증명과 동형 암호화 같은 고급 암호화 도구에 대한 도입 가능성이 있음

이번장에서는 현재 이더리움 암호 방식인 공개키 암호화(Public Key Cryptography, PKC)를 소개함

 

본론

키와 주소

이더리움의 두가지 계정 유형: 외부 소유 계정(Externally Owned Account, EOA)과 컨트랙트 계정(Contract)

디지털 개인키(private key), 이더리움 주소(Ethereum address), 디지털 서명(digital signature)을 통해 EOA의 이더 소유권 확립

계정 주소는 개인키에서 파생되며, 개인키는 계정(Account)라고 불리는 단일 이더리움 주소를 고유하게 결정

개인키를 사용하여 생성된 디지털 서명을 통해 자금의 접근과 통제가 이루어짐

공개키 암호화 기반 시스템에서 키는 개인키와 공개키로 구성된 쌍으로 제공됨

 

공개키 암호화와 암호화폐

공개키 암호화

1970년대 마틴 헬먼(Matin Hellman), 휫필드 디피(Whitfield Diffie), 랄프 머클(Ralph Merkle)에 의해 공개키 암호화 기법이 처음 공개됨

공개키 암호화는 연산은 쉽지만 역(reverse)연산은 어렵다는 수학 함수의 특성에 기반함

예를 들어 2개의 큰 소수를 곱하는 것은 쉽지만, 그 곱한 값의 소인수를 찾는 문제는 어려움 (8,018,009라는 수의 소인수를 찾고자 했을 때 소인수 중 하나를 2,003이라고 하면 나머지 소인수를 쉽게 찾을 수 있음)

이처럼 정보가 없으면 역연산이 어려운 함수를 트랩 도어 함수(trapdoor function)이라고 함

 

타원 곡선 암호화

암호화에 좀더 발전된 범주는 타원 곡선 산술 연산이 바탕이 됨

타원 곡선 산술은 곱은 간단하지만 나눗셈은 사실상 불가능함

이를 이산 로그 문제라고 하는데 연산을 효율적으로 가능하게 하는 트랩 도어가 발견되지 않음

타원 곡선 암호화(Elliptic curve cryptography)는 개인키와 디지털 서명의 기초가 됨

타원 곡선 수학이란 디지털 서명, 트랜잭션 세부 정보, 접근하려는 이더리움 주소가 일치하는지 확인하여 '누구나' 트랜잭션이 유효한지 확인할 수 있음을 의미

 

개인키

개인키는 무작위로 선택한 숫자

개인키는 해당 주소를 승인하는 컨트랙트에 대한 접근과 이더리움 주소와 관련된 모든 자금에 대한 사용자 제어의 근원

난수로 개인키 생성

키를 생성하는데 가장 중요한 것은 엔트로피, 즉 무작위성을 확보하는 것

개인키는 2^256보다 약간 작은 0이 아닌 숫자 (거대한 78자리 숫자 대략, 1.158 * 10^77)

일반적으로 Keccak-256 또는 SHA-256 같은 256비트 해시 알고리즘을 사용

개인키 생성 프로세스는 오프라인 프로세스이며, 어떠한 외부와의 통신을 요구하지 않음

같은 번호를 찾을 수 없도록 안전한 난수 생성기를 사용해야함

 

공개키

이더리움 공개키는 타원 곡선에 있는 점(point)으로 타원 곡선 방정식을 만족하는 x와 y좌표 집합을 의미

공개키는 비가역적 타원 곡선 곱셈을 사용하여 개인키로부터 계산됨

K = k * G (k: 개인키, G: 생성자 점(generator point), K: 공개키)

"*" 은 곱 연산이지만 일반적인 곱셈과 다른 스칼라 곱셈을 의미 

단순히 생각하면 생성자 점 G에 정수 k를 곱하여 K라는 점을 찾는 것

 

타원 곡선 암호화 설명

이더리움은 비트코인과 같은 secp256k1이라는 타원곡선을 사용

y^2 mod p = (x^3 + 7) mod p

p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1

타원 곡선은 실수 대신 소수 위수의 유한체 상에 정의되어 시각화하기 어려움

 

타원 곡선 산술 연산

타원 곡선 수학은 정수 산술과 비슷하나 연산의 결과는 선을 따라 이동하는 대신 곡선 상의 다른 점으로 이동함

기하학적으로 한 점 P1과 P2를 지나는 선을 그리면 이 선은 곡선과 마주치게 되는데 곡선과 만나는 이 점이 P1 + P2의 결과값인 P3가 됨

P1과 P2가 같은 점이면 접선으로 확장하여 P3를 찾을 수 있음

x값이 동일하고 y값의 부호만 반대인 경우 P3는 타원 곡선 상에 나타날 수 없는데 이경우 P3는 무한대로 표현

만일 P1이 무한대 점이면 P2와의 합 P3는 P2가 됨

점의 합은 결합성이 있으므로 (A + B) + C = A + (B + C)와 같음

덧셈이 정의되었으므로 이를 곱으로 표현할 수 있고 k * P = P + P + ... + P (k번 반복)으로 나타낼 수 있음

 

공개키 생성

무작위로 생성한 숫자 k 형태의 개인키로 시작하여 생성자 점(generate point) G라고 하는 곡선 상의 결정된 점에 개인키를 곱하여 공개키 K를 생성

K = k * G

생성자 점은 secp256K1 표준의 일부로 지정되어 있음

k와 K의 관계는 고정되어 있지만 공개키 K를 역산하여 개인키 k를 찾을 수 없음

이더리움에서는 16진수 문자(65바이트) 130개의 시리얼라이제이션(serialization)으로 표시되는 공개키를 확인할 수 있음

ex) 04 + x 좌표(32바이트/64(16진수)) + y 좌표(32바이트/64(16진수))

접두어 의미 길이(접두어 바이트 수)
0x00 무한대 1
0x04 압축되지 않은 지점 65
0x02 짝수 y의 압축된 점 33
0x03 홀수 y의 압축된 점 33

타원 곡선 라이브러리

OpenSSL

libsecp256k1

 

암호화 해시 함수

이더리움 공개키를 주소로 변환하는 작업에서 암호화 해시 함수가 사용됨

데이터 확인에 도움이 되는 디지털 지문(digital fingerprints)을 만드는 데 사용함

해시 함수(hash function)는 임의 크기의 데이터를 고정된 크기의 데이터로 매핑하는데 사용할 수 있는 모든 함수를 의미

해시 함수의 입력을 사전 이미지(pre-image), 메시지(message), 입력 데이터(input data)라고 하며, 결과값이 해시(hash)임

암호 해시 함수는 임의 크기의 데이터를 고정 크기의 비트열로 매핑하는 단방향 해시 함수임

다른 입력으로 같은 해시값이 나오는 경우를 해시 충돌이라고 하는데 좋은 해시 함수일수록 해시 충돌이 덜 발생함

 

해시 함수 속성의 활용

해시 충돌에 대한 저항은 이더리움에서 디지털 서명 위조를 피하기 위해 중요

데이터 핑거프린팅, 메시지 무결성(오류 감지), 작업증명, 인증(암호 해싱 및 키 스트래칭), 의사 난수 생성기, 메시지 커밋(커밋-공개 매커니즘), 고유 식별자

 

이더리움의 암호화 해시 함수: Keccak-256

Keccak-256 함수는 SHA-3 표준화를 위한 후보로 설계되었으며, 미국 표준기술연구소(NIST)에서 일부 파라미터를 조정하여 효율성을 향상했다고 주장

스노든의 내부고발로 파라미터의 조정은 난수 생성기 표준을 의도적으로 약화시켜 백도어를 배치했다는 것으로 밝혀짐에 따라 SHA-3가 아닌 기존의 Keccak-256을 그대로 사용하게 됨

 

어떤 해시 함수를 사용하고 있는가?

Keccak-256을 사용하고 있음에도 SHA-3라고 표시되는 경우가 있으므로 빈 문자열을 입력하여 그 결과값을 확인하여 실제 어떤 함수를 사용하고 있는지 확인이 가능

https://emn178.github.io/online-tools/keccak_256.html

Keccak256("") = c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
SHA3("") = a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a

 

이더리움 주소

이더리움 주소는 Keccak-256 단방향 해시 함수를 사용하는 공개키 또는 컨트랙트에서 파생한 고유 식별자(unique identifier)

개인키에서 공개키를 생성하고, 공개키는 Keccak-256으로 해시값을 구하게 됨

해시값의 마지막 20바이트만 유지하여 이를 주소로 사용 (때때로 0x를 접두어로 붙여 표기되기도 함)

 

이더리움 주소 형식

비트코인에서는 사용자 인터페이스에 내장된 체크섬을 포함하여 잘못 입력된 주소를 보호하도록 인코딩 되어 있으나 이더리움 주소는 따로 체크섬이 없음

이더리움은 이름 서비스를 통해 주소가 숨겨질 것으로 보고 이를 이름 서비스 등의 상위 계층에서 추가하고자 하였으나 생각보다 서비스가 느리게 개발됨에 따라 인코딩 방법을 고민하기 시작했음

 

대문자로 16진수 인코딩된 체크섬 (EIP-55)

EIP-55는 16진수 주소의 대소문자를 수정하여 이더리움 주소에 대해 이전 버전과 호환되는 체크섬을 제공

EIP-55를 지원하지 않는 지갑은 대소문자를 혼용하고 이에 대한 구분을 무시하기 때문에 문제가 없으며, 지원하는 경우 체크섬을 이용하여 주소의 오류여부를 99.986% 정확도로 감지할 수 있음

 

EIP-55 구현방법

0x 접두어 없이 소문자 주소를 해시 처리

해시의 해당 16진수가 0x8 이상인 경우 각 알파벳 문자를 대문자로 변환

Address의 네번째 d와 해시의 네번째 6을 확인해보면 해시의 네번째 값인 6은 8보다 작기때문에 d는 소문자로 남아 있게 됨

Address의 여섯번째 f와 해시의 여섯번째 c는 8보다 크기 때문에 소문자 f를 대문자 F로 변환함

이렇게 주소의 모든 문자를 같은 자리 해시와 비교하여 대문자로 변경할 수 있는 값을 대문자로 변환

Address: 001d3f1ef827552ae1114027bd3ecf1f086ba0f9
Hash   : 23a69c1653e4ebbb619b0b2cb8a9bad49892a9b9...

EIP-55로 인코딩된 주소의 오류 감지

0x001d3F1ef827552Ae1114027BD3ECF1f086bA0F9 주소가 뒤에서 두번째 글자인 F를 E로 잘못 읽어서 0x001d3F1ef827552Ae1114027BD3ECF1f086bA0E9로 인지하게 된 경우

EIP-55의 방식에 따라 0x001d3F1ef827552Ae1114027BD3ECF1f086bA0E9 의 0x를 제거하고 대문자를 소문자로 변환한 후 Keccak-256함수로 해시를 계산

Keccak256("001d3f1ef827552ae1114027bd3ecf1f086ba0e9" ) = 
5429b5d9460122fb4b11af9cb88b7bb76d8928862e0a57d46dd18dd8eO8a6927

 

앞서 구현방식에 따라서 대문자로 변환하는 과정을 진행

Address: 001d3f1ef827552ae1114027bd3ecf1f086ba0e9
Hash   : 5429b5d9460122fb4b11af9cb88b7bb76d8928862e0a57d46dd18dd8eO8a6927

주소의 앞에서 네번째 글자인 d와 해시의 네번째 글자인 9를 확인하였을 때, 9는 8이상이기 때문에 주소의 네번째 글자 d는 대문자이어야 하는데 실제로는 소문자로 전달되었으므로 정상적이지 않은 주소임을 알수 있음

결론

공개키 암호화를 간략히 확인하였으며, 이더리움에서의 공개키, 개인키 사용과 해시 함수 같은 암호화 도구를 사용하여 이더리움 주소를 만들고 검증함

디지털 서명과 개인키를 공개하지 않고 개인키의 소유권을 입증할 수 있는 방법에 대해서 확인

'Blockchain > Ethereum' 카테고리의 다른 글

Decoding Input Data using Ethereum ABI in Rust  (0) 2021.11.21