// SPDX-License-Identifier: MIT // // Runnable demo: node examples/threshold-account-demo.mjs (after `npm run build`) // // End-to-end proof that the AereThresholdAccount SDK produces cryptographically valid // authorizing legs for a non-custodial t-of-n POST-QUANTUM account, using REAL Falcon-512 // signing/verification off-chain (the same envelope the live precompile verifies). It does not // touch a chain: it shows exactly what each committee member signs, that ANY t members authorize, // and that below-threshold or forged legs do not. import { getBytes } from 'ethers'; import { keygen, verifyLocal, SCHEME, signLeg, encodeLegs, thresholdExecChallenge } from '../dist/index.js'; const line = (s = '') => console.log(s); const SCH = SCHEME.FALCON512; const N = 3, T = 2; line('=== AERE non-custodial post-quantum threshold account — SDK demo (2-of-3 Falcon-512) ===\n'); // 1. A committee of 3 independent post-quantum keys (in production each lives on a separate device). const members = []; for (let i = 0; i < N; i++) { const kp = keygen(SCH, getBytes('0x' + (i + 1).toString(16).padStart(96, '0'))); // 48-byte seed, deterministic for the demo members.push({ memberIndex: i, publicKey: kp.publicKey, secretKey: kp.secretKey }); line(` member ${i}: Falcon-512 pubkey ${kp.publicKey.length} bytes`); } // 2. The account + the call to authorize. (Addresses are placeholders — this demo is off-chain.) const account = '0x1111111111111111111111111111111111111111'; const target = '0x2222222222222222222222222222222222222222'; const value = 0n; const data = '0xa1e78d8b'; // some function selector the account would call const nonce = 0n; // 3. The EXACT challenge every member must sign, derived byte-for-byte like the contract. const challenge = thresholdExecChallenge(account, nonce, target, value, data, 2800n); line(`\n exec challenge @ nonce ${nonce}: ${challenge}`); // 4. TWO members (0 and 2) each PQC-sign the challenge -> authorizing legs. const signers = [members[0], members[2]]; const legs = signers.map((m) => signLeg(SCH, { memberIndex: m.memberIndex, secretKey: m.secretKey }, challenge)); // 5. Verify every leg locally with REAL Falcon verification (what the precompile enforces on-chain). let ok = 0; for (const leg of legs) { const member = members[leg.memberIndex]; const valid = verifyLocal(SCH, getBytes(challenge), getBytes(leg.signature), member.publicKey); line(` leg from member ${leg.memberIndex}: real Falcon verify = ${valid}`); if (valid) ok++; } line(`\n distinct valid signers = ${ok} / threshold ${T} -> ${ok >= T ? 'AUTHORIZED' : 'REJECTED'}`); // 6. The abi-encoded blob / call args the account.executeThreshold(...) would receive. const blob = encodeLegs(legs); line(`\n encoded Leg[] (${(blob.length - 2) / 2} bytes) ready for executeThreshold(target,value,data,legs)`); // 7. Negative cases: below threshold, and a forged leg. const oneLeg = [legs[0]]; line(`\n below-threshold (1 leg): distinct valid ${oneLeg.length} < ${T} -> REJECTED (as expected)`); const forged = getBytes(legs[1].signature); forged[41] ^= 0x01; // flip a byte inside the Falcon esig const forgedValid = verifyLocal(SCH, getBytes(challenge), forged, members[2].publicKey); line(` forged leg: real Falcon verify = ${forgedValid} -> not counted (as expected)`); line('\n=== demo complete: any 2 of the 3 post-quantum keys authorize; 1 or a forgery does not. ===');