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.
108 lines
4.0 KiB
Solidity
108 lines
4.0 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.23;
|
|
|
|
// Import ONLY the V2 history anchor. It transitively imports the V1 history
|
|
// anchor (and its single IAereStorageProofVerifier declaration), so this
|
|
// compilation closure sees exactly one copy of that interface. It deliberately
|
|
// does NOT import AereStateRootAnchor.sol, which declares a same-named interface
|
|
// and would collide.
|
|
import "../AereHistoryStateRootAnchorV2.sol";
|
|
|
|
/**
|
|
* @dev Test-only subclass of the ORIGINAL history anchor (V1) that injects a
|
|
* canonical block hash for a block number, standing in for the EIP-2935
|
|
* ring buffer without a live fork. Everything else is the production V1
|
|
* logic, including the redundant double verification in proveAgainstAnchor.
|
|
*/
|
|
contract MockHistoryAnchorV1 is AereHistoryStateRootAnchor {
|
|
mapping(uint256 => bytes32) public injected;
|
|
|
|
constructor(address verifier) AereHistoryStateRootAnchor(verifier) {}
|
|
|
|
function setHistoryBlockHash(uint256 blockNumber, bytes32 h) external {
|
|
injected[blockNumber] = h;
|
|
}
|
|
|
|
function _historyBlockHash(uint256 blockNumber) internal view override returns (bytes32) {
|
|
bytes32 h = injected[blockNumber];
|
|
if (h == bytes32(0)) revert OutOfHistoryWindow(blockNumber, block.number);
|
|
return h;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Test-only subclass of the corrected history anchor (V2) with the same
|
|
* injectable canonical block hash. proveAgainstAnchor runs the single
|
|
* corrected path.
|
|
*/
|
|
contract MockHistoryAnchorV2 is AereHistoryStateRootAnchorV2 {
|
|
mapping(uint256 => bytes32) public injected;
|
|
|
|
constructor(address verifier) AereHistoryStateRootAnchorV2(verifier) {}
|
|
|
|
function setHistoryBlockHash(uint256 blockNumber, bytes32 h) external {
|
|
injected[blockNumber] = h;
|
|
}
|
|
|
|
function _historyBlockHash(uint256 blockNumber) internal view override returns (bytes32) {
|
|
bytes32 h = injected[blockNumber];
|
|
if (h == bytes32(0)) revert OutOfHistoryWindow(blockNumber, block.number);
|
|
return h;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Counting stand-in for the LIVE AereStorageProofVerifier used to prove
|
|
* how many SP1 verifications a caller triggers.
|
|
*
|
|
* submitProofWithExpectedRoot is the ONE verification the corrected anchor
|
|
* must run: it validates, binds the committed root to the expected root,
|
|
* records, and increments `submitCalls`.
|
|
*
|
|
* verify() reverts with RedundantVerifyCall. The live verify() is a
|
|
* stateless view whose whole cost is the SP1 Groth16 pairing; the original
|
|
* anchor calls it purely to read the block number, which the corrected
|
|
* anchor derives locally. Making verify() revert here means any code path
|
|
* that still calls it (the V1 double-verify) fails loudly, while the
|
|
* corrected path (which never calls verify) is unaffected. `submitCalls`
|
|
* then witnesses that exactly one verification ran.
|
|
*/
|
|
contract CountingStorageProofVerifier is IAereStorageProofVerifier {
|
|
bool public shouldValidate = true;
|
|
uint256 public submitCalls;
|
|
|
|
/// @notice keccak256(publicValues) => recorded, for assertions.
|
|
mapping(bytes32 => bool) public recorded;
|
|
|
|
error RedundantVerifyCall();
|
|
|
|
function setValidate(bool v) external {
|
|
shouldValidate = v;
|
|
}
|
|
|
|
function verify(bytes calldata, bytes calldata)
|
|
external
|
|
pure
|
|
returns (uint256, bytes32, address, bytes32, bytes32)
|
|
{
|
|
revert RedundantVerifyCall();
|
|
}
|
|
|
|
function submitProofWithExpectedRoot(
|
|
bytes calldata publicValues,
|
|
bytes calldata /*proof*/,
|
|
bytes32 expectedStateRoot
|
|
) external returns (bytes32 value) {
|
|
require(shouldValidate, "InvalidProof");
|
|
require(publicValues.length == 192, "BadPublicValuesLength");
|
|
(, , bytes32 stateRoot, , , bytes32 v) = abi.decode(
|
|
publicValues,
|
|
(uint256, uint256, bytes32, address, bytes32, bytes32)
|
|
);
|
|
require(stateRoot == expectedStateRoot, "StateRootMismatch");
|
|
recorded[keccak256(publicValues)] = true;
|
|
submitCalls += 1;
|
|
return v;
|
|
}
|
|
}
|