aere-contracts/contracts/pqc/AereLatticeVerifier.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

89 lines
3.8 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
/**
* @title AereLatticeVerifier — lattice PQC verification core (Falcon/Dilithium family)
* @notice The mathematical HEART of lattice-based post-quantum signature
* verification, on-chain: negacyclic polynomial arithmetic in the ring
* R_q = Z_q[x]/(x^n + 1) with q = 12289 (the Falcon modulus), plus the
* short-vector (Euclidean norm) bound check.
*
* Given a public polynomial `h`, a challenge polynomial `c` (in Falcon,
* c = HashToPoint(nonce || message)), and a candidate signature
* (`s1`, `s2`), it checks the Falcon verification relation
* s1 == c - s2 * h (mod q, in the ring)
* and that (s1, s2) is a SHORT vector: ||(s1,s2)||^2 <= bound. A short
* solution only exists to someone holding the NTRU trapdoor, which is
* hard for classical AND quantum computers — that is the post-quantum
* security.
*
* HONEST SCOPE: this is the ring-arithmetic + norm core, parameterised
* by n (demo at 256; Falcon uses 512/1024). A SPEC-COMPLETE Falcon-512
* verifier additionally needs SHAKE-256 HashToPoint, Falcon's compressed
* signature decoding, and validation against NIST KAT vectors — a
* separate, larger effort. This contract proves AERE can do the lattice
* math on-chain; it is NOT a drop-in NIST Falcon-512 verifier.
*/
contract AereLatticeVerifier {
uint256 public constant Q = 12289; // Falcon modulus
uint256 public constant N = 64; // ring degree (demo; Falcon = 512/1024 via NTT)
/// @notice Negacyclic polynomial multiplication a*b in Z_q[x]/(x^n + 1).
function ringMul(uint256[] calldata a, uint256[] calldata b) public pure returns (uint256[] memory t) {
require(a.length == N && b.length == N, "len");
t = new uint256[](N);
for (uint256 i = 0; i < N; i++) {
uint256 ai = a[i];
if (ai == 0) continue;
for (uint256 j = 0; j < N; j++) {
uint256 p = mulmod(ai, b[j], Q);
uint256 k = i + j;
if (k < N) {
t[k] = addmod(t[k], p, Q);
} else {
// x^n = -1 => subtract into position k-n
t[k - N] = addmod(t[k - N], Q - p, Q);
}
}
}
}
/// @notice Squared Euclidean norm of a polynomial with coefficients centered
/// into (-q/2, q/2].
function normSq(uint256[] calldata v) public pure returns (uint256 s) {
for (uint256 i = 0; i < v.length; i++) {
uint256 x = v[i] % Q;
int256 c = x <= Q / 2 ? int256(x) : int256(x) - int256(Q);
s += uint256(c * c);
}
}
/**
* @notice Verify the Falcon-family lattice relation + short-vector bound.
* @param h public polynomial (n coeffs)
* @param c challenge polynomial (n coeffs) — Falcon: HashToPoint(msg)
* @param s1 signature part 1 (n coeffs)
* @param s2 signature part 2 (n coeffs)
* @param bound ||(s1,s2)||^2 must be <= bound
*/
function verify(
uint256[] calldata h,
uint256[] calldata c,
uint256[] calldata s1,
uint256[] calldata s2,
uint256 bound
) external pure returns (bool) {
require(h.length == N && c.length == N && s1.length == N && s2.length == N, "len");
// s2 * h
uint256[] memory t = ringMul(s2, h);
// s1 must equal c - s2*h (mod q)
for (uint256 i = 0; i < N; i++) {
uint256 expected = addmod(c[i] % Q, Q - t[i], Q); // (c - t) mod q
if (s1[i] % Q != expected) return false;
}
// short-vector bound
if (normSq(s1) + normSq(s2) > bound) return false;
return true;
}
}