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.
67 lines
2.8 KiB
Solidity
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;
|
|
}
|
|
}
|