// SPDX-License-Identifier: ISC pragma solidity ^0.8.20; // A contract that is cheap in execution gas but heavy in proving gas (pgas): it hammers the modexp precompile // (0x05) and the KECCAK256 opcode in a loop. Under Igneum's pgas table (igneum/exec/src/pgas.rs) modexp is // ~1000 + 10*input_len pgas for ~200 execution gas, so each call carries a large pgas/gas ratio and a loop can // drive a transaction's pgas toward the per-block proving budget B_p with only a few million execution gas. contract PgasBomb { event Done(uint256 iterations, uint256 acc); // Call the 1024-bit modexp precompile `n` times. Each call: baseLen=1, expLen=1, modLen=128 (input_len 226). function modexpLoop(uint256 n) external returns (uint256 acc) { bytes memory input = new bytes(96 + 1 + 1 + 128); // baseLen = 1 input[31] = 0x01; // expLen = 1 input[63] = 0x01; // modLen = 128 input[95] = 0x80; // base byte = 2 input[96] = 0x02; // exp byte = 1 input[97] = 0x01; // modulus: all 0xff (a large odd number) for (uint256 i = 0; i < 128; i++) input[98 + i] = 0xff; bytes memory out = new bytes(128); for (uint256 i = 0; i < n; i++) { bool ok; assembly { ok := staticcall(gas(), 0x05, add(input, 32), mload(input), add(out, 32), 128) } require(ok, "modexp failed"); acc += uint8(out[127]); } emit Done(n, acc); } // Hash a 32-byte word `n` times, chaining the result. Pure KECCAK256 opcode load. function keccakLoop(uint256 n) external returns (bytes32 h) { h = keccak256(abi.encodePacked(block.number)); for (uint256 i = 0; i < n; i++) { h = keccak256(abi.encodePacked(h)); } } }