ecrecover는 32바이트 다이제스트(digest)와 v·r·s 값으로 이더리움 주소를 복구할 뿐, 그 서명이 누구의 어떤 행위를 어느 체인·계약에서 승인했는지는 판단하지 않습니다. EIP-2는 거래 서명에서 큰 s 값(high-s)을 무효로 만들었지만, ecrecover 사전 컴파일 계약(precompile)은 과거 서명과의 호환을 위해 큰 s 값도 계속 받아 줍니다. 그래서 계약은 s가 secp256k1 위수의 절반 이하인지, v가 허용된 형식인지, 복구된 주소가 제로 주소가 아닌지를 확인해야 합니다. 여기에 EIP-191·712 접두사, chainId, 검증 계약, 행위 매개변수, 논스와 기한을 다이제스트에 묶어 재사용(replay) 범위를 좁혀야 합니다.
같은 의미의 ECDSA 서명이 두 개일 수 있습니다
secp256k1 ECDSA에서는 유효한 (r,s)에 대해 (r,n-s)와 반대 복구 패리티 조합도 같은 공개키를 복구할 수 있습니다. 서명 바이트가 서로 다르므로 서명 해시를 고유 키로 쓰거나 ‘이 바이트는 아직 쓰지 않았다’는 매핑으로 막는 방식은 우회될 수 있습니다. 재사용을 막는 핵심 키는 메시지 논스와 서명자여야 합니다.
EIP-2의 홈스테드 규칙은 이더리움 거래에서 s가 n/2보다 크면 무효로 처리하게 했지만, ecrecover 사전 컴파일 계약은 바꾸지 않았습니다. 옛 비트코인 서명 같은 용도를 살려 두기 위해서입니다. 따라서 지갑이 늘 정규 서명을 만든다고 가정하지 말고 계약 경계에서 작은 s 값(low-s)인지 검사합니다.
ecrecover는 암호학적 복구 함수이지 승인 정책 함수가 아닙니다. 복구된 주소 앞뒤의 메시지 문맥은 계약이 직접 검증해야 합니다.
JOBCOIN 해설

그림은 이 주제의 공통 개념을 단순화한 설명입니다. 아래 항목에서 이 글의 구체적인 조건과 예외를 함께 읽어보세요.
- 같은 의미의 ECDSA 서명이 두 개일 수 있습니다
secp256k1 ECDSA에서는 유효한 (r,s)에 대해 (r,n-s)와 반대 복구 패리티 조합도 같은 공개키를 복구할 수 있습니다.
- v·r·s와 실패 결과를 모두 검증합니다
솔리디티의 ecrecover는 오류가 나면 address(0)를 돌려줍니다.
- 퍼밋 예제로 다이제스트 범위를 점검합니다
소유자가 지출자에게 토큰 100개의 사용 한도(allowance)를 주는 체인 밖 서명을 만든다고 해 보겠습니다.
설명을 위한 개념도 · 실제 가격·거래 내역·통계가 아닙니다.
v·r·s와 실패 결과를 모두 검증합니다
솔리디티의 ecrecover는 오류가 나면 address(0)를 돌려줍니다. 제로 주소가 역할 매핑에서 허용되거나 서명자 입력값과 우연히 같아지는 로직이라면 실패가 승인으로 바뀔 수 있으므로 recovered != address(0)부터 확인합니다. r·s 범위와 s의 하위 절반 조건, 그리고 v가 27·28인지 아니면 라이브러리가 0·1로 정규화하는지 명시합니다.
EIP-2098 압축 서명처럼 패리티가 s의 최상위 비트에 들어가는 형식도 있으므로 64바이트용과 65바이트용 해석기를 섞어 쓰지 않습니다. 거래의 EIP-155 v 값과 메시지 서명의 v 값을 같은 방식으로 해석하면 체인 ID 계산식이 엉뚱하게 적용될 수 있습니다.
| 검사 | 막는 문제 | 누락 시 결과 |
|---|---|---|
| 작은 s 값·v 범위 | ECDSA의 가변 표현 | 다른 바이트로 재사용 |
| 제로 주소 | 복구 실패 | 실패를 서명자로 오인 |
| 도메인 접두사 | 다른 종류 서명의 혼용 | 거래와 메시지 혼동 |
| 체인·계약 | 다른 도메인에서의 재사용 | 다른 배포에서 재사용 |
| 논스·기한 | 시간·횟수 재사용 | 같은 승인 반복 실행 |
퍼밋 예제로 다이제스트 범위를 점검합니다
소유자가 지출자에게 토큰 100개의 사용 한도(allowance)를 주는 체인 밖 서명을 만든다고 해 보겠습니다. 다이제스트에는 owner, spender, value뿐 아니라 현재 논스와 기한, 도메인의 chainId와 verifyingContract가 들어가야 합니다. 계약은 복구된 서명자가 owner인지 확인하고 논스를 소비한 뒤 사용 한도를 갱신합니다.
금액만 서명하면 공격자가 그 서명을 다른 지출자나 계약에 붙여 쓸 수 있습니다. 논스를 넣었더라도 상태 값을 올리기 전에 토큰 훅 같은 외부 호출을 하면 재진입으로 같은 논스가 다시 쓰일 수 있습니다. 서명 검증, 논스 반영, 외부 상호작용의 순서를 하나의 상태 전이로 봅니다.
- 서명 방식과 접두사 바이트를 고정합니다.
- 타입 필드와 타입 해시를 시험 벡터로 검산합니다.
- s 하위 절반·v 형식·제로 주소를 검사합니다.
- 체인 ID·검증 계약·논스·기한을 포함합니다.
- 논스는 외부 호출 전에 소비하고 이벤트를 남깁니다.
EIP-191은 의도하지 않은 이더리움 거래 서명을 막습니다
EIP-191 서명 데이터는 0x19 뒤에 버전 바이트, 버전별 데이터, 본문을 잇는 구조를 씁니다. 맨 앞의 0x19는 서명 데이터가 유효한 RLP 이더리움 거래로 해석되지 않게 합니다. 버전 0은 의도한 검증자 주소를 넣고, 버전 0x45는 personal_sign 계열 접두사에 쓰입니다.
접두사가 있다고 해서 응용 도메인 구분이 충분해지지는 않습니다. 두 계약이 같은 본문과 검증자 규칙을 함께 쓰면 서명이 재사용될 수 있습니다. EIP-712 도메인 구분자나 프로토콜 고유 도메인을 쓰고, 프록시 업그레이드 때의 검증 계약 처리와 체인 분기 대응 정책을 문서로 남깁니다.
서명 바이트보다 승인 상태를 감사합니다
운영 기록에는 서명 원본 전체보다 서명자, 다이제스트, 논스, 행위, 거래 해시를 서로 연결해 남깁니다. 서명을 고유 ID로 쓰지 않고 메시지 다이제스트·서명자·논스의 소비 상태를 기준으로 중복 실행을 막습니다. 개인키나 공개되지 않은 승인 본문은 기록에 남기지 않습니다.
시험 벡터에는 정상적인 작은 s 값, 그에 대응하는 큰 s 값, 잘못된 v, 제로 주소 복구, 다른 체인 ID·계약, 기한 만료, 논스 재사용을 넣습니다. 화면에 보여 준 문구와 계약이 해시한 바이트가 같은지 독립 구현으로 비교해야 합니다.
자주 묻는 질문
이더리움 거래가 작은 s 값이면 계약 서명도 자동으로 작은 s 값인가요?
아닙니다. EIP-2의 거래 유효성 규칙과 ecrecover 사전 컴파일 계약의 입력 검사는 서로 다르므로 계약이 직접 확인해야 합니다.
ecrecover가 제로 주소를 돌려주면 서명자가 0인 건가요?
복구에 실패했을 수 있습니다. 유효한 서명자로 취급하지 말고 명시적으로 거부해야 합니다.
논스만 넣으면 재사용이 모두 막히나요?
같은 계약 안의 반복은 줄지만, 다른 체인·계약에서의 재사용을 막으려면 도메인도 다이제스트에 포함해야 합니다.
더 깊이 읽기
본문에서 다룬 개념과 확인 절차를 다음 글에서 이어서 살펴보세요.



