
Walkthrough: Huff Challenge #4
In this article, we are going to explore the solution to the Huff Challenge 4. You can find walkthroughs for other challenges below:Challenge #1Challenge #2Challenge #3Also if you are new to huff and wanna learn how to test and deploy Huff contracts, check out this article. Alright let’s dive in.The Problem Statement:In this challenge, we're tasked with writing a Huff smart contract that reverses the calldata that it receives. Essentially, if you send data to this contract, it should be ...

Testing and deploying Huff contracts
In this post, we will dive into the steps involved in testing and deploying a smart-contract written using the Huff programming language. For those who don’t know:Huff is a low-level programming language designed for developing highly optimized smart contracts that run on the Ethereum Virtual Machine (EVM). Huff does not hide the inner workings of the EVM and instead exposes its programming stack to the developer for manual manipulation. The Aztec Protocol team originally created Huff to writ...

Huff By Example
In this rapidly evolving landscape of blockchain technology, efficiency isn't just an advantage—it's a necessity. More the adoption is, the more congested the networks become (for now this is the case), hence the race for gas optimization intensifies, every opcode, every byte, and every operation counts. Enter Huff, a language so close to the metal of the Ethereum Virtual Machine (EVM) which has the potential to take on-chain possibilities to one step further. In this post, we’ll di...
EVM | DeFi | SmartContracts 🚀

Walkthrough: Huff Challenge #4
In this article, we are going to explore the solution to the Huff Challenge 4. You can find walkthroughs for other challenges below:Challenge #1Challenge #2Challenge #3Also if you are new to huff and wanna learn how to test and deploy Huff contracts, check out this article. Alright let’s dive in.The Problem Statement:In this challenge, we're tasked with writing a Huff smart contract that reverses the calldata that it receives. Essentially, if you send data to this contract, it should be ...

Testing and deploying Huff contracts
In this post, we will dive into the steps involved in testing and deploying a smart-contract written using the Huff programming language. For those who don’t know:Huff is a low-level programming language designed for developing highly optimized smart contracts that run on the Ethereum Virtual Machine (EVM). Huff does not hide the inner workings of the EVM and instead exposes its programming stack to the developer for manual manipulation. The Aztec Protocol team originally created Huff to writ...

Huff By Example
In this rapidly evolving landscape of blockchain technology, efficiency isn't just an advantage—it's a necessity. More the adoption is, the more congested the networks become (for now this is the case), hence the race for gas optimization intensifies, every opcode, every byte, and every operation counts. Enter Huff, a language so close to the metal of the Ethereum Virtual Machine (EVM) which has the potential to take on-chain possibilities to one step further. In this post, we’ll di...
EVM | DeFi | SmartContracts 🚀

Subscribe to PraneshASP ⚡

Subscribe to PraneshASP ⚡
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers


In this article, we’re going to have a look into the solution for Huff Challenge #5. If you wanna check-out the solutions for other challenges, look here.
The challenge we're examining today revolves around message signatures. Our goal is to create a contract using Huff, that takes a signature as input from the calldata, verifies if the message was indeed signed by the sender of the transaction, and returns true if it was. If the message wasn't signed by the sender or if the calldata doesn't adhere to the expected structure, we want the contract to do something that causes the transaction to run out of gas.
Here’s the solution for your quick glance:
#define macro MAIN() = takes (0) returns (0) {
/// Check if calldatasize is 97 bytes (MessageHash=32, Signature=65)
calldatasize
0x61 eq
extractParamsAndStore jumpi
oog jump
extractParamsAndStore:
/// Store the message hash
0x00 calldataload
0x00 mstore
/// Store 'v'
0x60 calldataload
0x3f mstore
/// Store 'r'
0x20 calldataload
0x40 mstore
/// Store 's'
0x40 calldataload
0x60 mstore
/// Prepare stack for 'ecrecover' staticcall
0x20
0x00
0x80
0x00
chainid
gas
staticcall validate jumpi
oog jump
/// Check if caller==retdata (signer address)
validate:
0x00 mload
dup1
caller
eq valid jumpi
oog jump
// Return true
valid:
chainid
0x00 mstore
0x20 0x00 return
// out-of-gas
oog:
0x01 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff mstore
If the above code is all Greek and Latin to you, don’t worry. I’m here to break it down for you.
#define macro MAIN() = takes (0) returns (0) {
calldatasize
0x61 eq
extractParamsAndStore jumpi
oog jump
The first part of the contract is responsible for checking whether the calldatasize equals 0x61 (which is the hexadecimal representation of 97 in decimal). 97 bytes is the expected size of the calldata (MessageHash=32 bytes, Signature=65 bytes). If the size is correct, it jumps to the extractParamsAndStore label. Otherwise, it jumps to the oog (out-of-gas) label to make the transaction run out of gas.
Assumption*: The contract assumes that the calldata is structured in a specific way (message hash first, followed by the v, r, s components of the signature). If the input doesn't follow this structure, the contract won't function as intended.*
Next, we extract parameters from the calldata:
extractParamsAndStore:
0x00 calldataload
0x00 mstore
0x60 calldataload
0x3f mstore
0x20 calldataload
0x40 mstore
0x40 calldataload
0x60 mstore
This part of the code extracts and stores the message hash, v, r, and s values from the calldata. These values represent the signed message we're looking for. The calldataload operation takes the start byte from the calldata, and mstore stores this data in memory.
We then prepare the stack with parameters for the ecrecover call:
0x20
0x00
0x80
0x00
chainid
gas
staticcall validate jumpi
oog jump
A staticcall is made to the precompiled contract residing at the address 0x01. It implements the ecrecover method. It is used to extract the signer’s address from the signature using message hash, v, r, and s values as input. The jumpi instruction then checks the outcome of the ecrecover call. If it's successful, the control gets transferred to the validate label. Otherwise, it jumps to oog, causing the transaction to run out of gas.
Assumption: The above piece of code assumes that the contract will be deployed on the Ethereum mainnet as you can see we use chainid as the target address of static call where the precompile for ecrecover resides. To learn more about precompiles, look here.
The contract then verifies if the extracted signer’s address matches the transaction sender’s address:
validate:
0x00 mload // [rcvd_address]
dup1 // [rcvd_address, rcvd_address]
caller // [msg.sender, rcvd_address]
eq valid jumpi // [msg.sender == rcvd_address?]
oog jump // if not equal, jump to out-of-gas block
The mload operation loads the signer's address from memory which is be the return value of the ecrecover call, dup1 duplicates this address on the stack, and caller gets the address of the transaction sender. The eq operation checks if the two addresses match. If they do, the program jumps to the valid label. Otherwise, it jumps to oog, again causing the transaction to run out of gas.
Finally, the contract returns true in the case of a valid signature:
valid:
chainid
0x00 mstore
0x20 0x00 return
This section stores the current chain id (which serves as a boolean value 0x01 for Mainnet to represent true) into memory and returns it.
And in case of invalid calldata or signature, we run out of gas:
oog:
0x01
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
mstore
This code tries to store a massive value into memory, thereby using up all the available gas and causing an out-of-gas error.
You can find a runnable PoC including tests for all the Huff Challenges here:
https://github.com/minaminao/ctf-blockchain/tree/main/src/HuffChallenge
To learn more about Huff, join the Huff developers discord server:
Stay tuned… Until next time 👋👋
In this article, we’re going to have a look into the solution for Huff Challenge #5. If you wanna check-out the solutions for other challenges, look here.
The challenge we're examining today revolves around message signatures. Our goal is to create a contract using Huff, that takes a signature as input from the calldata, verifies if the message was indeed signed by the sender of the transaction, and returns true if it was. If the message wasn't signed by the sender or if the calldata doesn't adhere to the expected structure, we want the contract to do something that causes the transaction to run out of gas.
Here’s the solution for your quick glance:
#define macro MAIN() = takes (0) returns (0) {
/// Check if calldatasize is 97 bytes (MessageHash=32, Signature=65)
calldatasize
0x61 eq
extractParamsAndStore jumpi
oog jump
extractParamsAndStore:
/// Store the message hash
0x00 calldataload
0x00 mstore
/// Store 'v'
0x60 calldataload
0x3f mstore
/// Store 'r'
0x20 calldataload
0x40 mstore
/// Store 's'
0x40 calldataload
0x60 mstore
/// Prepare stack for 'ecrecover' staticcall
0x20
0x00
0x80
0x00
chainid
gas
staticcall validate jumpi
oog jump
/// Check if caller==retdata (signer address)
validate:
0x00 mload
dup1
caller
eq valid jumpi
oog jump
// Return true
valid:
chainid
0x00 mstore
0x20 0x00 return
// out-of-gas
oog:
0x01 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff mstore
If the above code is all Greek and Latin to you, don’t worry. I’m here to break it down for you.
#define macro MAIN() = takes (0) returns (0) {
calldatasize
0x61 eq
extractParamsAndStore jumpi
oog jump
The first part of the contract is responsible for checking whether the calldatasize equals 0x61 (which is the hexadecimal representation of 97 in decimal). 97 bytes is the expected size of the calldata (MessageHash=32 bytes, Signature=65 bytes). If the size is correct, it jumps to the extractParamsAndStore label. Otherwise, it jumps to the oog (out-of-gas) label to make the transaction run out of gas.
Assumption*: The contract assumes that the calldata is structured in a specific way (message hash first, followed by the v, r, s components of the signature). If the input doesn't follow this structure, the contract won't function as intended.*
Next, we extract parameters from the calldata:
extractParamsAndStore:
0x00 calldataload
0x00 mstore
0x60 calldataload
0x3f mstore
0x20 calldataload
0x40 mstore
0x40 calldataload
0x60 mstore
This part of the code extracts and stores the message hash, v, r, and s values from the calldata. These values represent the signed message we're looking for. The calldataload operation takes the start byte from the calldata, and mstore stores this data in memory.
We then prepare the stack with parameters for the ecrecover call:
0x20
0x00
0x80
0x00
chainid
gas
staticcall validate jumpi
oog jump
A staticcall is made to the precompiled contract residing at the address 0x01. It implements the ecrecover method. It is used to extract the signer’s address from the signature using message hash, v, r, and s values as input. The jumpi instruction then checks the outcome of the ecrecover call. If it's successful, the control gets transferred to the validate label. Otherwise, it jumps to oog, causing the transaction to run out of gas.
Assumption: The above piece of code assumes that the contract will be deployed on the Ethereum mainnet as you can see we use chainid as the target address of static call where the precompile for ecrecover resides. To learn more about precompiles, look here.
The contract then verifies if the extracted signer’s address matches the transaction sender’s address:
validate:
0x00 mload // [rcvd_address]
dup1 // [rcvd_address, rcvd_address]
caller // [msg.sender, rcvd_address]
eq valid jumpi // [msg.sender == rcvd_address?]
oog jump // if not equal, jump to out-of-gas block
The mload operation loads the signer's address from memory which is be the return value of the ecrecover call, dup1 duplicates this address on the stack, and caller gets the address of the transaction sender. The eq operation checks if the two addresses match. If they do, the program jumps to the valid label. Otherwise, it jumps to oog, again causing the transaction to run out of gas.
Finally, the contract returns true in the case of a valid signature:
valid:
chainid
0x00 mstore
0x20 0x00 return
This section stores the current chain id (which serves as a boolean value 0x01 for Mainnet to represent true) into memory and returns it.
And in case of invalid calldata or signature, we run out of gas:
oog:
0x01
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
mstore
This code tries to store a massive value into memory, thereby using up all the available gas and causing an out-of-gas error.
You can find a runnable PoC including tests for all the Huff Challenges here:
https://github.com/minaminao/ctf-blockchain/tree/main/src/HuffChallenge
To learn more about Huff, join the Huff developers discord server:
Stay tuned… Until next time 👋👋
No activity yet