토요일, 3월 26, 2022

[B급 프로그래머] 이더리움 지갑 주소를 제대로 검증하려면?

어쩌다 보니 이더리움 지갑 주소를 검증할 일이 생겼다. 이더리움 주소는 보통 "0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9"처럼 0x 뒤에 40자의 16진수가 붙으면 되므로 정규 표현식으로 쉽게 표현이 가능할 듯이 보인다. 그러면 다음과 같은 파이썬 코드 한 줄이면 끝이다.

if re.match(r'^(0x)?[0-9a-f]{40}$', address, flags=re.IGNORECASE):
    return True
else:
    return False

그러면 여기서 한 가지 의문이 생길 수 있다. 주민등록번호, ISBN, 신용카드처럼 혹시 체크썸은 없을까? 위 코드는 정말 verification만 수행한 로직이지 실제 validation은 빠진 상황이므로 실수나 해킹 등으로 주소를 살짝 변경한 상황에 대응하기가 무척 어려워보인다.

정답부터 이야기하지만 초기 이더리움 지갑 주소를 만들 때는 체크썸이 없었지만 나중에 문제점을 인식하고 EIP-55로 체크썸을 추가하게 된다. 따라서 완벽하게 동작하는 이더리움 지갑 주소 검증 프로그램은 EIP-55에 따라 만들어야 한다.

EIP-55의 동작 원리는 무엇일까? 40자를 그대로 둔 상태에서 체크썸을 넣어야 하므로 일반적인 방법으로는 쉽지 않아 보인다. 그래서 해당 주소에 대해 Keccak256 해시를 구해서 16진수로 변경해 해시의 첫 20바이트(즉 40자)를 체크썸으로 사용하는 방법을 택한다.

Address: 001d3f1ef827552ae1114027bd3ecf1f086ba0f9
Hash   : 23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9...

여기서 Address의 알파벳 글자를 만나면 대응하는 자리의 Hash 값을 읽어서 8보다 더 큰 경우에 대문자로 바꾸는 방법을 사용한다. 결과는 다음과 같이 될 것이다.

Address: 001d3F1ef827552Ae1114027BD3ECF1f086bA0F9
Hash   : 23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9...

해시값은 원 주소에서 조금만 바뀌어도 크게 흔들리게 되므로, 이런 성질을 이용해서 특정 알파벳 글자의 대소문자가 제대로 되었는지를 확인하면 끝난다. 예를 들어, 앞에서 누군가 실수로 마지막 F를 E로 잘못 전달했다면 다음과 같이 알파벳 대소문자 규칙이 깨질 것이다.

001d3F1ef827552Ae1114027BD3ECF1f086bA0E9
5429b5d9460122fb4b11af9cb88b7bb76d892886...

흥미로운가? EIP-55가 나온 배경은 EIP55: Why It’s Important, What It Is, and Why We’re Talking About It Now를 참고하고, 더 자세한 설명은 오랄리에서 출간한 Mastering Ethereum의 4장을 참고하기 바란다.

EOB

댓글 없음:

댓글 쓰기