aere-contracts/contracts/zkverify/v6_0/SP1VerifierGroth16.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

84 lines
3.2 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol";
import {Verifier} from "./Groth16Verifier.sol";
/// @title SP1 Verifier
/// @author Succinct Labs
/// @notice This contracts implements a solidity verifier for SP1.
contract SP1Verifier is Verifier, ISP1VerifierWithHash {
/// @notice Thrown when the verifier selector from this proof does not match the one in this
/// verifier. This indicates that this proof was sent to the wrong verifier.
/// @param received The verifier selector from the first 4 bytes of the proof.
/// @param expected The verifier selector from the first 4 bytes of the VERIFIER_HASH().
error WrongVerifierSelector(bytes4 received, bytes4 expected);
/// @notice Thrown when the exit code is invalid.
error InvalidExitCode();
/// @notice Thrown when the proof is invalid.
error InvalidProof();
/// @notice Thrown when the vkRoot is invalid.
error InvalidVkRoot();
/// @notice The version of the circuit.
function VERSION() external pure returns (string memory) {
return "v6.0.0";
}
/// @inheritdoc ISP1VerifierWithHash
function VERIFIER_HASH() public pure returns (bytes32) {
return 0x0e78f4db7a6771a3a6a7d9c3b0de6fe73d58781368967a7fe84d87aefffec896;
}
/// @notice The recursion vk root.
function VK_ROOT() public pure returns (bytes32) {
return 0x008cd56e10c2fe24795cff1e1d1f40d3a324528d315674da45d26afb376e8670;
}
/// @notice Hashes the public values to a field elements inside Bn254.
/// @param publicValues The public values.
function hashPublicValues(bytes calldata publicValues) public pure returns (bytes32) {
return sha256(publicValues) & bytes32(uint256((1 << 253) - 1));
}
/// @notice Verifies a proof with given public values and vkey.
/// @param programVKey The verification key for the RISC-V program.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
) external view {
bytes4 receivedSelector = bytes4(proofBytes[:4]);
bytes4 expectedSelector = bytes4(VERIFIER_HASH());
if (receivedSelector != expectedSelector) {
revert WrongVerifierSelector(receivedSelector, expectedSelector);
}
uint256 expectedVkRoot = uint256(VK_ROOT());
bytes32 publicValuesDigest = hashPublicValues(publicValues);
(uint256 exitCode, uint256 vkRoot, uint256 nonce, uint256[8] memory proof) =
abi.decode(proofBytes[4:], (uint256, uint256, uint256, uint256[8]));
if (exitCode != 0) {
revert InvalidExitCode();
}
if (vkRoot != expectedVkRoot) {
revert InvalidVkRoot();
}
uint256[5] memory inputs;
inputs[0] = uint256(programVKey);
inputs[1] = uint256(publicValuesDigest);
inputs[2] = exitCode;
inputs[3] = vkRoot;
inputs[4] = nonce;
this.verifyProof(proof, inputs);
}
}