diff --git a/bin/auto-sync.txt b/bin/auto-sync.txt index db1ae412..4c42e16a 100644 --- a/bin/auto-sync.txt +++ b/bin/auto-sync.txt @@ -37,6 +37,7 @@ hamming hello-world high-scores house +intergalactic-transmission isbn-verifier isogram killer-sudoku-helper diff --git a/config.json b/config.json index 670d309a..3679ab3e 100644 --- a/config.json +++ b/config.json @@ -847,6 +847,14 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "intergalactic-transmission", + "name": "Intergalactic Transmission", + "uuid": "1e91fd0f-98ee-404c-ac69-fc6a012f6c1b", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "kindergarten-garden", "name": "Kindergarten Garden", diff --git a/exercises/practice/intergalactic-transmission/.docs/instructions.md b/exercises/practice/intergalactic-transmission/.docs/instructions.md new file mode 100644 index 00000000..54970881 --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.docs/instructions.md @@ -0,0 +1,54 @@ +# Instructions + +Your job is to help implement + +- the transmitter, which calculates the transmission sequence, and +- the receiver, which decodes it. + +A parity bit is simple way of detecting transmission errors. +The transmitters and receivers can only transmit and receive _exactly_ eight bits at a time (including the parity bit). +The parity bit is set so that there is an _even_ number of 1 bits in each transmission, and the parity bit is always the first bit from the right. +So if the receiver receives `11000001`, `01110101` or `01000000` (i.e. a transmission with an odd number of 1 bits), it knows there is an error. + +However, messages are rarely this short, and need to be transmitted in a sequence when they are longer. + +For example, consider the message `11000000 00000001 11000000 11011110` (or `C0 01 C0 DE` in hex). + +Since each transmission contains exactly eight bits, it can only contain seven bits of data and the parity bit. +A parity bit must then be inserted after every seven bits of data: + +```text +11000000 00000001 11000000 11011110 + ↑ ↑ ↑ ↑ (7th bits) +``` + +The transmission sequence for this message looks like this: + +```text +1100000_ 0000000_ 0111000_ 0001101_ 1110 + ↑ ↑ ↑ ↑ (parity bits) +``` + +The data in the first transmission in the sequence (`1100000`) has two 1 bits (an even number), so the parity bit is 0. +The first transmission becomes `11000000` (or `C0` in hex). + +The data in the next transmission (`0000000`) has zero 1 bits (an even number again), so the parity bit is 0 again. +The second transmission thus becomes `00000000` (or `00` in hex). + +The data for the next two transmissions (`0111000` and `0001101`) have three 1 bits. +Their parity bits are set to 1 so that they have an even number of 1 bits in the transmission. +They are transmitted as `01110001` and `00011011` (or `71` and `1B` in hex). + +The last transmission (`1110`) has only four bits of data. +Since exactly eight bits are transmitted at a time and the parity bit is the rightmost bit, three 0 bits and then the parity bit are added to make up eight bits. +It now looks like this (where `_` is the parity bit): + +```text +1110 000_ + ↑↑↑ (added 0 bits) +``` + +There is an odd number of 1 bits again, so the parity bit is 1. +The last transmission in the sequence becomes `11100001` (or `E1` in hex). + +The entire transmission sequence for this message is `11000000 00000000 01110001 00011011 11100001` (or `C0 00 71 1B E1` in hex). diff --git a/exercises/practice/intergalactic-transmission/.docs/introduction.md b/exercises/practice/intergalactic-transmission/.docs/introduction.md new file mode 100644 index 00000000..f19dffbe --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.docs/introduction.md @@ -0,0 +1,23 @@ +# Introduction + +Trillions upon trillions of messages zip between Earth and neighboring galaxies every millisecond. +But transmitting over such long distances is tricky. +Pesky solar flares, temporal distortions, stray forces, and even the flap of a space butterfly's wing can cause a random bit to change during transmission. + +Now imagine the consequences: + +- Crashing the Intergalactic Share Market when "buy low" turns to "sell now". +- Losing contact with the Kepler Whirl system when "save new worm hole" becomes "cave new worm hole". +- Or plunging the universe into existential horror by replacing a cowboy emoji 🤠 with a clown emoji 🤡. + +Detecting corrupted messages isn't just important — it's critical. +The receiver _must_ know when something has gone wrong before disaster strikes. + +But how? +Scientists and engineers from across the universe have been battling this problem for eons. +Entire cosmic AI superclusters churn through the data. +And then, one day, a legend resurfaces — an ancient, powerful method, whispered in debugging forums, muttered by engineers who've seen too much... + +The Parity Bit! + +A method so simple, so powerful, that it might just save interstellar communication. diff --git a/exercises/practice/intergalactic-transmission/.meta/config.json b/exercises/practice/intergalactic-transmission/.meta/config.json new file mode 100644 index 00000000..77ef73ca --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "resu-xuniL" + ], + "files": { + "solution": [ + "IntergalacticTransmission.php" + ], + "test": [ + "IntergalacticTransmissionTest.php" + ], + "example": [ + ".meta/example.php" + ] + }, + "blurb": "Add parity bits to a message for transmission", + "source": "Kah Goh", + "source_url": "https://github.com/exercism/problem-specifications/pull/2543" +} diff --git a/exercises/practice/intergalactic-transmission/.meta/example.php b/exercises/practice/intergalactic-transmission/.meta/example.php new file mode 100644 index 00000000..6708eaf1 --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.meta/example.php @@ -0,0 +1,58 @@ + sprintf('0x%02x', bindec($eightBit)), + array_map( + function ($sevenBit) { + $sevenBit = str_pad($sevenBit, 7, '0'); + substr_count($sevenBit, "1") % 2 === 0 ? $parityBit = "0" : $parityBit = "1"; + return $sevenBit . $parityBit; + }, + str_split( + implode( + '', + array_map( + fn ($hex) => sprintf('%08b', hexdec($hex)), + $sequence + ) + ), + 7 + ) + ) + ); +} + +function decodeMessage(array $message): array +{ + return array_map( + fn ($eightBit) => sprintf('0x%02x', bindec($eightBit)), + array_filter( + str_split( + implode( + '', + array_map( + function ($eightBit) { + if (substr_count($eightBit, "1") % 2 === 0) { + return substr($eightBit, 0, 7); + } else { + throw new Exception("Error: wrong parity"); + } + }, + array_map( + fn ($hex) => sprintf('%08b', hexdec($hex)), + $message + ) + ) + ), + 8 + ), + function ($eightBit) { + return strlen($eightBit) === 8; + } + ) + ); +} diff --git a/exercises/practice/intergalactic-transmission/.meta/tests.toml b/exercises/practice/intergalactic-transmission/.meta/tests.toml new file mode 100644 index 00000000..64a8aace --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.meta/tests.toml @@ -0,0 +1,88 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[f99d4046-b429-4582-9324-f0bcac7ab51c] +description = "calculate transmit sequences -> empty message" + +[ee27ea2d-8999-4f23-9275-8f6879545f86] +description = "calculate transmit sequences -> 0x00 is transmitted as 0x0000" + +[97f27f98-8020-402d-be85-f21ba54a6df0] +description = "calculate transmit sequences -> 0x02 is transmitted as 0x0300" + +[24712fb9-0336-4e2f-835e-d2350f29c420] +description = "calculate transmit sequences -> 0x06 is transmitted as 0x0600" + +[7630b5a9-dba1-4178-b2a0-4a376f7414e0] +description = "calculate transmit sequences -> 0x05 is transmitted as 0x0581" + +[ab4fe80b-ef8e-4a99-b4fb-001937af415d] +description = "calculate transmit sequences -> 0x29 is transmitted as 0x2881" + +[4e200d84-593b-4449-b7c0-4de1b6a0955e] +description = "calculate transmit sequences -> 0xc001c0de is transmitted as 0xc000711be1" + +[fbc537e9-6b21-4f4a-8c2b-9cf9b702a9b7] +description = "calculate transmit sequences -> six byte message" + +[d5b75adf-b5fc-4f77-b4ab-77653e30f07c] +description = "calculate transmit sequences -> seven byte message" + +[6d8b297b-da1d-435e-bcd7-55fbb1400e73] +description = "calculate transmit sequences -> eight byte message" + +[54a0642a-d5aa-490c-be89-8e171a0cab6f] +description = "calculate transmit sequences -> twenty byte message" + +[9a8084dd-3336-474c-90cb-8a852524604d] +description = "decode received messages -> empty message" + +[879af739-0094-4736-9127-bd441b1ddbbf] +description = "decode received messages -> zero message" + +[7a89eeef-96c5-4329-a246-ec181a8e959a] +description = "decode received messages -> 0x0300 is decoded to 0x02" + +[3e515af7-8b62-417f-960c-3454bca7f806] +description = "decode received messages -> 0x0581 is decoded to 0x05" + +[a1b4a3f7-9f05-4b7a-b86e-d7c6fc3f16a9] +description = "decode received messages -> 0x2881 is decoded to 0x29" + +[2e99d617-4c91-4ad5-9217-e4b2447d6e4a] +description = "decode received messages -> first byte has wrong parity" + +[507e212d-3dae-42e8-88b4-2223838ff8d2] +description = "decode received messages -> second byte has wrong parity" + +[b985692e-6338-46c7-8cea-bc38996d4dfd] +description = "decode received messages -> 0xcf4b00 is decoded to 0xce94" + +[7a1f4d48-696d-4679-917c-21b7da3ff3fd] +description = "decode received messages -> 0xe2566500 is decoded to 0xe2ad90" + +[467549dc-a558-443b-80c5-ff3d4eb305d4] +description = "decode received messages -> six byte message" + +[1f3be5fb-093a-4661-9951-c1c4781c71ea] +description = "decode received messages -> seven byte message" + +[6065b8b3-9dcd-45c9-918c-b427cfdb28c1] +description = "decode received messages -> last byte has wrong parity" + +[98af97b7-9cca-4c4c-9de3-f70e227a4cb1] +description = "decode received messages -> eight byte message" + +[aa7d4785-2bb9-43a4-a38a-203325c464fb] +description = "decode received messages -> twenty byte message" + +[4c86e034-b066-42ac-8497-48f9bc1723c1] +description = "decode received messages -> wrong parity on 16th byte" diff --git a/exercises/practice/intergalactic-transmission/IntergalacticTransmission.php b/exercises/practice/intergalactic-transmission/IntergalacticTransmission.php new file mode 100644 index 00000000..330f9e85 --- /dev/null +++ b/exercises/practice/intergalactic-transmission/IntergalacticTransmission.php @@ -0,0 +1,35 @@ +. + * + * To disable strict typing, comment out the directive below. + */ + +declare(strict_types=1); + +function transmitSequence(array $sequence): array +{ + throw new \BadFunctionCallException(sprintf('Implement the %s function', __FUNCTION__)); +} + +function decodeMessage(array $message): array +{ + throw new \BadFunctionCallException(sprintf('Implement the %s function', __FUNCTION__)); +} diff --git a/exercises/practice/intergalactic-transmission/IntergalacticTransmissionTest.php b/exercises/practice/intergalactic-transmission/IntergalacticTransmissionTest.php new file mode 100644 index 00000000..0106bc9e --- /dev/null +++ b/exercises/practice/intergalactic-transmission/IntergalacticTransmissionTest.php @@ -0,0 +1,458 @@ + Empty message')] + public function testCalculateTransmitSequencesEmptyMessage(): void + { + $message = []; + $expected = []; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: ee27ea2d-8999-4f23-9275-8f6879545f86 + */ + #[TestDox('Calculate transmit sequences -> 0x00 is transmitted as 0x0000')] + public function testCalculateTransmitSequences0x00IsTransmittedAs0x0000(): void + { + $message = ["0x00"]; + $expected = ["0x00", "0x00"]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: 97f27f98-8020-402d-be85-f21ba54a6df0 + */ + #[TestDox('Calculate transmit sequences -> 0x02 is transmitted as 0x0300')] + public function testCalculateTransmitSequences0x02IsTransmittedAs0x0300(): void + { + $message = ["0x02"]; + $expected = ["0x03", "0x00"]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: 24712fb9-0336-4e2f-835e-d2350f29c420 + */ + #[TestDox('Calculate transmit sequences -> 0x06 is transmitted as 0x0600')] + public function testCalculateTransmitSequences0x06IsTransmittedAs0x0600(): void + { + $message = ["0x06"]; + $expected = ["0x06", "0x00"]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: 7630b5a9-dba1-4178-b2a0-4a376f7414e0 + */ + #[TestDox('Calculate transmit sequences -> 0x05 is transmitted as 0x0581')] + public function testCalculateTransmitSequences0x05IsTransmittedAs0x0581(): void + { + $message = ["0x05"]; + $expected = ["0x05", "0x81"]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: ab4fe80b-ef8e-4a99-b4fb-001937af415d + */ + #[TestDox('Calculate transmit sequences -> 0x29 is transmitted as 0x2881')] + public function testCalculateTransmitSequences0x29IsTransmittedAs0x2881(): void + { + $message = ["0x29"]; + $expected = ["0x28", "0x81"]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: 4e200d84-593b-4449-b7c0-4de1b6a0955e + */ + #[TestDox('Calculate transmit sequences -> 0xc001c0de is transmitted as 0xc000711be1')] + public function testCalculateTransmitSequences0xc001c0deIsTransmittedAs0xc000711be1(): void + { + $message = ["0xc0", "0x01", "0xc0", "0xde"]; + $expected = ["0xc0", "0x00", "0x71", "0x1b", "0xe1"]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: fbc537e9-6b21-4f4a-8c2b-9cf9b702a9b7 + */ + #[TestDox('Calculate transmit sequences -> Six byte message')] + public function testCalculateTransmitSequencesSixByteMessage(): void + { + $message = ["0x47", "0x72", "0x65", "0x61", "0x74", "0x21"]; + $expected = ["0x47", "0xb8", "0x99", "0xac", "0x17", "0xa0", "0x84"]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: d5b75adf-b5fc-4f77-b4ab-77653e30f07c + */ + #[TestDox('Calculate transmit sequences -> Seven byte message')] + public function testCalculateTransmitSequencesSevenByteMessage(): void + { + $message = ["0x47", "0x72", "0x65", "0x61", "0x74", "0x31", "0x21"]; + $expected = ["0x47", "0xb8", "0x99", "0xac", "0x17", "0xa0", "0xc5", "0x42"]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: 6d8b297b-da1d-435e-bcd7-55fbb1400e73 + */ + #[TestDox('Calculate transmit sequences -> Eight byte message')] + public function testCalculateTransmitSequencesEightByteMessage(): void + { + $message = [ + "0xc0", + "0x01", + "0x13", + "0x37", + "0xc0", + "0xde", + "0x21", + "0x21" + ]; + $expected = [ + "0xc0", + "0x00", + "0x44", + "0x66", + "0x7d", + "0x06", + "0x78", + "0x42", + "0x21", + "0x81" + ]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: 54a0642a-d5aa-490c-be89-8e171a0cab6f + */ + #[TestDox('Calculate transmit sequences -> Twenty byte message')] + public function testCalculateTransmitSequencesTwentyByteMessage(): void + { + $message = [ + "0x45", + "0x78", + "0x65", + "0x72", + "0x63", + "0x69", + "0x73", + "0x6d", + "0x20", + "0x69", + "0x73", + "0x20", + "0x61", + "0x77", + "0x65", + "0x73", + "0x6f", + "0x6d", + "0x65", + "0x21" + ]; + $expected = [ + "0x44", + "0xbd", + "0x18", + "0xaf", + "0x27", + "0x1b", + "0xa5", + "0xe7", + "0x6c", + "0x90", + "0x1b", + "0x2e", + "0x33", + "0x03", + "0x84", + "0xee", + "0x65", + "0xb8", + "0xdb", + "0xed", + "0xd7", + "0x28", + "0x84" + ]; + $this->assertEquals($expected, transmitSequence($message)); + } + + /** + * uuid: 9a8084dd-3336-474c-90cb-8a852524604d + */ + #[TestDox('Decode received messages -> Empty message')] + public function testDecodeReceivedMessagesEmptyMessage(): void + { + $message = []; + $expected = []; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 879af739-0094-4736-9127-bd441b1ddbbf + */ + #[TestDox('Decode received messages -> Zero message')] + public function testDecodeReceivedMessagesZeroMessage(): void + { + $message = ["0x00", "0x00"]; + $expected = ["0x00"]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 7a89eeef-96c5-4329-a246-ec181a8e959a + */ + #[TestDox('Decode received messages -> 0x0300 is decoded to 0x02')] + public function testDecodeReceivedMessages0x0300IsDecodedTo0x02(): void + { + $message = ["0x03", "0x00"]; + $expected = ["0x02"]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 3e515af7-8b62-417f-960c-3454bca7f806 + */ + #[TestDox('Decode received messages -> 0x0581 is decoded to 0x05')] + public function testDecodeReceivedMessages0x0581IsDecodedTo0x05(): void + { + $message = ["0x05", "0x81"]; + $expected = ["0x05"]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: a1b4a3f7-9f05-4b7a-b86e-d7c6fc3f16a9 + */ + #[TestDox('Decode received messages -> 0x2881 is decoded to 0x29')] + public function testDecodeReceivedMessages0x2881IsDecodedTo0x29(): void + { + $message = ["0x28", "0x81"]; + $expected = ["0x29"]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 2e99d617-4c91-4ad5-9217-e4b2447d6e4a + */ + #[TestDox('Decode received messages -> First byte has wrong parity')] + public function testDecodeReceivedMessagesFirstByteHasWrongParity(): void + { + $message = ["0x07", "0x00"]; + $this->expectException(Exception::class); + $this->expectExceptionMessageMatches('/wrong parity/'); + decodeMessage($message); + } + + /** + * uuid: 507e212d-3dae-42e8-88b4-2223838ff8d2 + */ + #[TestDox('Decode received messages -> Second byte has wrong parity')] + public function testDecodeReceivedMessagesSecondByteHasWrongParity(): void + { + $message = ["0x03", "0x68"]; + $this->expectException(Exception::class); + $this->expectExceptionMessageMatches('/wrong parity/'); + decodeMessage($message); + } + + /** + * uuid: b985692e-6338-46c7-8cea-bc38996d4dfd + */ + #[TestDox('Decode received messages -> 0xcf4b00 is decoded to 0xce94')] + public function testDecodeReceivedMessages0xcf4b00IsDecodedTo0xce94(): void + { + $message = ["0xcf", "0x4b", "0x00"]; + $expected = ["0xce", "0x94"]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 7a1f4d48-696d-4679-917c-21b7da3ff3fd + */ + #[TestDox('Decode received messages -> 0xe2566500 is decoded to 0xe2ad90')] + public function testDecodeReceivedMessages0xe2566500IsDecodedTo0xe2ad90(): void + { + $message = ["0xe2", "0x56", "0x65", "0x00"]; + $expected = ["0xe2", "0xad", "0x90"]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 467549dc-a558-443b-80c5-ff3d4eb305d4 + */ + #[TestDox('Decode received messages -> Six byte message')] + public function testDecodeReceivedMessagesSixByteMessage(): void + { + $message = ["0x47", "0xb8", "0x99", "0xac", "0x17", "0xa0", "0x84"]; + $expected = ["0x47", "0x72", "0x65", "0x61", "0x74", "0x21"]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 1f3be5fb-093a-4661-9951-c1c4781c71ea + */ + #[TestDox('Decode received messages -> Seven byte message')] + public function testDecodeReceivedMessagesSevenByteMessage(): void + { + $message = ["0x47", "0xb8", "0x99", "0xac", "0x17", "0xa0", "0xc5", "0x42"]; + $expected = ["0x47", "0x72", "0x65", "0x61", "0x74", "0x31", "0x21"]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 6065b8b3-9dcd-45c9-918c-b427cfdb28c1 + */ + #[TestDox('Decode received messages -> Last byte has wrong parity')] + public function testDecodeReceivedMessagesLastByteHasWrongParity(): void + { + $message = ["0x47", "0xb8", "0x99", "0xac", "0x17", "0xa0", "0xc5", "0x43"]; + $this->expectException(Exception::class); + $this->expectExceptionMessageMatches('/wrong parity/'); + decodeMessage($message); + } + + /** + * uuid: 98af97b7-9cca-4c4c-9de3-f70e227a4cb1 + */ + #[TestDox('Decode received messages -> Eight byte message')] + public function testDecodeReceivedMessagesEightByteMessage(): void + { + $message = [ + "0xc0", + "0x00", + "0x44", + "0x66", + "0x7d", + "0x06", + "0x78", + "0x42", + "0x21", + "0x81" + ]; + $expected = [ + "0xc0", + "0x01", + "0x13", + "0x37", + "0xc0", + "0xde", + "0x21", + "0x21" + ]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: aa7d4785-2bb9-43a4-a38a-203325c464fb + */ + #[TestDox('Decode received messages -> Twenty byte message')] + public function testDecodeReceivedMessagesTwentyByteMessage(): void + { + $message = [ + "0x44", + "0xbd", + "0x18", + "0xaf", + "0x27", + "0x1b", + "0xa5", + "0xe7", + "0x6c", + "0x90", + "0x1b", + "0x2e", + "0x33", + "0x03", + "0x84", + "0xee", + "0x65", + "0xb8", + "0xdb", + "0xed", + "0xd7", + "0x28", + "0x84" + ]; + $expected = [ + "0x45", + "0x78", + "0x65", + "0x72", + "0x63", + "0x69", + "0x73", + "0x6d", + "0x20", + "0x69", + "0x73", + "0x20", + "0x61", + "0x77", + "0x65", + "0x73", + "0x6f", + "0x6d", + "0x65", + "0x21" + ]; + $this->assertEquals($expected, decodeMessage($message)); + } + + /** + * uuid: 4c86e034-b066-42ac-8497-48f9bc1723c1 + */ + #[TestDox('Decode received messages -> Wrong parity on 16th byte')] + public function testDecodeReceivedMessagesWrongParityOn16thByte(): void + { + $message = [ + "0x44", + "0xbd", + "0x18", + "0xaf", + "0x27", + "0x1b", + "0xa5", + "0xe7", + "0x6c", + "0x90", + "0x1b", + "0x2e", + "0x33", + "0x03", + "0x84", + "0xef", + "0x65", + "0xb8", + "0xdb", + "0xed", + "0xd7", + "0x28", + "0x84" + ]; + $this->expectException(Exception::class); + $this->expectExceptionMessageMatches('/wrong parity/'); + decodeMessage($message); + } +}