BitmaskVerifier
Purpose​
The BitmaskVerifier is a customizable, low-level verifier module that enables selective call authorization using bitmask-based hashing. It allows a contract to validate whether a function call (defined by who, where, value, and data) conforms to a pre authorized pattern.
It supports:
- Partial matching of calldata.
- Exact or wildcard matching on sender, target, or ETH value.
- Highly gas efficient verification with minimal storage.
Core Concept: Bitmask Based Hashing​
The BitmaskVerifier computes a hash over masked components of a transaction and compares it to a stored or expected hash.
The verification succeeds if:
calculateHash(bitmask, who, where, value, data) == expectedHash
Bitmask Format​
The bitmask is a byte array with the following structure:
| Segment | Bytes | Targeted Field | Description |
|---|---|---|---|
| [0:32] | 32 bytes | who | Mask for the caller address (left padded to 32 bytes) |
| [32:64] | 32 bytes | where | Mask for the target contract address (left padded to 32 bytes) |
| [64:96] | 32 bytes | value | Mask for ETH value (uint256) |
| [96:] | data.length | data | One byte per calldata byte; used to mask calldata selectively |
This structure allows the verifier to:
- Fully match addresses and value.
- Partially match calldata (for example permit
approve(x, anyAmount)).
Function: calculateHash​
function calculateHash(
bytes calldata bitmask,
address who,
address where,
uint256 value,
bytes calldata data
) public pure returns (bytes32)
Logic​
This function computes a keccak256 hash over the masked versions of each input field:
who, masked bybitmask[0:32]where, masked bybitmask[32:64]value, masked bybitmask[64:96]- Each
data[i]masked bybitmask[96+i]
Example Use​
If a bitmask has 0xff for a given byte, that byte is strictly matched. If 0x00, the byte is ignored (wildcarded). Mixed values allow partial matching.
Function: verifyCall​
function verifyCall(
address who,
address where,
uint256 value,
bytes calldata data,
bytes calldata verificationData
) public pure returns (bool)
Input: verificationData​
This input must be ABI encoded as:
abi.encode(bytes32 expectedHash, bytes bitmask)
Logic​
- Parses
expectedHashandbitmaskfrom the calldata. - Verifies that the bitmask length matches
96 + data.length. The 96 bytes cover 32 forwho, 32 forwhere, 32 forvalue, and one byte per calldata byte. - Calls
calculateHash()and compares it toexpectedHash.
Returns:
trueif the masked call hash matches the expected hash.falseotherwise.
Use Cases​
This verifier enables granular control over contract interactions, for example:
- Approvals to a specific contract: Allow
approve(farmContract, anyAmount)but block other approvals. - Partial calldata authorization: Authorize only the first 4 bytes (function selector) of a call.
- Curated access for specific addresses: Allow only specific curators to call
delegate(address)with known targets. - Value bound actions: Authorize only zero ETH transactions or enforce a cap on
value.