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.
82 lines
3.8 KiB
Solidity
82 lines
3.8 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.23;
|
|
|
|
/**
|
|
* @title MockPQCPrecompile, TEST-ONLY faithful mock of the AERE native PQC precompiles
|
|
*
|
|
* @notice Hardhat has no PQC precompile, so tests install this at 0x0AE1..0x0AE4 via
|
|
* hardhat_setCode. It parses the input EXACTLY as the live Besu precompiles do
|
|
* (per their Java sources: AereFalconSupport / MLDSA44 / SLHDSA128s) and returns
|
|
* a RAW 32-byte word 0x..01 iff the embedded signature "commitment" matches
|
|
* keccak256(pk || message). This models the real semantics: valid iff a genuine
|
|
* signature by THIS key over THIS message. Any malformed or non-matching input
|
|
* returns a raw 32-byte 0x..00 (invalid). The raw (non-ABI-encoded) return byte
|
|
* layout is identical to the live precompiles, so the caller's
|
|
* `ret.length >= 32 && ret[31] == 0x01` check behaves as it does on mainnet.
|
|
*
|
|
* The parse offsets here are the precompiles' spec offsets, NOT copied from the
|
|
* contract under test, so a positive attest passing here proves the contract
|
|
* built the input at the correct offsets. The real encoding is separately proven
|
|
* against the LIVE mainnet precompile via eth_call.
|
|
*/
|
|
contract MockPQCPrecompile {
|
|
uint8 private immutable _scheme;
|
|
|
|
constructor(uint8 scheme_) {
|
|
_scheme = scheme_;
|
|
}
|
|
|
|
// No public functions other than fallback, so an input whose leading bytes look
|
|
// like a selector can never dispatch anywhere but the verifier.
|
|
fallback() external {
|
|
bool valid = _check(msg.data);
|
|
bytes32 w = valid ? bytes32(uint256(1)) : bytes32(0);
|
|
assembly {
|
|
mstore(0x0, w)
|
|
return(0x0, 32)
|
|
}
|
|
}
|
|
|
|
function _check(bytes calldata input) internal view returns (bool) {
|
|
if (_scheme == 1) return _checkFalcon(input, 897, 0x29);
|
|
if (_scheme == 2) return _checkFalcon(input, 1793, 0x2A);
|
|
if (_scheme == 3) return _checkFixed(input, 1312, 2420);
|
|
if (_scheme == 4) return _checkFixed(input, 32, 7856);
|
|
return false;
|
|
}
|
|
|
|
// Falcon: input = pk(pkLen) || sm ; sm = sigLen(2 BE) || nonce(40) || message || esig ;
|
|
// esig = esigHeader || compressedSig ; sigLen == esig.length. (mirrors AereFalconSupport.verify)
|
|
function _checkFalcon(bytes calldata input, uint256 pkLen, uint8 esigHeader) internal pure returns (bool) {
|
|
if (input.length <= pkLen) return false;
|
|
bytes calldata pk = input[0:pkLen];
|
|
bytes calldata sm = input[pkLen:];
|
|
if (sm.length < 2 + 40 + 2) return false;
|
|
uint256 sigLen = (uint256(uint8(sm[0])) << 8) | uint256(uint8(sm[1]));
|
|
if (sigLen < 2 || 2 + 40 + sigLen > sm.length) return false;
|
|
uint256 msgLen = sm.length - 2 - 40 - sigLen;
|
|
bytes calldata esig = sm[sm.length - sigLen:];
|
|
if (esig.length < 33) return false;
|
|
if (uint8(esig[0]) != esigHeader) return false;
|
|
bytes calldata message = sm[42:42 + msgLen];
|
|
bytes32 commitment = _load(esig, 1);
|
|
return commitment == keccak256(abi.encodePacked(pk, message));
|
|
}
|
|
|
|
// ML-DSA-44 / SLH-DSA-128s: input = pk(pkLen) || sig(sigLen) || message(rest).
|
|
function _checkFixed(bytes calldata input, uint256 pkLen, uint256 sigLen) internal pure returns (bool) {
|
|
if (input.length < pkLen + sigLen + 32) return false;
|
|
bytes calldata pk = input[0:pkLen];
|
|
bytes calldata sig = input[pkLen:pkLen + sigLen];
|
|
bytes calldata message = input[pkLen + sigLen:];
|
|
bytes32 commitment = _load(sig, 0);
|
|
return commitment == keccak256(abi.encodePacked(pk, message));
|
|
}
|
|
|
|
function _load(bytes calldata s, uint256 off) internal pure returns (bytes32 r) {
|
|
assembly {
|
|
r := calldataload(add(s.offset, off))
|
|
}
|
|
}
|
|
}
|