123456import { describe, expect, it } from "vitest";7import { generateKeyPair } from "@stablelib/x25519";8import {9 computeAuthProof,10 hexToBytes,11 isSmallOrderPubkey,12 noiseKKInitiator,13 performResponderAuth,14} from "./noise-js";15import type { NoiseNKSession } from "./noise-js";1617const SMALL_ORDER_PUBKEY_HEX = [18 "00".repeat(32),19 "01" + "00".repeat(31),20 "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",21 "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",22 "ec" + "ff".repeat(30) + "7f",23 "ed" + "ff".repeat(30) + "7f",24 "ee" + "ff".repeat(30) + "7f",25 "cdeb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",26 "4c9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",27];2829const deadTransport = {30 send: async () => undefined,31 receive: () => new Promise<Uint8Array>(() => undefined),32};3334describe("PB-26-014 follow-up — JS-side small-order X25519 rejection", () => {35 it("flags all nine small-order u-coordinates; a real generated key passes", () => {36 for (const hex of SMALL_ORDER_PUBKEY_HEX) {37 expect(isSmallOrderPubkey(hexToBytes(hex))).toBe(true);38 }39 expect(isSmallOrderPubkey(generateKeyPair().publicKey)).toBe(false);40 });4142 it("KK initiator aborts against a small-order responder static", async () => {43 const initiator = generateKeyPair();44 for (const hex of SMALL_ORDER_PUBKEY_HEX) {45 await expect(46 noiseKKInitiator(47 initiator.secretKey,48 initiator.publicKey,49 hexToBytes(hex),50 deadTransport.send,51 deadTransport.receive,52 ),53 ).rejects.toThrow(/small-order/i);54 }55 });5657 it("computeAuthProof refuses a small-order responder key", () => {58 const initiator = generateKeyPair();59 const nonce = new Uint8Array(32);60 const handshakeHash = new Uint8Array(32);61 expect(() =>62 computeAuthProof(63 initiator.secretKey,64 initiator.publicKey,65 hexToBytes(SMALL_ORDER_PUBKEY_HEX[3]!),66 nonce,67 handshakeHash,68 ),69 ).toThrow(/small-order/i);70 });7172 it("performResponderAuth refuses a PROOF frame with a small-order initiator key", async () => {73 const responder = generateKeyPair();74 const session = { handshakeHash: new Uint8Array(32) } as NoiseNKSession;75 const proofFrame = new TextEncoder().encode(76 JSON.stringify({77 type: "PROOF",78 initiator_public_key_hex: SMALL_ORDER_PUBKEY_HEX[0],79 proof_hex: "00".repeat(32),80 }),81 );82 await expect(83 performResponderAuth(84 session,85 responder.secretKey,86 responder.publicKey,87 async () => undefined,88 async () => proofFrame,89 ),90 ).rejects.toThrow(/small-order/i);91 });92});