aere-research/pq-finality-circuit/scripts/gen_vectors.mjs
Aere Network 4a0b48588c 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:30 +03:00

104 lines
3.6 KiB
JavaScript

// gen_vectors.mjs
//
// Generate `xmss-verify-core/src/vectors.rs` from the OFFICIAL RFC 8391
// XMSS-SHA2_10_256 known-answer vector committed at
// aerenew/contracts/test/fixtures/xmss-sha2_10_256-kat.json
// (github.com/XMSS/xmss-reference deterministic test/vectors.c, oid=1, idx=512, msg=0x25).
//
// This exists so the Rust test vector is provably DERIVED from the committed
// official fixture, with no hand transcription of the 67 WOTS+ chains and 10
// authentication-path nodes. Run:
// node scripts/gen_vectors.mjs
//
// Deterministic: same input JSON -> byte-identical vectors.rs.
import { readFileSync, writeFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
const here = dirname(fileURLToPath(import.meta.url));
const katPath = resolve(
here,
"../../../contracts/test/fixtures/xmss-sha2_10_256-kat.json"
);
const outPath = resolve(here, "../xmss-verify-core/src/vectors.rs");
const kat = JSON.parse(readFileSync(katPath, "utf8"));
const strip = (h) => h.replace(/^0x/, "");
const bytes = (h) => {
const s = strip(h);
if (s.length % 2 !== 0) throw new Error(`odd hex: ${h}`);
const out = [];
for (let i = 0; i < s.length; i += 2) out.push(parseInt(s.slice(i, i + 2), 16));
return out;
};
const arr32 = (h) => {
const b = bytes(h);
if (b.length !== 32) throw new Error(`expected 32 bytes, got ${b.length}: ${h}`);
return b;
};
const fmtHash = (b) =>
"[" + b.map((x) => "0x" + x.toString(16).padStart(2, "0")).join(", ") + "]";
const fmtHashArray = (list, indent) =>
list.map((h) => `${indent}${fmtHash(arr32(h))},`).join("\n");
const msgBytes = bytes(kat.msg);
if (kat.wots.length !== 67) throw new Error(`expected 67 WOTS chains, got ${kat.wots.length}`);
if (kat.auth.length !== 10) throw new Error(`expected 10 auth nodes, got ${kat.auth.length}`);
const out = `// GENERATED by scripts/gen_vectors.mjs from the OFFICIAL committed KAT
// aerenew/contracts/test/fixtures/xmss-sha2_10_256-kat.json
// Source: ${kat.source}
// Do NOT edit by hand: re-run \`node scripts/gen_vectors.mjs\`.
//
// RFC 8391 XMSS-SHA2_10_256 (OID 0x00000001): n=32, w=16, len=67, h=10, SHA-256.
// This is the same official reference vector the on-chain AereXmssVerifier.sol and
// its independent JS oracle (contracts/test/xmssVerifier.test.js) are validated with.
use crate::{Hash, XmssPubKey, XmssSig, H, LEN};
/// Long-term XMSS public root (first 32 bytes of the XMSS public key).
pub const PUB_ROOT: Hash = ${fmtHash(arr32(kat.pubRoot))};
/// XMSS public SEED (last 32 bytes of the XMSS public key).
pub const PUB_SEED: Hash = ${fmtHash(arr32(kat.pubSeed))};
/// Leaf index used by the signer for this signature.
pub const IDX: u32 = ${kat.idx};
/// Per-signature randomizer R (from the signature).
pub const R: Hash = ${fmtHash(arr32(kat.R))};
/// The signed message bytes.
pub const MSG: [u8; ${msgBytes.length}] = ${fmtHash(msgBytes)};
/// The 67 WOTS+ one-time-signature chain values.
pub const WOTS: [Hash; LEN] = [
${fmtHashArray(kat.wots, " ")}
];
/// The h = 10 Merkle authentication-path nodes.
pub const AUTH: [Hash; H] = [
${fmtHashArray(kat.auth, " ")}
];
/// The official reference public key as a [\`XmssPubKey\`].
pub fn official_pubkey() -> XmssPubKey {
XmssPubKey { root: PUB_ROOT, seed: PUB_SEED }
}
/// The official reference signature as a [\`XmssSig\`].
pub fn official_sig() -> XmssSig {
XmssSig { idx: IDX, r: R, wots: WOTS, auth: AUTH }
}
`;
writeFileSync(outPath, out);
console.log(`wrote ${outPath}`);
console.log(` pubRoot ${kat.pubRoot}`);
console.log(` idx ${kat.idx}, msg ${kat.msg}, ${kat.wots.length} WOTS chains, ${kat.auth.length} auth nodes`);