aere-contracts/contracts/compliance/AereCompliancePoolSP1Verifier.sol
Aere Network a13a649b77
Some checks are pending
contracts-ci / Install (lockfile) → compile → full test suite (push) Waiting to run
contracts-ci / PQC known-answer tests (NIST vectors) (push) Waiting to run
contracts-ci / Coverage (scoped, with artifacts) (push) Waiting to run
Initial public release
Aere Network public source. Everything here can be checked against the live
chain (chain id 2800, https://rpc.aere.network).

Scope note, stated up front rather than buried: consensus on chain 2800 is
classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at
the signature, precompile, account and transport layers. Nothing here makes the
consensus post-quantum, and no document in it should be read as claiming so.
2026-07-20 01:02:37 +03:00

67 lines
2.8 KiB
Solidity

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