1import { describe, it, expect } from "vitest";2import {3 reedSolomonEncode,4 reedSolomonDecode,5 RS_BLOCK_DATA,6 RS_BLOCK_PARITY,7 RS_BLOCK_TOTAL,8} from "./rs";910function randomBytes(n: number): Uint8Array {11 const out = new Uint8Array(n);12 for (let i = 0; i < n; i++) out[i] = (Math.random() * 256) | 0;13 return out;14}1516function corruptBytes(buf: Uint8Array, n: number): Uint8Array {17 const out = new Uint8Array(buf);18 const positions = new Set<number>();19 while (positions.size < n) {20 positions.add((Math.random() * buf.length) | 0);21 }22 for (const p of positions) out[p] ^= ((Math.random() * 255) | 0) + 1;23 return out;24}2526describe("Reed-Solomon RS(255,178)", () => {27 it("constants are coherent", () => {28 expect(RS_BLOCK_DATA + RS_BLOCK_PARITY).toBe(RS_BLOCK_TOTAL);29 expect(RS_BLOCK_TOTAL).toBe(255);30 });3132 it("round-trips a small payload (no errors)", () => {33 const data = new Uint8Array([0x4d, 0x01, 0x05, 0x00, 1, 2, 3, 4, 5]);34 const encoded = reedSolomonEncode(data);35 expect(encoded.length).toBe(RS_BLOCK_TOTAL); 36 const decoded = reedSolomonDecode(encoded, data.length);37 expect(Array.from(decoded)).toEqual(Array.from(data));38 });3940 it("round-trips a multi-block payload (no errors)", () => {41 const data = randomBytes(RS_BLOCK_DATA * 3 + 17);42 const encoded = reedSolomonEncode(data);43 expect(encoded.length).toBe(RS_BLOCK_TOTAL * 4); 44 const decoded = reedSolomonDecode(encoded, data.length);45 expect(Array.from(decoded)).toEqual(Array.from(data));46 });4748 it("corrects 1 byte error per block", () => {49 const data = randomBytes(RS_BLOCK_DATA);50 const encoded = reedSolomonEncode(data);51 const corrupted = corruptBytes(encoded, 1);52 const decoded = reedSolomonDecode(corrupted, data.length);53 expect(Array.from(decoded)).toEqual(Array.from(data));54 });5556 it("corrects up to floor(parity/2) byte errors per block", () => {57 const data = randomBytes(RS_BLOCK_DATA);58 const encoded = reedSolomonEncode(data);59 60 const corrupted = corruptBytes(encoded, 38);61 const decoded = reedSolomonDecode(corrupted, data.length);62 expect(Array.from(decoded)).toEqual(Array.from(data));63 });6465 it("fails when more than floor(parity/2) errors per block", () => {66 const data = randomBytes(RS_BLOCK_DATA);67 const encoded = reedSolomonEncode(data);68 const corrupted = corruptBytes(encoded, 50); 69 expect(() => reedSolomonDecode(corrupted, data.length)).toThrow(/uncorrectable/);70 });7172 it("handles empty payload", () => {73 const encoded = reedSolomonEncode(new Uint8Array(0));74 expect(encoded.length).toBe(0);75 const decoded = reedSolomonDecode(encoded, 0);76 expect(decoded.length).toBe(0);77 });7879 it("rejects malformed received length", () => {80 expect(() =>81 reedSolomonDecode(new Uint8Array(RS_BLOCK_TOTAL + 1), 10),82 ).toThrow(/not a multiple/);83 });84});