// SPDX-License-Identifier: MIT pragma solidity 0.8.23; interface IAereFalcon512Verifier { function verifySignedMessage(bytes calldata pk, bytes calldata sm) external pure returns (bool); } /** * @title RealFalcon512PrecompileAdapter, TEST-ONLY real-crypto stand-in for the 0x0AE1 precompile * * @notice Hardhat has no native PQC precompile. Where MockPQCPrecompile models the precompile's * SEMANTICS (accept iff a keccak commitment matches), this adapter runs ACTUAL Falcon-512 * verification: install it at 0x0AE1 via hardhat_setCode and every registry precompile * staticcall (`pk || sm`) is routed into the audited, NIST-KAT-proven AereFalcon512Verifier * (see AereFalcon512Verifier.test.js, which accepts the official round-3 KAT vector 0). * * The precompile wire format is IDENTICAL to the live mainnet precompile and to what * AerePQCKeyRegistry / AerePQCThreshold build: * input = pk(897) || sm , sm = sigLen(2, big-endian) || nonce(40) || message || esig * so a positive result here proves the registry assembled the input at the exact NIST * offsets AND that a genuine Falcon-512 signature (not a mock commitment) is accepted. The * raw 32-byte return word (0x..01 / 0x..00) matches the live precompile byte layout, so the * caller's `ret.length >= 32 && ret[31] == 0x01` check behaves exactly as on chain 2800. * * The immutable verifier address is baked into runtime bytecode, so it survives the * hardhat_setCode copy to 0x0AE1. */ contract RealFalcon512PrecompileAdapter { address public immutable verifier; uint256 internal constant PK_LEN = 897; // Falcon-512 public key length constructor(address _verifier) { verifier = _verifier; } fallback() external { bool valid = _check(msg.data); bytes32 w = valid ? bytes32(uint256(1)) : bytes32(0); assembly { mstore(0x0, w) return(0x0, 32) } } function _check(bytes calldata input) internal view returns (bool) { if (input.length <= PK_LEN) return false; bytes calldata pk = input[0:PK_LEN]; bytes calldata sm = input[PK_LEN:]; (bool ok, bytes memory ret) = verifier.staticcall( abi.encodeWithSelector(IAereFalcon512Verifier.verifySignedMessage.selector, pk, sm) ); return ok && ret.length >= 32 && abi.decode(ret, (bool)); } }