// Honest gas report for AereThresholdAccount.executeThreshold. The MockPQCPrecompile returns // almost immediately, so the MEASURED gas here is the account's own Solidity + calldata overhead // (decode + distinct-bitmap + per-leg envelope assembly + staticcall dispatch). The REAL on-chain // cost adds the live precompile's verify gas per leg (Falcon-512 ~40k, ML-DSA-44 ~55k, Falcon-1024 // ~75k, SLH-DSA-128s ~350k — from research/aip-draft-pqc-precompiles.md). We measure the marginal // overhead per leg by differencing two thresholds, then project the real (scheme, t) cost. const { ethers, network } = require("hardhat"); const PRECOMPILE = { 1: ethers.getAddress("0x0000000000000000000000000000000000000ae1"), 2: ethers.getAddress("0x0000000000000000000000000000000000000ae2"), 3: ethers.getAddress("0x0000000000000000000000000000000000000ae3"), 4: ethers.getAddress("0x0000000000000000000000000000000000000ae4"), }; const META = { 1: { pkLen: 897, pkHeader: 0x09, esigHeader: 0x29, falcon: true } }; const REAL_PRECOMPILE_GAS = { 1: 40000, 2: 75000, 3: 55000, 4: 350000 }; function makeRng(seedText) { let seed = ethers.keccak256(ethers.toUtf8Bytes(seedText)); return { bytes(n) { const out = new Uint8Array(n); let i = 0; while (i < n) { seed = ethers.keccak256(seed); const c = ethers.getBytes(seed); for (let j = 0; j < c.length && i < n; j++, i++) out[i] = c[j]; } return out; }, }; } function makePubKey(rng) { const raw = rng.bytes(META[1].pkLen); raw[0] = META[1].pkHeader; return ethers.hexlify(raw); } function genuine(pubKey, message, rng) { const commitment = ethers.keccak256(ethers.concat([pubKey, message])); const nonce = rng.bytes(40); const esig = ethers.concat([new Uint8Array([META[1].esigHeader]), commitment]); return ethers.hexlify(ethers.concat([nonce, esig])); } describe("AereThresholdAccount — gas report (Falcon-512, n=8)", function () { let mockCode, ep, echo, pubKeys, rng, factory; const N = 8; before(async function () { mockCode = {}; const F = await ethers.getContractFactory("MockPQCPrecompile"); for (const s of [1, 2, 3, 4]) { const m = await F.deploy(s); await m.waitForDeployment(); mockCode[s] = await ethers.provider.getCode(await m.getAddress()); } }); beforeEach(async function () { for (const s of [1, 2, 3, 4]) await network.provider.send("hardhat_setCode", [PRECOMPILE[s], mockCode[s]]); [ep] = await ethers.getSigners(); rng = makeRng("gas-report"); pubKeys = []; for (let i = 0; i < N; i++) pubKeys.push(makePubKey(rng)); factory = await (await ethers.getContractFactory("AereThresholdAccountFactory")).deploy(); await factory.waitForDeployment(); echo = await (await ethers.getContractFactory("EchoTarget")).deploy(); await echo.waitForDeployment(); }); async function deploy(t, salt) { const addr = await factory.computeAddress(ep.address, 1, t, pubKeys, salt); await (await factory.createAccount(ep.address, 1, t, pubKeys, salt)).wait(); return ethers.getContractAt("AereThresholdAccount", addr); } async function execGas(account, t) { const target = await echo.getAddress(); const data = echo.interface.encodeFunctionData("bump"); const challenge = await account.execChallenge(0, target, 0, data); const legs = []; for (let i = 0; i < t; i++) legs.push([i, genuine(pubKeys[i], challenge, rng)]); const tx = await account.executeThreshold(target, 0, data, legs); const rc = await tx.wait(); return Number(rc.gasUsed); } it("measures marginal overhead per leg and projects the real per-scheme cost", async function () { const g2 = await execGas(await deploy(2, ethers.id("g2")), 2); const g6 = await execGas(await deploy(6, ethers.id("g6")), 6); const perLegOverhead = Math.round((g6 - g2) / 4); const baseOverhead = g2 - 2 * perLegOverhead; console.log(`\n executeThreshold measured gas (mock precompile ~free):`); console.log(` t=2: ${g2} gas t=6: ${g6} gas`); console.log(` marginal Solidity+calldata overhead per leg: ~${perLegOverhead} gas`); console.log(` fixed base overhead: ~${baseOverhead} gas`); console.log(` projected REAL cost = base + t*(overhead + precompile_verify):`); for (const s of [1, 2, 3, 4]) { const name = { 1: "Falcon-512", 2: "Falcon-1024", 3: "ML-DSA-44", 4: "SLH-DSA-128s" }[s]; const perLegReal = perLegOverhead + REAL_PRECOMPILE_GAS[s]; const t3 = baseOverhead + 3 * perLegReal; const cap = 16777216; // EIP-7825 per-tx gas cap (2^24) const tMax = Math.floor((cap - baseOverhead) / perLegReal); console.log(` ${name.padEnd(13)} real/leg ~${perLegReal} gas | 3-of-n ~${t3} gas | t_max under 2^24 ~ ${tMax}`); } // sanity: overhead is positive and gas grew with t if (!(g6 > g2 && perLegOverhead > 0)) throw new Error("unexpected gas profile"); }); });