// 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));
    }
}
