일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- ethers websocket
- 스마트컨트렉트테스트
- 깃허브명령어
- 스마트컨트렉트 함수이름 중복 호출
- 컨트렉트 배포 자동화
- 스마트컨트렉트프록시
- ethers type
- ethers v6
- nest.js설명
- nestjs 튜토리얼
- multicall
- ambiguous function description
- ethers typescript
- 러스트 기초 학습
- ethers
- 스마트 컨트렉트 함수이름 중복
- 프록시배포구조
- git rebase
- SBT표준
- vue기초
- 러스트 기초
- rust 기초
- 컨트렉트 동일한 함수이름 호출
- chainlink 설명
- 러스트기초
- 체인의정석
- 스마트컨트렉트 예약어 함수이름 중복
- Vue.js
- Vue
- 머신러닝기초
Archives
- Today
- Total
체인의정석
이더리움에서 데이터 서명관련 EIP 정리 (EIP1271 & EIP2098) 본문
728x90
반응형
호출 부분
/**
* @dev Internal view function to verify the signature of an order. An
* ERC-1271 fallback will be attempted if either the signature length
* is not 32 or 33 bytes or if the recovered signer does not match the
* supplied offerer. Note that in cases where a 32 or 33 byte signature
* is supplied, only standard ECDSA signatures that recover to a
* non-zero address are supported.
*
* @param offerer The offerer for the order.
* @param orderHash The order hash.
* @param signature A signature from the offerer indicating that the order
* has been approved.
*/
function _verifySignature(
address offerer,
bytes32 orderHash,
bytes memory signature
) internal view {
// Skip signature verification if the offerer is the caller.
if (offerer == msg.sender) {
return;
}
// Derive EIP-712 digest using the domain separator and the order hash.
bytes32 digest = _deriveEIP712Digest(_domainSeparator(), orderHash);
// Ensure that the signature for the digest is valid for the offerer.
_assertValidSignature(offerer, digest, signature);
}
Derive EIP712 => domainSeparator() 를 통해 구분 지으며, orderHash와 같이 서명하여 서명에 대한 구분 진행
/**
* @dev Internal pure function to efficiently derive an digest to sign for
* an order in accordance with EIP-712.
*
* @param domainSeparator The domain separator.
* @param orderHash The order hash.
*
* @return value The hash.
*/
function _deriveEIP712Digest(bytes32 domainSeparator, bytes32 orderHash)
internal
pure
returns (bytes32 value)
{
// Leverage scratch space to perform an efficient hash.
assembly {
// Place the EIP-712 prefix at the start of scratch space.
mstore(0, EIP_712_PREFIX)
// Place the domain separator in the next region of scratch space.
mstore(EIP712_DomainSeparator_offset, domainSeparator)
// Place the order hash in scratch space, spilling into the first
// two bytes of the free memory pointer — this should never be set
// as memory cannot be expanded to that size, and will be zeroed out
// after the hash is performed.
mstore(EIP712_OrderHash_offset, orderHash)
// Hash the relevant region (65 bytes).
value := keccak256(0, EIP712_DigestPayload_size)
// Clear out the dirtied bits in the memory pointer.
mstore(EIP712_OrderHash_offset, 0)
}
}
1. 컨트렉트 대상인 경우
signer.code.length > 0
스마트 컨트렉트 지갑인 경우 EIP1271
EIP1271은 스마트컨트렉트 형태의 지갑 주소에 대한 서명이 유효한지 검증해 주는 컨트렉트이다.
/**
* @dev Internal view function to verify the signature of an order using
* ERC-1271 (i.e. contract signatures via `isValidSignature`).
*
* @param signer The signer for the order.
* @param digest The signature digest, derived from the domain separator
* and the order hash.
* @param signature A signature (or other data) used to validate the digest.
*/
function _assertValidEIP1271Signature(
address signer,
bytes32 digest,
bytes memory signature
) internal view {
if (
EIP1271Interface(signer).isValidSignature(digest, signature) !=
EIP1271Interface.isValidSignature.selector
) {
revert InvalidSigner();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
interface ERC20ApprovalInterface {
function approve(address, uint256) external returns (bool);
}
interface NFTApprovalInterface {
function setApprovalForAll(address, bool) external;
}
contract EIP1271Wallet {
bytes4 private constant _EIP_1271_MAGIC_VALUE = 0x1626ba7e;
address public immutable owner;
bool public showRevertMessage;
mapping(bytes32 => bool) public digestApproved;
bool public isValid;
constructor(address _owner) {
owner = _owner;
showRevertMessage = true;
isValid = true;
}
function setValid(bool valid) external {
isValid = valid;
}
function revertWithMessage(bool showMessage) external {
showRevertMessage = showMessage;
}
function registerDigest(bytes32 digest, bool approved) external {
digestApproved[digest] = approved;
}
function approveERC20(
ERC20ApprovalInterface token,
address operator,
uint256 amount
) external {
if (msg.sender != owner) {
revert("Only owner");
}
token.approve(operator, amount);
}
function approveNFT(NFTApprovalInterface token, address operator) external {
if (msg.sender != owner) {
revert("Only owner");
}
token.setApprovalForAll(operator, true);
}
function isValidSignature(bytes32 digest, bytes memory signature)
external
view
returns (bytes4)
{
if (digestApproved[digest]) {
return _EIP_1271_MAGIC_VALUE;
}
// NOTE: this is obviously not secure, do not use outside of testing.
if (signature.length == 64) {
// All signatures of length 64 are OK as long as valid is true
return isValid ? _EIP_1271_MAGIC_VALUE : bytes4(0xffffffff);
}
if (signature.length != 65) {
revert();
}
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
if (
uint256(s) >
0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
) {
revert();
}
if (v != 27 && v != 28) {
revert();
}
address signer = ecrecover(digest, v, r, s);
if (signer == address(0)) {
revert();
}
if (signer != owner) {
if (showRevertMessage) {
revert("BAD SIGNER");
}
revert();
}
return isValid ? _EIP_1271_MAGIC_VALUE : bytes4(0xffffffff);
}
}
2. EIP 2098 서명
signature.length == 64
서명 코드
// If signature contains 64 bytes, parse as EIP-2098 signature. (r+s&v)
// Declare temporary vs that will be decomposed into s and v.
bytes32 vs;
(r, vs) = abi.decode(signature, (bytes32, bytes32));
s = vs & EIP2098_allButHighestBitMask;
v = uint8(uint256(vs >> 255)) + 27;
// Signature-related
bytes32 constant EIP2098_allButHighestBitMask = (
0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
);
EIP 2098 설명
secp256k1 곡선은 서명과 결합될 때 서명된 다이제스트의 공개 키 계산을 허용하며, 이는 메타 트랜잭션 및 다중 서명 계약과 같은 EVM 계약의 온체인뿐만 아니라 외부 소유 계정에서 트랜잭션의 원점을 설정하는 데 암묵적으로 사용된다.
현재 시그니처는 표현하기 위해 65바이트가 필요하며, 256비트 워드에 정렬될 경우 96바이트가 필요하다. 또한 RLP 인코딩 트랜잭션의 yParity에는 (평균) 1.5바이트가 필요합니다. 콤팩트 서명의 경우 64바이트로 줄일 수 있으며, 워드 정렬 시 64바이트로 유지되며, RLP 인코딩 트랜잭션의 경우 yParity에 필요한 1.5바이트를 절약할 수 있다.
=> 65 바이트 인 경우 일반적인 서명이며.
=> 64 바이트 인 경우 콤팩트 서명이다. 워드 정렬을 한 서명이다.
일반 EOA 주소로 이루어진 서명이 여기에 해당된다.
728x90
반응형
'블록체인 > Solidity' 카테고리의 다른 글
Solidity constants vs immutable 차이 (0) | 2022.07.06 |
---|---|
Solidity 코드 분리하기 , 분리하며 나오는 Contract should be marked as abstract 에러 해결 (0) | 2022.07.06 |
Internal compiler error: Accessors for mapping with dynamically-sized keys not yet implemented 오류 해결 (0) | 2022.06.22 |
web3.utils.soliditySha3 와 ethers.utils.solidityKeccak256 (0) | 2022.06.22 |
기존 소스를 실행 시킬 경우 오래된 오픈 제플린 코드 버전 맞추기 (0) | 2022.06.22 |
Comments