package com.peachpasswords.codex import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test import kotlin.random.Random class CodexCodecTest { @Test fun rs_recovers_dropped_shards() { val data = 6 val parity = computeParityShards(data) // 2 val size = 40 val rng = Random(7) val original = Array(data) { ByteArray(size) { rng.nextInt().toByte() } } val shards = Array(data + parity) { i -> if (i < data) original[i].copyOf() else ByteArray(size) } ReedSolomon.encode(shards, data, parity) // Drop `parity` shards (the max tolerable) — here drop 2 data shards. val present = BooleanArray(data + parity) { true } shards[1] = ByteArray(0); present[1] = false shards[4] = ByteArray(0); present[4] = false ReedSolomon.reconstruct(shards, data, parity, present) for (i in 0 until data) assertArrayEquals("shard $i", original[i], shards[i]) } @Test fun gf_mul_div_are_inverse() { for (a in 1..255) for (b in 1..255) { assertEquals(a, Galois.div(Galois.mul(a, b), b)) } } @Test fun full_codec_round_trip() { val payload = CodexPayload( version = 2, verifyCode = "PX-AB12-CD34", vaultBlob = "x".repeat(5000), timestamp = 111, entryCount = 7, vaultFingerprint = "DEADBEEF".repeat(4), generatedAt = 222, ) val bytes = CodexCodec.json.encodeToString(CodexPayload.serializer(), payload).toByteArray() val compressed = CodexCodec.deflate(bytes) assertArrayEquals(bytes, CodexCodec.inflate(compressed)) val (envelopes, layout) = CodexCodec.encodeToEnvelopes(compressed, payload.verifyCode) assertTrue(envelopes.all { CodexCodec.verifyChunkIntegrity(it) }) assertEquals(layout.dataChunks + layout.parityChunks, envelopes.size) // Lose the maximum tolerable codes in stripe 0, then rebuild. val parity = layout.parityChunks / layout.stripeCount val survivors = envelopes.toMutableList() repeat(parity) { survivors.removeAt(0) } // drop first `parity` data shards val recovered = CodexCodec.reconstructCompressed(survivors) val parsed = CodexCodec.json.decodeFromString(CodexPayload.serializer(), String(CodexCodec.inflate(recovered))) assertEquals(payload, parsed) } @Test fun corrupted_chunk_fails_integrity() { val (envelopes, _) = CodexCodec.encodeToEnvelopes(CodexCodec.deflate("hello world".toByteArray()), "PX-0000-0000") val tampered = envelopes.first().copy(d = CodexCodec.base64Url("tampered".toByteArray())) assertTrue(!CodexCodec.verifyChunkIntegrity(tampered)) } @Test fun inflate_exactly_at_the_cap_round_trips() { val data = ByteArray(CodexCodec.MAX_INFLATED_BYTES.toInt()) // zeros compress to ~17 KB assertArrayEquals(data, CodexCodec.inflate(CodexCodec.deflate(data))) } @Test fun inflate_refuses_decompression_bombs() { val bomb = CodexCodec.deflate(ByteArray(CodexCodec.MAX_INFLATED_BYTES.toInt() + 1)) assertTrue("bomb compresses tiny", bomb.size < 64 * 1024) val error = try { CodexCodec.inflate(bomb) null } catch (e: CodexException) { e } assertEquals(CodexErrorCode.PAYLOAD_TOO_LARGE, error?.code) } }