트랜잭션
트랜잭션 T는 다음 data를 포함한다.
T = { nonce, gasPrice, gasLimit, to, value, data, v, r, s }
- nonce: 보내는 EOA(External Owned Account) 의 counter.
- 중간에 생략되면 생략된 nonce가 와서 유효하게 처리되기 전까지 이후의 nonce를 가지는 트랜잭션은 mempool에 저장되었다가 처리 후 유효하게 된다.
- gasPrice: 발신자가 보내는 가스의 가격. 단위는 wei.
- 0도 가능. 높을 수록 해당 트랜잭션이 빨리 처리됨.
- gasLimit: 이 트랜잭션을 위해 구입할 가스의 최대량
- 21000 gas. 이더 소비량 = 21000 * gasPrice
- to: 수신 이더리움 address (20 bytes)
- value: 수신처에 보낼 이더의 양
- data: 가변 길이 data payload
- to가 contract address라면, 4 bytes의
function selector
와 그 이후의function argument
를 serialize한 data이다.function selector = (keccak-256(function prototype))[0:4]
- to가 contract address라면, 4 bytes의
- v, r, s: EOA의 ECDSA 디지털 서명의 구성 요소
서명
서명 시 사용되는 트랜잭션 T는 9개 필드로 다음과 같다. 이 중 맨 끝의 3개 { chainID, 0, 0 }은 EIP-155에 의해 추가된다. EIP-155는 Simple Replay Attack Protection으로 chainID를 포함하여 다른 네트워크 체인에서 해당 트랜잭션이 replay될 수 없도록 한다.
T = { nonce, gasPrice, gasLimit, to, value, data, chainID, 0, 0 }
Sig는 서명으로 서명 알고리즘, F sig() 로 (r, s) 두 값이 output으로 만들어진다. Transaction T와 private key k를 사용한다. RLP는 Recursive Length Prefix (RLP) encoding scheme 을 말한다.
Sig = F sig(keccak256(RLP(T)), k) = (r, s)
서명 시에는 임시 private key q, 그리고 q로부터 생성되는 임시 public key Q 를 사용한다.
q = rand() % 2**256
Q = q * K = (x, y)
여기서 r = Q의 x 좌표이다. s는 다음으로 계산된다.
s ≡ q**-1 (Keccak-256(RLP(T)) + r * k) mod p
서명 검증
r, s 그리고 sender의 public key K를 사용해서 Q를 계산한다. Q의 x 좌표와 r이 같으면 서명이 유효하다.
w = s**-1 mod p
u1 = Keccak-256(RLP(T)) * w mod p
u2 = r * w mod p
Q ≡ u1 * G + u2 * K (mod p)
참고: https://github.com/ethereumbook/ethereumbook/blob/develop/06transactions.asciidoc
서명검증 w에 오타가 있네요.
w = s-1 mod p -> w = s ** -1 mod p
오! 그렇네요! 정말 감사합니다!