이더리움의 트랜잭션 서명에 대해서 알아보자

Jeong-hwan, Yun
5 min readFeb 1, 2019

--

트랜잭션 구조

https://medium.com/@codetractio/inside-an-ethereum-transaction-fa94ffca912f

이더리움의 트랜잭션은 위와 같은 구조를 가지고 있습니다. Nonce는 트랜잭션의 재실행 공격을 막기 위한 장치입니다. 트랜잭션의 nonce는 계정의 nonce와 같아야하고 트랜잭션이 처리될 때마다 계정의 nonce는 1씩 증가합니다. Value는 보내는 이더의 양입니다. Data는 컨트랙트에 전달될 데이터입니다. 이 글에서 나머지 v, r, s의 값에 대해서 알아보겠습니다.

타원곡선

타원곡선은 y²=x³+Ax+B 형태의 방정식입니다. 그래프로 그리면 이러한 형태가 나오게 됩니다.

https://prateekvjoshi.com/2015/02/07/why-are-they-called-elliptic-curves/
https://medium.com/@peterreid_12788/part-2-is-elliptic-curve-cryptography-ecc-a-step-towards-something-more-understanding-ecc-3c933d3922e

타원곡선에서 P+Q=R은 위와같은 방식으로 정의됩니다. P와 Q를 잇는 직선을 그었을 때 만나는 다른 한 점에서 x축을 기준으로 뒤집으면 R이 나오게 됩니다. 만약 P와 Q가 같은 점이라면 접선과 만나는 점을 x축을 기준으로 뒤집은 점이 R이 됩니다. 타원곡선에서의 덧셈은 교환법칙과 결합법칙을 만족합니다. 또한 Q=xG일 때 Q와 G를 알아도 x를 알아내는 것은 극도로 어렵습니다. 그렇기 때문에 x가 비밀키가 되고 Q가 공개키가 됩니다. G는 미리 정해져있습니다.

이러한 타원곡선을 나머지 연산을 통해서 유한체로 만들 수 있습니다.

https://bitcoin.stackexchange.com/questions/21907/what-does-the-curve-used-in-bitcoin-secp256k1-look-like

y²=x³+7 over F17의 그래프입니다. x가 2일 때 2³+7 mod 17 = 15이고 y가 7일 때 7² mod 17 = 15, 10일 때 10² mod 17 = 15이므로 위의 그래프가 그려진다는 것을 알 수 있습니다.

secp256k1

비트코인과 이더리움은 서명을 만들기 위해 secp256k1 표준을 사용합니다. 각각의 인자는 이곳에서 확인할 수 있습니다. secp256k1의 그래프는 y²=x³+7이고 이렇게 생겼습니다.

유한체로 만들기 위해서 32바이트에 가까운 소수인

p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F = 2256–232–29–28–27–26–24–1

로 나머지 연산을 하게 됩니다. 또한 G의 경우

x = 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798
y = 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8

인 점이 됩니다.

서명을 만들기 위해서 랜덤한 값 k를 생성합니다. 그리고 P=kG의 x값을 r이라고 합니다. s=(h(m)+xr)/k mod n를 계산합니다. h(m)은 트랜잭션을 해시한다는 뜻인데 이때 v, r, s는 알 수가 없으므로 제외하고 해시합니다. v는 P의 y값의 마지막 비트가 되고(0 또는 1) 거기서 27을 더합니다.

서명을 검증하는 쪽은 Q=r ⁻¹(sP−h(m)G)를 계산해서 공개키를 얻을 수 있습니다. (r ⁻¹은 mod의 역원입니다.) 하지만 여기서 검증하는 쪽은 P의 x값만을 알고 있는데 y²=x³+7의 그래프를 알고있으므로 r과 v를 참고해서 특정한 y값을 구할 수 있습니다.

(하지만 x값을 통해서 P를 구할 때 이론적으로는 점은 네가지의 경우의 수가 나올 수 있다고 합니다. 기본적으로 그래프가 대칭이므로 +-값의 y가 나오지만 추가적으로 두가지의 경우가 더 나올 수 있다고 합니다. 하지만 저는 이해를 못했기 때문에 궁금하시다면 더 찾아보시기 바랍니다. 참고1 참고2)

이렇게 해서 공개키를 얻을 수 있습니다. 트랜잭션에 보내는 주소가 따로 없는데 이렇게 해서 나온 공개키를 해시해서 20바이트로 자른 값이 보내는 주소가 됩니다.

마지막으로 chain id가 설정된 경우 v를 구할 때 27을 더하지 않고 2 * chainId + 35를 더하게 됩니다. 이더리움 클래식 하드포크 후 체인 간의 트랜잭션 재실행 공격을 막기 위해서 이러한 요소가 추가되었습니다. 참고

마무리

이더리움의 서명 방식에 대해 간략하게 알아보았습니다. 트랜잭션에 chain id가 없고 보내는 사람의 주소가 없다는 점이 특이해 보였는데 이번에 서명 부분을 공부하면서 의문이 해소되었습니다. 암호학에 대해서 전문적으로 설명하는 글은 아니였지만 이 글을 읽으시는 분들께서도 트랜잭션에 대해서 좀 더 이해가 높아지는 기회가 되셨다면 좋겠습니다.

--

--