aboutsummaryrefslogtreecommitdiffstats
path: root/security-utils/src/test/java/com/yahoo/security/BaseNCodecTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'security-utils/src/test/java/com/yahoo/security/BaseNCodecTest.java')
-rw-r--r--security-utils/src/test/java/com/yahoo/security/BaseNCodecTest.java122
1 files changed, 122 insertions, 0 deletions
diff --git a/security-utils/src/test/java/com/yahoo/security/BaseNCodecTest.java b/security-utils/src/test/java/com/yahoo/security/BaseNCodecTest.java
new file mode 100644
index 00000000000..da67ea2dff3
--- /dev/null
+++ b/security-utils/src/test/java/com/yahoo/security/BaseNCodecTest.java
@@ -0,0 +1,122 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.security;
+
+import org.junit.jupiter.api.Test;
+
+import java.math.BigInteger;
+
+import static com.yahoo.security.ArrayUtils.hex;
+import static com.yahoo.security.ArrayUtils.toUtf8Bytes;
+import static com.yahoo.security.ArrayUtils.unhex;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * @author vekterli
+ */
+public class BaseNCodecTest {
+
+ private static void verifyRoundtrip(BaseNCodec codec, byte[] bytes, String expectedEncoded) {
+ String enc = codec.encode(bytes);
+ assertEquals(expectedEncoded, enc);
+ byte[] dec = codec.decode(enc);
+ assertEquals(hex(bytes), hex(dec));
+ }
+
+ private static void verifyRoundtrip(BaseNCodec codec, String str, String expectedEncoded) {
+ verifyRoundtrip(codec, toUtf8Bytes(str), expectedEncoded);
+ }
+
+ @Test
+ void decoding_chars_not_in_alphabet_throws() {
+ var b58 = Base58.codec();
+ // [0OIl] are not in Base58 alphabet, but within the alphabet LUT range
+ assertThrows(IllegalArgumentException.class, () -> b58.decode("233QC0"));
+ // '{' is one beyond 'z', which is the highest char in the LUT range
+ assertThrows(IllegalArgumentException.class, () -> b58.decode("233QC{"));
+ }
+
+ @Test
+ void alphabet_char_duplication_during_codec_setup_throws() {
+ assertThrows(IllegalArgumentException.class, () -> BaseNCodec.of("abcda"));
+ }
+
+ @Test
+ void base58_codec_test_cases_pass() {
+ var b58 = Base58.codec();
+ assertEquals(58, b58.base());
+ // https://datatracker.ietf.org/doc/html/draft-msporny-base58-03 test vectors:
+ verifyRoundtrip(b58, "Hello World!", "2NEpo7TZRRrLZSi2U");
+ verifyRoundtrip(b58, "The quick brown fox jumps over the lazy dog.",
+ "USm3fpXnKG5EUBx2ndxBDMPVciP5hGey2Jh4NDv6gmeo1LkMeiKrLJUUBk6Z");
+ verifyRoundtrip(b58, unhex("0000287fb4cd"), "11233QC4");
+
+ // Values that have been cross-referenced with other encoder implementations:
+ verifyRoundtrip(b58, "", "");
+ verifyRoundtrip(b58, unhex("00"), "1");
+ verifyRoundtrip(b58, unhex("0000"), "11");
+ verifyRoundtrip(b58, unhex("ff"), "5Q");
+ verifyRoundtrip(b58, unhex("00ff"), "15Q");
+ verifyRoundtrip(b58, unhex("ff00"), "LQX");
+ verifyRoundtrip(b58, unhex("ffffff"), "2UzHL");
+ verifyRoundtrip(b58, unhex("287fb4cd"), "233QC4");
+ }
+
+ @Test
+ void base62_codec_test_cases_pass() {
+ var b62 = Base62.codec();
+ assertEquals(62, b62.base());
+ verifyRoundtrip(b62, "Hello World!", "T8dgcjRGkZ3aysdN");
+ verifyRoundtrip(b62, "\0\0Hello World!", "00T8dgcjRGkZ3aysdN");
+ verifyRoundtrip(b62, "", "");
+ verifyRoundtrip(b62, unhex("00"), "0");
+ verifyRoundtrip(b62, unhex("0000"), "00");
+ verifyRoundtrip(b62, unhex("00000000ffffffff"), "00004gfFC3");
+ verifyRoundtrip(b62, unhex("ffffffff00000000"), "LygHZwPV2MC");
+ }
+
+ // Test with some common bases that are easier to reason about:
+
+ @Test
+ void codec_generalizes_down_to_base_10() {
+ var b10 = BaseNCodec.of("0123456789");
+ verifyRoundtrip(b10, unhex("00"), "0");
+ verifyRoundtrip(b10, unhex("000f"), "015");
+ verifyRoundtrip(b10, unhex("ffff"), "65535");
+
+ // A large prime number: 2^252 + 27742317777372353535851937790883648493 (Curve25519 order)
+ var numStr = "7237005577332262213973186563042994240857116359379907606001950938285454250989";
+ var numBN = new BigInteger(numStr);
+ verifyRoundtrip(b10, numBN.toByteArray(), numStr);
+ }
+
+ // Possibly world's most inefficient hex conversion?
+ @Test
+ void codec_generalizes_down_to_base_16() {
+ var b2 = BaseNCodec.of("0123456789ABCDEF");
+ assertEquals(16, b2.base());
+ verifyRoundtrip(b2, unhex(""), "");
+ verifyRoundtrip(b2, unhex("00"), "0");
+ verifyRoundtrip(b2, unhex("80"), "80");
+ verifyRoundtrip(b2, unhex("01"), "1");
+ verifyRoundtrip(b2, unhex("F0"), "F0");
+ verifyRoundtrip(b2, unhex("0F"), "F");
+ verifyRoundtrip(b2, unhex("F00F"), "F00F");
+ verifyRoundtrip(b2, unhex("5FAF"), "5FAF");
+ }
+
+ // Very likely genuinely the world's most inefficient binary conversion.
+ @Test
+ void codec_generalizes_down_to_base_2() {
+ var b2 = BaseNCodec.of("01");
+ assertEquals(2, b2.base());
+ verifyRoundtrip(b2, unhex(""), "");
+ verifyRoundtrip(b2, unhex("00"), "0");
+ verifyRoundtrip(b2, unhex("000000"), "000"); // note: prefix zero byte sentinels!
+ verifyRoundtrip(b2, unhex("80"), "10000000");
+ verifyRoundtrip(b2, unhex("01"), "1");
+ verifyRoundtrip(b2, unhex("F0"), "11110000");
+ verifyRoundtrip(b2, unhex("0F"), "1111");
+ }
+
+}