#!/usr/bin/env python3 # Derive AereFalcon512VerifierHTP.sol from AereFalcon512Verifier.sol by replacing # ONLY the in-EVM hashToPoint with a call to the native 0x0AE7 precompile. Every # other step (SHAKE helpers, decode, ring mul, norm check) is byte-identical, so a # WITH-vs-WITHOUT gas comparison isolates exactly the HashToPoint cost. import re import sys src_path = sys.argv[1] out_path = sys.argv[2] s = open(src_path).read() # 1. rename the contract s = s.replace("contract AereFalcon512Verifier {", "contract AereFalcon512VerifierHTP {") # 2. relax `pure` -> `view` on function declarations (the precompile call is a staticcall = view) s = re.sub(r"\)(\s*)(public|internal|external|private)(\s+)pure", r")\1\2\3view", s) # 3. replace the whole hashToPoint function body with a precompile-backed one (brace-matched) start = s.index("function hashToPoint(") # walk to the opening brace of the body brace = s.index("{", start) depth = 0 i = brace while i < len(s): if s[i] == "{": depth += 1 elif s[i] == "}": depth -= 1 if depth == 0: break i += 1 end = i + 1 # inclusive of closing brace replacement = ( "function hashToPoint(bytes memory nonce, bytes memory message) public view returns (uint256[512] memory cc) {\n" " // Native AERE Falcon HashToPoint precompile @ 0x0AE7: logn(1)=9 || nonce(40) || message\n" " bytes memory input = bytes.concat(bytes1(uint8(9)), nonce, message);\n" " (bool okp, bytes memory outp) = address(0x0AE7).staticcall(input);\n" " require(okp && outp.length == 1024, \"htp precompile failed\");\n" " for (uint256 i = 0; i < 512; i++) {\n" " cc[i] = (uint256(uint8(outp[2 * i])) << 8) | uint256(uint8(outp[2 * i + 1]));\n" " }\n" " }" ) s = s[:start] + replacement + s[end:] open(out_path, "w").write(s) print("wrote", out_path)