오프체인 서명 검증(Off-chain Signature Verification)이란?

개요 블록체인 기술에서 모든 것을 온체인(On-chain)으로 처리하는 것은 비효율적이거나 불가능한 경우가 많음 이때 오프체인 서명 검증(Off-chain Signature Verification)은 오프체인(서버)의 유연성과 온체인(컨트랙트)의 신뢰성을 결합하는 강력한 해결책이 됨 쉽게 비유하자면, 클럽 매니저(서버)가 VIP 손님(사용자)에게만 특별한 싸인이 담긴 입장권(서명)을 발급하고, 입구의 가드(스마트 컨트랙트)는 그 싸인만 확인하고 들여보내는 것과 같음 가드는 매번 매니저에게 연락할 필요 없이, 위조되지 않은 싸인인지 확인만 하면 됨 이 글에서는 오프체인 서명 검증이 무엇인지, 어떤 용어들이 사용되는지, 그리고 가장 중요하게는 어떤 원리로 동작하는지 상세히 알아봄 ...

September 21, 2025

안전한 가스비 대납을 위한 오프체인 서명 검증 페이마스터 (in ZkSync Era)

개요 블록체인 서비스에서 사용자가 겪는 가장 큰 장벽 중 하나는 단연 가스비(Gas Fee)임 아무리 좋은 서비스를 만들어도, 사용자가 지갑에 가스비로 쓸 코인(ETH 등)을 보유하고 있어야 한다는 점은 대중화를 가로막는 결정적인 요인임 이 문제를 해결해 사용자가 가스비 걱정 없이 서비스 핵심 가치에만 집중하게 만드는 것, 즉 가스리스 트랜잭션(Gasless Transaction)을 구현하는 것이 이번 개발의 최종 목표였음 zkSync Era는 이를 위해 페이마스터(Paymaster)라는 강력한 시스템을 제공함. 페이마스터는 서비스 제공자 같은 제3자가 사용자를 대신해 트랜잭션 수수료를 지불할 수 있게 해주는 스마트 컨트랙트임 ...

September 21, 2025

EIP-712 기반 signTypedData 가이드와 지갑 연동 핵심

개요 signTypedData는 EIP-712 표준을 구현한 서명 메서드로 구조화된 데이터에 서명하기 위한 표준 인터페이스를 제공함 지갑은 사람이 읽을 수 있는 형태로 서명 내용을 표시하고, 서명은 특정 도메인과 체인에 귀속되어 재사용 공격을 줄임 signTypedData와 EIP-712의 관계 정의 signTypedData는 EIP-712 규격을 따르는 구조화 데이터 서명 메서드 이더리움 지갑 및 제공자에서 eth_signTypedData, eth_signTypedData_v3, eth_signTypedData_v4 형태로 노출 버전 signTypedData 최초 버전 signTypedData_v3 signTypedData_v4 가장 널리 사용되는 최신 버전 라이브러리 사용 ethers에서는 _signTypedData로 제공 const signature = await signer._signTypedData(domain, types, value) 지갑 연동은 일반적으로 provider에 직접 요청하는 방식 사용 const signature = await ethereum.request({ method: 'eth_signTypedData_v4', params: [account, JSON.stringify({ domain, types, message: value })], })동작 원리 요약 타입화된 구조체 정의 예시 구조체와 필드 타입을 정형화해 명세 도메인 분리자 사용 이름, 버전, 체인 ID, 검증 컨트랙트 주소를 포함해 서명 범위 고정 타입 해시와 데이터 해시 생성 타입 정의를 keccak256으로 해싱 후 데이터 인코딩 해시 생성 최종 해시에 서명 및 검증 지갑에서 서명 생성, 컨트랙트에서 도메인과 타입을 동일하게 재현해 검증 사용 예시 간단한 도메인, 타입, 메시지 구성 예시 const domain = { name: 'MyApp', version: '1', chainId, verifyingContract } const types = { Action: [ { name: 'user', type: 'address' }, { name: 'amount', type: 'uint256' } ] } const value = { user: userAddress, amount } // ethers 서명 const sig = await signer._signTypedData(domain, types, value) // 지갑 요청 v4 서명 const sig2 = await ethereum.request({ method: 'eth_signTypedData_v4', params: [account, JSON.stringify({ domain, types, message: value })], }) 컨트랙트 검증 예시 요약 // OpenZeppelin EIP712, ECDSA 사용 가정 bytes32 digest = _hashTypedDataV4( keccak256(abi.encode( keccak256("Action(address user,uint256 amount)"), user, amount )) ) require(ECDSA.recover(digest, signature) == signer, "Invalid signature")EIP-712 핵심 개념 정리 목적 사람이 읽을 수 있는 서명 메시지 제공 도메인에 귀속된 서명으로 리플레이 공격 저감 구조 타입화된 데이터 스키마와 도메인 분리자 타입 해시와 데이터 해시를 조합한 최종 해시 장점 지갑 UI에서 의미 있는 정보 노출로 UX 개선 다른 dApp이나 체인에서 재사용 어려움으로 보안 강화 주의사항과 팁 v4 사용 권장 v4는 가장 널리 지원되고 구조체 및 배열 표현이 안정적임 provider 요청 방식 web3 라이브러리 함수보다 ethereum.request의 eth_signTypedData_v4 사용이 호환성 측면에서 안전함 타입 정의 일치 컨트랙트와 클라이언트의 타입 이름, 필드 순서, 정수 크기 등 완전 일치 필요 도메인 정합성 chainId와 verifyingContract가 실제 네트워크와 배포 주소와 일치해야 검증 성공 데이터 인코딩 JS 측 정수값은 문자열 또는 BigNumber 형태 사용 권장, 오버플로와 반올림 이슈 회피 ethers 사용 시 types에 EIP712Domain을 포함하지 않음, _signTypedData가 도메인을 별도로 처리함 v4 메시지 포맷 params에 JSON.stringify로 { domain, types, message } 형태 전달 필요 마무리 signTypedData는 곧 EIP-712 사용을 의미하며 구조화된 데이터에 대한 안전한 서명을 가능하게 함 ethers의 _signTypedData 또는 지갑의 eth_signTypedData_v4를 사용해 서명하고, 컨트랙트에서는 동일한 도메인과 타입으로 해시를 재현해 검증하면 됨 명세 일치와 도메인 정합성만 확보하면 안전하고 예측 가능한 서명 흐름을 구현 가능 ...

December 20, 2025