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.
89 lines
3.8 KiB
Solidity
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;
|
|
}
|
|
}
|