import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Base64; import java.util.ArrayList; import java.util.List; import java.util.Arrays; import java.math.BigInteger; import swiss.qpq.gajumaru.core.encoding.Base58; import swiss.qpq.gajumaru.core.encoding.RLP; import swiss.qpq.gajumaru.core.encoding.ApiEncoder; import swiss.qpq.gajumaru.core.formatting.GajuFormat; import swiss.qpq.gajumaru.core.crypto.Keccak256; import swiss.qpq.gajumaru.core.crypto.Blake2b; import swiss.qpq.gajumaru.core.crypto.Ed25519; import swiss.qpq.gajumaru.core.data.Id; import swiss.qpq.gajumaru.core.tools.CryptoUtils; public class Testinator { public static void main(String[] args) { if (args.length < 2) { System.out.println("Error: Provide the test suite name and the required arguments."); System.exit(1); } try { switch (args[0]) { case "base64" -> { System.out.print(base64(args[1])); } case "base58" -> { System.out.print(base58(args[1])); } case "base58_check" -> { System.out.print(base58_check(args[1])); } case "rlp" -> { System.out.print(rlp(args[1])); } case "rlp_stream" -> { System.out.print(rlp_stream(args[1])); } case "rlp_fail" -> { System.out.print(rlp_fail(args[1])); } case "gaju_format" -> { System.out.print(gaju_format(args[1])); } case "keccak256" -> { System.out.print(keccak256(args[1])); } case "blake2b" -> { System.out.print(blake2b(args[1])); } case "ed25519" -> { System.out.print(ed25519(args[1])); } case "ed25519_verify" -> { System.out.print(ed25519_verify(args[1])); } case "api_encode" -> { System.out.print(api_encode(args[1])); } case "id_serialization" -> { System.out.print(id_serialization(args[1])); } case "fe_parity" -> { System.out.print(fe_parity(args[1])); } case "reduce_parity" -> { System.out.print(reduce_parity(args[1])); } case "smb_parity" -> { System.out.print(smb_parity(args[1])); } case "femul_parity" -> { System.out.print(femul_parity(args[1])); } case "frombytes_parity" -> { System.out.print(frombytes_parity(args[1])); } case "ge_parity" -> { System.out.print(ge_parity(args[1], args[2])); } case "keccak" -> { byte[] in = CryptoUtils.hexToBin(args[1]); System.out.println(CryptoUtils.binToHex(Keccak256.hash(in))); } case "blake2b_direct" -> { byte[] in = CryptoUtils.hexToBin(args[1]); System.out.println(CryptoUtils.binToHex(Blake2b.hash(in))); } case "ak_encode" -> { byte[] in = CryptoUtils.hexToBin(args[1]); System.out.println(ApiEncoder.encode(ApiEncoder.Type.ACCOUNT_PUBKEY, in)); } case "ed25519_pub" -> { byte[] seed = CryptoUtils.hexToBin(args[1]); System.out.println(CryptoUtils.binToHex(Ed25519.publicKey(seed))); } case "id_serialize" -> { int tag = Integer.parseInt(args[1]); byte[] val = CryptoUtils.hexToBin(args[2]); Id id = new Id(Id.Tag.fromValue(tag), val); System.out.println(CryptoUtils.binToHex(id.serialize())); } default -> { System.out.println("Error: Unknown test suite or command: " + args[0]); System.exit(1); } } } catch (Exception e) { System.err.println("Error: " + e.getMessage()); e.printStackTrace(); System.exit(1); } } private static String ge_parity(String aHex, String bHex) throws IOException { byte[] a = CryptoUtils.hexToBin(aHex); byte[] b = CryptoUtils.hexToBin(bHex); Ed25519.Scratch sc = new Ed25519.Scratch(); Ed25519.Ge p1 = Ed25519.scalarMulBase(a, sc); Ed25519.Ge p2 = Ed25519.scalarMulBase(b, sc); Ed25519.Ge p3 = new Ed25519.Ge(); Ed25519.ge_add(p3, p1, p2, sc); byte[] res = Ed25519.compress(p3, sc); p1.wipe(); p2.wipe(); p3.wipe(); sc.wipe(); return CryptoUtils.binToHex(res) + "|||"; } private static String frombytes_parity(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "frombytes.test"); Path resPath = Path.of(workingPath, "frombytes.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String hex : lines) { if (hex.trim().isEmpty()) continue; byte[] in = CryptoUtils.hexToBin(hex); long[] h = new long[10]; Ed25519.fe_frombytes(h, in); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10; i++) { if (i > 0) sb.append(","); sb.append(h[i]); } results.add(sb.toString()); } Files.write(resPath, results); return resPath.toString(); } private static String femul_parity(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "femul.test"); Path resPath = Path.of(workingPath, "femul.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String line : lines) { if (line.trim().isEmpty()) continue; String[] parts = line.split("\\|"); byte[] a = CryptoUtils.hexToBin(parts[0]); byte[] b = CryptoUtils.hexToBin(parts[1]); long[] ha = new long[10], hb = new long[10]; Ed25519.fe_frombytes(ha, a); Ed25519.fe_frombytes(hb, b); long[] hr = new long[10]; Ed25519.fe_mul(hr, ha, hb, new long[19]); byte[] out = Ed25519.fe_contract(hr); results.add(CryptoUtils.binToHex(out)); } Files.write(resPath, results); return resPath.toString(); } private static String smb_parity(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "smb.test"); Path resPath = Path.of(workingPath, "smb.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String hex : lines) { if (hex.trim().isEmpty()) continue; byte[] in = CryptoUtils.hexToBin(hex); Ed25519.Scratch sc = new Ed25519.Scratch(); Ed25519.Ge p = Ed25519.scalarMulBase(in, sc); byte[] out = Ed25519.compress(p, sc); p.wipe(); sc.wipe(); results.add(CryptoUtils.binToHex(out)); } Files.write(resPath, results); return resPath.toString(); } private static String reduce_parity(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "reduce.test"); Path resPath = Path.of(workingPath, "reduce.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String hex : lines) { if (hex.trim().isEmpty()) continue; byte[] in = CryptoUtils.hexToBin(hex); byte[] s = Arrays.copyOf(in, 64); Ed25519.reduceScalar(s); byte[] out = Arrays.copyOf(s, 32); results.add(CryptoUtils.binToHex(out)); } Files.write(resPath, results); return resPath.toString(); } private static String fe_parity(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "fe.test"); Path resPath = Path.of(workingPath, "fe.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String hex : lines) { if (hex.trim().isEmpty()) continue; byte[] in = CryptoUtils.hexToBin(hex); long[] h = new long[10]; Ed25519.fe_frombytes(h, in); byte[] out = Ed25519.fe_contract(h); results.add(CryptoUtils.binToHex(out)); } Files.write(resPath, results); return resPath.toString(); } private static String base64(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "base64.test"); Path encPath = Path.of(workingPath, "base64.java.txt"); Path decPath = Path.of(workingPath, "base64.java.back"); byte[] rawB = Files.readAllBytes(testPath); byte[] encB = Base64.getEncoder().encode(rawB); Files.write(encPath, encB); byte[] readE = Files.readAllBytes(encPath); byte[] decB = Base64.getDecoder().decode(readE); Files.write(decPath, decB); return encPath.toString() + " " + decPath.toString(); } private static String base58(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "base58.test"); Path encPath = Path.of(workingPath, "base58.java.txt"); Path decPath = Path.of(workingPath, "base58.java.back"); byte[] rawB = Files.readAllBytes(testPath); String encS = Base58.encode(rawB); Files.write(encPath, encS.getBytes()); byte[] readE = Files.readAllBytes(encPath); String readS = new String(readE); byte[] decB = Base58.decode(readS); Files.write(decPath, decB); return encPath.toString() + " " + decPath.toString(); } private static String base58_check(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "base58_check.test"); Path encPath = Path.of(workingPath, "base58_check.java.txt"); Path decPath = Path.of(workingPath, "base58_check.java.back"); byte[] rawB = Files.readAllBytes(testPath); String encS = Base58.checkEncode(rawB); Files.write(encPath, encS.getBytes()); byte[] readE = Files.readAllBytes(encPath); String readS = new String(readE); byte[] decB = Base58.checkDecode(readS); Files.write(decPath, decB); return encPath.toString() + " " + decPath.toString(); } private static String rlp(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "rlp.test"); Path resPath = Path.of(workingPath, "rlp.java.back"); byte[] encB = Files.readAllBytes(testPath); RLP.RLP_Data decRLP = RLP.decode(encB); RLP.RLP_List root = decRLP.asList(); RLP.RLP_List sub = root.getItems().get(1).asList(); byte[] anchor = sub.getItems().get(1).asItem().getBytes(); byte[] reEnc = RLP.encode(decRLP); Files.write(resPath, reEnc); return new String(anchor) + "|" + resPath.toString(); } private static String rlp_stream(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "rlp_stream.test"); byte[] buffer = Files.readAllBytes(testPath); List hashes = new ArrayList<>(); int offset = 0; while (offset < buffer.length) { RLP.DecodeResult res = RLP.decodeFrom(buffer, offset); hashes.add(Integer.toString(res.data().hashCode())); // Just to verify we got objects offset += res.consumed(); } return Integer.toString(hashes.size()); } private static String rlp_fail(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "rlp_fail.test"); byte[] buffer = Files.readAllBytes(testPath); try { RLP.decode(buffer); return "SUCCESS"; } catch (RLP.RLPException e) { return "RLP_EXCEPTION: " + e.getMessage(); } catch (Exception e) { return "OTHER_EXCEPTION: " + e.getClass().getSimpleName(); } } private static String gaju_format(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "gaju_format.test"); Path resPath = Path.of(workingPath, "gaju_format.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String line : lines) { if (line.trim().isEmpty()) continue; String[] p = line.split("\\|"); String op = p[0]; switch (op) { case "amount" -> { GajuFormat.Type style = GajuFormat.Type.valueOf(p[1]); GajuFormat.Unit unit = GajuFormat.Unit.valueOf(p[2]); char sep = p[3].charAt(0); int span = Integer.parseInt(p[4]); BigInteger val = new BigInteger(p[5]); results.add(GajuFormat.amount(new GajuFormat.FormatSpec(style, unit, sep, span), val)); } case "approx" -> { GajuFormat.Type style = GajuFormat.Type.valueOf(p[1]); GajuFormat.Unit unit = GajuFormat.Unit.valueOf(p[2]); char sep = p[3].charAt(0); int span = Integer.parseInt(p[4]); BigInteger val = new BigInteger(p[5]); int prec = Integer.parseInt(p[6]); results.add(GajuFormat.approxAmount(new GajuFormat.FormatSpec(style, unit, sep, span), val, prec)); } case "read" -> { byte[] b = GajuFormat.read(p[1]); results.add(new BigInteger(b).toString()); } } } Files.write(resPath, results); return resPath.toString(); } private static String keccak256(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "keccak256.test"); Path resPath = Path.of(workingPath, "keccak256.java.txt"); byte[] input = Files.readAllBytes(testPath); byte[] hash = Keccak256.hash(input); Files.write(resPath, CryptoUtils.binToHex(hash).getBytes()); return resPath.toString(); } private static String blake2b(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "blake2b.test"); Path resPath = Path.of(workingPath, "blake2b.java.txt"); byte[] input = Files.readAllBytes(testPath); byte[] hash = Blake2b.hash(input); Files.write(resPath, CryptoUtils.binToHex(hash).getBytes()); return resPath.toString(); } private static String ed25519(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "ed25519.test"); Path resPath = Path.of(workingPath, "ed25519.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String line : lines) { if (line.trim().isEmpty()) continue; String[] parts = line.split("\\|"); byte[] seed = CryptoUtils.hexToBin(parts[0]); byte[] msg = CryptoUtils.hexToBin(parts[1]); byte[] pub = Ed25519.publicKey(seed); byte[] sig = Ed25519.sign(seed, msg); boolean verify = Ed25519.verify(pub, msg, sig); results.add(CryptoUtils.binToHex(pub) + "|" + CryptoUtils.binToHex(sig) + "|" + verify); CryptoUtils.wipe(seed); CryptoUtils.wipe(msg); CryptoUtils.wipe(pub); CryptoUtils.wipe(sig); } Files.write(resPath, results); return resPath.toString(); } private static String ed25519_verify(String workingPath) throws IOException { Path seedPath = Path.of(workingPath, "ed25519_seed.test"); Path msgPath = Path.of(workingPath, "ed25519_msg.test"); byte[] seed = CryptoUtils.hexToBin(Files.readString(seedPath).trim()); byte[] message = Files.readAllBytes(msgPath); byte[] pub = Ed25519.publicKey(seed); byte[] sig = Ed25519.sign(seed, message); boolean verify = Ed25519.verify(pub, message, sig); return CryptoUtils.binToHex(pub) + "|" + CryptoUtils.binToHex(sig) + "|" + verify; } private static String api_encode(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "api_encode.test"); Path resPath = Path.of(workingPath, "api_encode.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String line : lines) { if (line.trim().isEmpty()) continue; String[] p = line.split("\\|"); ApiEncoder.Type type = ApiEncoder.Type.valueOf(p[0]); byte[] payload = CryptoUtils.hexToBin(p[1]); results.add(ApiEncoder.encode(type, payload)); if (type == ApiEncoder.Type.ACCOUNT_SECKEY) { CryptoUtils.wipe(payload); } } Files.write(resPath, results); return resPath.toString(); } private static String id_serialization(String workingPath) throws IOException { Path testPath = Path.of(workingPath, "id_serialization.test"); Path resPath = Path.of(workingPath, "id_serialization.java.txt"); List lines = Files.readAllLines(testPath); List results = new ArrayList<>(); for (String line : lines) { if (line.trim().isEmpty()) continue; String[] p = line.split("\\|"); Id.Tag tag = Id.Tag.fromValue(Integer.parseInt(p[0])); byte[] val = CryptoUtils.hexToBin(p[1]); Id id = new Id(tag, val); results.add(CryptoUtils.binToHex(id.serialize())); } Files.write(resPath, results); return resPath.toString(); } }