aere-contracts/contracts/zkverify/risczero/RiscZeroVerifierRouter.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

106 lines
5.1 KiB
Solidity

// Copyright 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.9;
import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IRiscZeroVerifier, Receipt} from "./IRiscZeroVerifier.sol";
/// @notice Router for IRiscZeroVerifier, allowing multiple implementations to be accessible behind a single address.
contract RiscZeroVerifierRouter is IRiscZeroVerifier, Ownable2Step {
/// @notice Mapping from 4-byte verifier selector to verifier contracts.
/// Used to route receipts to verifiers that are able to check the receipt.
mapping(bytes4 => IRiscZeroVerifier) public verifiers;
/// @notice Value of an entry that has never been set.
IRiscZeroVerifier internal constant UNSET = IRiscZeroVerifier(address(0));
/// @notice A "tombstone" value used to mark verifier entries that have been removed from the mapping.
IRiscZeroVerifier internal constant TOMBSTONE = IRiscZeroVerifier(address(1));
/// @notice Error raised when attempting to verify a receipt with a selector that is not
/// registered on this router. Generally, this indicates a version mismatch where the
/// prover generated a receipt with version of the zkVM that does not match any
/// registered version on this router contract.
error SelectorUnknown(bytes4 selector);
/// @notice Error raised when attempting to add a verifier for a selector that is already registered.
error SelectorInUse(bytes4 selector);
/// @notice Error raised when attempting to verify a receipt with a selector that has been
/// removed, or attempting to add a new verifier with a selector that was previously
/// registered and then removed.
error SelectorRemoved(bytes4 selector);
/// @notice Error raised when attempting to add a verifier with a zero address.
error VerifierAddressZero();
constructor(address admin) Ownable() { transferOwnership(admin); }
/// @notice Adds a verifier to the router, such that it can receive receipt verification calls.
function addVerifier(bytes4 selector, IRiscZeroVerifier verifier) external virtual onlyOwner {
if (verifiers[selector] == TOMBSTONE) {
revert SelectorRemoved({selector: selector});
}
if (verifiers[selector] != UNSET) {
revert SelectorInUse({selector: selector});
}
if (address(verifier) == address(0)) {
revert VerifierAddressZero();
}
verifiers[selector] = verifier;
}
/// @notice Removes verifier from the router, such that it can not receive verification calls.
/// Removing a selector sets it to the tombstone value. It can never be set to any
/// other value, and can never be reused for a new verifier, in order to enforce the
/// property that each selector maps to at most one implementation across time.
function removeVerifier(bytes4 selector) external virtual onlyOwner {
// Simple check to reduce the chance of accidents.
// NOTE: If there ever _is_ a reason to remove a selector that has never been set, the owner
// can call addVerifier with the tombstone address.
if (verifiers[selector] == UNSET) {
revert SelectorUnknown({selector: selector});
}
verifiers[selector] = TOMBSTONE;
}
/// @notice Get the associated verifier, reverting if the selector is unknown or removed.
function getVerifier(bytes4 selector) public view virtual returns (IRiscZeroVerifier) {
IRiscZeroVerifier verifier = verifiers[selector];
if (verifier == UNSET) {
revert SelectorUnknown({selector: selector});
}
if (verifier == TOMBSTONE) {
revert SelectorRemoved({selector: selector});
}
return verifier;
}
/// @notice Get the associated verifier, reverting if the selector is unknown or removed.
function getVerifier(bytes calldata seal) public view returns (IRiscZeroVerifier) {
// Use the first 4 bytes of the seal at the selector to look up in the mapping.
return getVerifier(bytes4(seal[0:4]));
}
/// @inheritdoc IRiscZeroVerifier
function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view virtual {
getVerifier(seal).verify(seal, imageId, journalDigest);
}
/// @inheritdoc IRiscZeroVerifier
function verifyIntegrity(Receipt calldata receipt) external view virtual {
getVerifier(receipt.seal).verifyIntegrity(receipt);
}
}