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.
104 lines
3.7 KiB
Solidity
104 lines
3.7 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.23;
|
|
|
|
/// @dev Generated Halo2 (bn254/KZG) verifier ABI: verifyProof returns a
|
|
/// 32-byte true on success and REVERTS (empty data) on any failure.
|
|
interface IHalo2Verifier {
|
|
function verifyProof(bytes calldata proof, uint256[] calldata instances)
|
|
external
|
|
returns (bool);
|
|
}
|
|
|
|
/**
|
|
* @title AereHalo2ProofAnchor — on-chain record of verified Halo2 proofs
|
|
* @notice Thin, admin-less anchor over a generated Halo2 Solidity verifier
|
|
* (privacy-scaling-explorations/halo2-solidity-verifier, bn254/KZG,
|
|
* Bdfg21/SHPLONK batch opening). The bound verifier for this
|
|
* deployment is AereHalo2CubicVerifier: a real 4-row standard-PLONK
|
|
* circuit proving knowledge of a private x with x^3 + x + 5 == out,
|
|
* where out is the single public instance.
|
|
*
|
|
* verifyAndRecord() forwards (proof, instances) to the verifier;
|
|
* the verifier reverts on an invalid proof, so reaching the record
|
|
* line means the proof is genuinely valid. Records are append-only:
|
|
* (sender, keccak256(proof), keccak256(instances), block, time).
|
|
*
|
|
* IMMUTABILITY: the verifier address is fixed at deploy; no owner,
|
|
* no admin, no pause.
|
|
*/
|
|
contract AereHalo2ProofAnchor {
|
|
|
|
/// @notice The generated Halo2 verifier this anchor is bound to.
|
|
address public immutable VERIFIER;
|
|
|
|
struct Record {
|
|
address sender;
|
|
bytes32 proofHash; // keccak256 of the raw proof bytes
|
|
bytes32 instancesHash; // keccak256(abi.encodePacked(instances))
|
|
uint64 blockNumber;
|
|
uint64 timestamp;
|
|
}
|
|
|
|
Record[] private _records;
|
|
|
|
/// @notice Number of successful verifications per proof hash.
|
|
mapping(bytes32 => uint256) public verificationCountByProofHash;
|
|
|
|
event Halo2ProofVerified(
|
|
address indexed sender,
|
|
bytes32 indexed proofHash,
|
|
bytes32 instancesHash,
|
|
uint256 index
|
|
);
|
|
|
|
error ZeroVerifier();
|
|
error ProofRejected();
|
|
|
|
constructor(address verifier) {
|
|
if (verifier == address(0)) revert ZeroVerifier();
|
|
VERIFIER = verifier;
|
|
}
|
|
|
|
/**
|
|
* @notice Verify a Halo2 proof through the bound verifier and record it.
|
|
* @param proof Raw proof bytes as produced by the halo2 prover
|
|
* (Keccak256Transcript, ProverSHPLONK).
|
|
* @param instances Public instances (for AereHalo2CubicVerifier: [out]).
|
|
* @return index Index of the stored record.
|
|
*/
|
|
function verifyAndRecord(bytes calldata proof, uint256[] calldata instances)
|
|
external
|
|
returns (uint256 index)
|
|
{
|
|
// The generated verifier reverts on an invalid proof; bubble that up
|
|
// as a clean custom error if it somehow returns false instead.
|
|
bool ok = IHalo2Verifier(VERIFIER).verifyProof(proof, instances);
|
|
if (!ok) revert ProofRejected();
|
|
|
|
bytes32 proofHash = keccak256(proof);
|
|
bytes32 instancesHash = keccak256(abi.encodePacked(instances));
|
|
|
|
index = _records.length;
|
|
_records.push(Record({
|
|
sender: msg.sender,
|
|
proofHash: proofHash,
|
|
instancesHash: instancesHash,
|
|
blockNumber: uint64(block.number),
|
|
timestamp: uint64(block.timestamp)
|
|
}));
|
|
verificationCountByProofHash[proofHash] += 1;
|
|
|
|
emit Halo2ProofVerified(msg.sender, proofHash, instancesHash, index);
|
|
}
|
|
|
|
/// @notice Total number of recorded verifications.
|
|
function recordCount() external view returns (uint256) {
|
|
return _records.length;
|
|
}
|
|
|
|
/// @notice Full record at `index` (reverts if out of range).
|
|
function getRecord(uint256 index) external view returns (Record memory) {
|
|
return _records[index];
|
|
}
|
|
}
|