import { describe, expect, it } from "vitest"; import { CHIRP_MAGIC_BYTES, CHIRP_PAYLOAD_LENGTH, CHIRP_PROTOCOL_VERSION, DEVICE_TYPE_ANDROID, DEVICE_TYPE_EXTENSION, } from "./sync-types"; import { ChirpDecodeError, crc32, decodeChirpPayload, encodeChirpPayload, } from "./chirp-payload"; function fixedPayload() { return { version: CHIRP_PROTOCOL_VERSION, deviceType: DEVICE_TYPE_EXTENSION, ephemeralPublicKey: Uint8Array.from( Array.from({ length: 32 }, (_, i) => (i * 7 + 11) & 0xff), ), sessionNonce: Uint8Array.from( Array.from({ length: 16 }, (_, i) => (i * 31 + 1) & 0xff), ), }; } describe("crc32", () => { it("matches known IEEE 802.3 vectors", () => { expect(crc32(new Uint8Array())).toBe(0x00000000); expect(crc32(new TextEncoder().encode("123456789"))).toBe(0xcbf43926); expect(crc32(new TextEncoder().encode("a"))).toBe(0xe8b7be43); }); }); describe("chirp payload codec", () => { it("round-trips identity for a fixed payload", () => { const original = fixedPayload(); const bytes = encodeChirpPayload(original); expect(bytes.length).toBe(CHIRP_PAYLOAD_LENGTH); const decoded = decodeChirpPayload(bytes); expect(decoded.version).toBe(original.version); expect(decoded.deviceType).toBe(original.deviceType); expect(decoded.ephemeralPublicKey).toEqual(original.ephemeralPublicKey); expect(decoded.sessionNonce).toEqual(original.sessionNonce); }); it("writes magic bytes PEAC at offset 0", () => { const bytes = encodeChirpPayload(fixedPayload()); expect(bytes.subarray(0, 4)).toEqual(CHIRP_MAGIC_BYTES); }); it("zero-fills the reserved padding region", () => { const bytes = encodeChirpPayload(fixedPayload()); for (let i = 58; i < 64; i++) expect(bytes[i]).toBe(0); }); it("rejects wrong-length input", () => { expect(() => decodeChirpPayload(new Uint8Array(63))).toThrow(ChirpDecodeError); expect(() => decodeChirpPayload(new Uint8Array(65))).toThrow(ChirpDecodeError); }); it("rejects bad magic", () => { const bytes = encodeChirpPayload(fixedPayload()); bytes[0] = 0; expect(() => decodeChirpPayload(bytes)).toThrow(/magic/); }); it("rejects unsupported version", () => { const bytes = encodeChirpPayload(fixedPayload()); bytes[4] = 0xff; // CRC will also fail, but version is checked first expect(() => decodeChirpPayload(bytes)).toThrow(/version/); }); it("rejects unknown device type", () => { const bytes = encodeChirpPayload(fixedPayload()); bytes[5] = 0x09; expect(() => decodeChirpPayload(bytes)).toThrow(/device type/); }); it("rejects checksum tamper", () => { const bytes = encodeChirpPayload(fixedPayload()); bytes[10] ^= 1; // flip a pubkey bit expect(() => decodeChirpPayload(bytes)).toThrow(/CRC32/); }); it("rejects non-zero padding", () => { const bytes = encodeChirpPayload(fixedPayload()); // Mutate padding then re-patch CRC over the first 54 bytes so that the // padding check is reached rather than failing at CRC first. bytes[63] = 0xab; const fresh = crc32(bytes.subarray(0, 54)); bytes[54] = (fresh >>> 24) & 0xff; bytes[55] = (fresh >>> 16) & 0xff; bytes[56] = (fresh >>> 8) & 0xff; bytes[57] = fresh & 0xff; expect(() => decodeChirpPayload(bytes)).toThrow(/padding/); }); it("encodes android device type byte", () => { const bytes = encodeChirpPayload({ ...fixedPayload(), deviceType: DEVICE_TYPE_ANDROID }); expect(bytes[5]).toBe(0x02); }); });