web3.py로 알아보는 이더리움의 서명확인
안녕하세요, 이더리움 코드보는 SigmoiD입니다.
오늘은 Web3를 이용하여 이더리움의 서명 예제를 작성해 봄으로서, 실제 서명이 어떤 역할을 하는지 알아보고자 합니다.
1. 테스트 시나리오
- 전송자가 전달하고자 하는 메시지를 하나 정합니다.
- 메시지의 요약본으로 사용할 메시지 해시를 생성합니다.
- 메시지 해시에 프라이빗키를 이용하여 서명합니다.
- 서명 결과와 메시지를 수신자에게 전송합니다.
- 수신자는 수신한 데이터 중 서명결과에 포함된 메시지 해시와, V, R, S 를 사용하여 서명자의 주소를 알아냅니다.
- 서명자의 주소와 전송자의 주소가 같은지 확인합니다.
- 수신한 데이터 중 메시지 부분의 해시를 계산합니다.
- 계산한 메시지 해시와 서명 결과에 포함된 메시지 해시가 같은지 검사합니다.
만약 8번까지 통과한다면, 이 메시지는 정말로 전송자가 보낸것이며(5,6), 위조되지 않았음(7,8)을 확인할 수 있습니다.
2. 구현
먼저 web3를 사용하여 python dapp을 작성하였습니다.
# 보내고 싶은 메시지를 정한다
msg = 'sigmoid'.encode('utf-8')
msg_hex = msg.hex()
# 메시지의 해시를 생성한다
msg_hash = defunct_hash_message(hexstr=msg_hex)
# 생성한 메시지 해시에 개인키로 서명
signed_result = w3.eth.account.signHash(msg_hash,private_key=private_key)
# {서명결과 + 메시지}를 broadcast한다
# 누군가 받았다고 가정하고..
# 서명자 확인 (3가지 방법으로)
# web3를 이용하여 recover
recovered1_addr = w3.eth.account.recoverHash(signed_result.messageHash, signature=signed_result.signature)
# local의 contract를 이용하여 recover
recovered2_addr = contract.functions.get_signer(signed_result.messageHash, signed_result.v, signed_result.r.to_bytes(32,'big'), signed_result.s.to_bytes(32,'big')).call()
# remote의 contract를 이용하여 recover
tx_hash = contract.functions.get_signer(signed_result.messageHash, signed_result.v, signed_result.r.to_bytes(32,'big'), signed_result.s.to_bytes(32,'big')).transact({'from': signer_addr, 'gas': 700000} )
# 트렌젝션이 블록에 포함될때까지 대기
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
# 영수증의 이벤트를 확인한다
result = contract.events.ReturnSigner().processReceipt(tx_receipt)
# 수신한 메시지의 해시를 계산한다
calc_message_hash = defunct_hash_message(hexstr=msg_hex)
# 수신한 메시지 해시와 계산한 메시지 해시를 비교하여 메시지 위조 확인가능
if signed_result.messageHash == calc_message_hash:
3. 출력결과
signer:0x39B7165b780Cce549c49D7C602CFf968596b885D
from Web3:0x39B7165b780Cce549c49D7C602CFf968596b885D
from local:0x39B7165b780Cce549c49D7C602CFf968596b885D
from remote:0x39B7165b780Cce549c49D7C602CFf968596b885D
message digest verified
4. 결과 되짚어보기
결국 서명이란 "이 메시지를 어떤 계정이 보냈다" 라는 증명입니다.
바꾸어 말하면 서명 정보를 통해 계정 주소를 재 생성하면 이 메시지는 해당 주소가 보낸것이 되는것이죠. 이러한 기능을 지원하기 위해 solidity, web3 모두, 메시지 해시와, V, R, S 서명값을 이용해 타원곡선상의 주소를 복구해주는 기능을 지원합니다.왜 메시지에 직접하지 않고, 해시에 서명을 하느냐, 메시지의 위변조 여부를 검증하기 적절하기 때문입니다. 전달된 메시지의 해시를 내가 계산해보고, 수신한 메시지의 해시와 비교해보는 과정에서 위변조 여부를 알수 있게되니다. 메시지가 위조되었다면, 서명된 해시와 내가 계산한 해시가 달라질테니까요.
모든 구현내용은 아래 링크에서 확인하실 수 있습니다.
https://github.com/NAKsir-melody/eth_verify_signature
이더리움 스터디에 조금이나마 도움이 되었으면 좋겠습니다.
감사합니다.