// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "../zkverify/ISP1Verifier.sol";

/// @title AereCompliancePoolSP1Verifier
/// @notice SP1-backed verifier adapter for AereCompliancePool. Bridges the
///         pool's `IPrivacyPoolVerifier.verify(bytes proof, uint256[] pubs)`
///         interface to the Succinct Labs SP1 verifier gateway.
///
///         The off-chain prover is the Rust SP1 program at
///         `zk-circuits/compliance-pool/program`. Its compiled VKEY is
///         stored as a constructor-immutable here. The 8 public inputs
///         the pool passes (poolId, depositRoot, associationRoot,
///         nullifierHash, recipient, feeRecipient, refund, fee) are
///         abi-encoded into the same struct the program commits to.
///
/// @dev    Drop-in replacement for `MockPrivacyPoolVerifier` in production
///         deploys. Test deploys may continue to use the mock to avoid
///         needing a real SP1 proof per test.
contract AereCompliancePoolSP1Verifier {
    ISP1Verifier public immutable SP1;
    bytes32       public immutable PROGRAM_VKEY;

    error InvalidPublicInputCount();
    error InvalidPublicValues();

    constructor(ISP1Verifier sp1, bytes32 programVKey) {
        require(address(sp1) != address(0) && programVKey != bytes32(0), "zero");
        SP1 = sp1;
        PROGRAM_VKEY = programVKey;
    }

    /// @notice Verify a withdraw proof.
    /// @param  proof   SP1-encoded proof bytes (Groth16 or PLONK over SP1 zkVM)
    /// @param  pubs    [poolId, depositRoot, associationRoot, nullifierHash,
    ///                  recipient, feeRecipient, refund, fee]
    /// @return ok      True iff SP1 verifier accepts the proof against the
    ///                 ABI-encoded public-values struct.
    function verify(bytes calldata proof, uint256[] calldata pubs) external view returns (bool ok) {
        if (pubs.length != 8) revert InvalidPublicInputCount();

        // The Rust program commits PublicValues = (bytes32 pool_id,
        // bytes32 deposit_root, bytes32 association_root,
        // bytes32 nullifier_hash, address recipient, address fee_recipient,
        // uint256 refund, uint256 fee).
        bytes memory publicValues = abi.encode(
            bytes32(pubs[0]),
            bytes32(pubs[1]),
            bytes32(pubs[2]),
            bytes32(pubs[3]),
            address(uint160(pubs[4])),
            address(uint160(pubs[5])),
            pubs[6],
            pubs[7]
        );

        // SP1Verifier.verifyProof reverts on failure. Wrap in a low-level
        // staticcall so we can return bool to fit the existing pool
        // interface.
        (bool success, ) = address(SP1).staticcall(
            abi.encodeCall(ISP1Verifier.verifyProof, (PROGRAM_VKEY, publicValues, proof))
        );
        return success;
    }
}
