CodexCodecTest.kt

2.7 KB · raw

1package com.peachpasswords.codex23import org.junit.Assert.assertArrayEquals4import org.junit.Assert.assertEquals5import org.junit.Assert.assertTrue6import org.junit.Test7import kotlin.random.Random89class CodexCodecTest {1011    @Test fun rs_recovers_dropped_shards() {12        val data = 613        val parity = computeParityShards(data) // 214        val size = 4015        val rng = Random(7)16        val original = Array(data) { ByteArray(size) { rng.nextInt().toByte() } }17        val shards = Array(data + parity) { i -> if (i < data) original[i].copyOf() else ByteArray(size) }18        ReedSolomon.encode(shards, data, parity)1920        // Drop `parity` shards (the max tolerable) — here drop 2 data shards.21        val present = BooleanArray(data + parity) { true }22        shards[1] = ByteArray(0); present[1] = false23        shards[4] = ByteArray(0); present[4] = false24        ReedSolomon.reconstruct(shards, data, parity, present)2526        for (i in 0 until data) assertArrayEquals("shard $i", original[i], shards[i])27    }2829    @Test fun gf_mul_div_are_inverse() {30        for (a in 1..255) for (b in 1..255) {31            assertEquals(a, Galois.div(Galois.mul(a, b), b))32        }33    }3435    @Test fun full_codec_round_trip() {36        val payload = CodexPayload(37            version = 2, verifyCode = "PX-AB12-CD34",38            vaultBlob = "x".repeat(5000), timestamp = 111, entryCount = 7,39            vaultFingerprint = "DEADBEEF".repeat(4), generatedAt = 222,40        )41        val bytes = CodexCodec.json.encodeToString(CodexPayload.serializer(), payload).toByteArray()42        val compressed = CodexCodec.deflate(bytes)43        assertArrayEquals(bytes, CodexCodec.inflate(compressed))4445        val (envelopes, layout) = CodexCodec.encodeToEnvelopes(compressed, payload.verifyCode)46        assertTrue(envelopes.all { CodexCodec.verifyChunkIntegrity(it) })47        assertEquals(layout.dataChunks + layout.parityChunks, envelopes.size)4849        // Lose the maximum tolerable codes in stripe 0, then rebuild.50        val parity = layout.parityChunks / layout.stripeCount51        val survivors = envelopes.toMutableList()52        repeat(parity) { survivors.removeAt(0) } // drop first `parity` data shards53        val recovered = CodexCodec.reconstructCompressed(survivors)54        val parsed = CodexCodec.json.decodeFromString(CodexPayload.serializer(), String(CodexCodec.inflate(recovered)))55        assertEquals(payload, parsed)56    }5758    @Test fun corrupted_chunk_fails_integrity() {59        val (envelopes, _) = CodexCodec.encodeToEnvelopes(CodexCodec.deflate("hello world".toByteArray()), "PX-0000-0000")60        val tampered = envelopes.first().copy(d = CodexCodec.base64Url("tampered".toByteArray()))61        assertTrue(!CodexCodec.verifyChunkIntegrity(tampered))62    }63}