package unit; import java.util.HashMap; /** * wolfssl-0001 unit test * * Models the O(C×S) ALPN selection in ALPN_find_match() / TLSX_ALPN_Find() * and the O(C+S) fixed version using a hash set of server names. * * Compile: javac -d . WolfSslAlpnFindTest.java * Run: java unit.WolfSslAlpnFindTest */ public class WolfSslAlpnFindTest { // ------------------------------------------------------------------ // // Model TLSX_ALPN_Find: O(S) linear scan of server linked list // // ------------------------------------------------------------------ // static String tlsxAlpnFind(String[] serverList, String name) { for (String s : serverList) { if (s.length() == name.length() && s.equals(name)) return s; } return null; } // ------------------------------------------------------------------ // // DEFECTIVE: O(C × S) — ALPN_find_match calls TLSX_ALPN_Find(O(S)) // // for each of C client-offered names // // ------------------------------------------------------------------ // static String defectiveMatch(String[] serverList, String[] clientNames) { // Outer: iterate client list (wolfSSL uses client-preference order) for (String clientName : clientNames) { // Inner: TLSX_ALPN_Find — O(S) scan String found = tlsxAlpnFind(serverList, clientName); if (found != null) return found; } return null; } // ------------------------------------------------------------------ // // FIXED: O(C + S) — hash set of server names, O(1) lookup // // ------------------------------------------------------------------ // static String fixedMatch(String[] serverList, String[] clientNames) { // Build hash set of server names — O(S) HashMap serverSet = new HashMap<>(); for (String s : serverList) serverSet.put(s, s); // Iterate client list — O(C), each lookup O(1) expected for (String clientName : clientNames) { String found = serverSet.get(clientName); if (found != null) return found; } return null; } // ------------------------------------------------------------------ // // Counting versions // // ------------------------------------------------------------------ // static long[] ops = new long[2]; static String defectiveCounting(String[] serverList, String[] clientNames) { for (String cn : clientNames) { for (String sn : serverList) { ops[0]++; if (sn.equals(cn)) return sn; } } return null; } static String fixedCounting(String[] serverList, String[] clientNames) { HashMap ss = new HashMap<>(); for (String s : serverList) { ops[1]++; ss.put(s, s); } for (String cn : clientNames) { ops[1]++; String found = ss.get(cn); if (found != null) return found; } return null; } static int pass = 0, fail = 0; static void check(String label, boolean cond) { if (cond) { System.out.println(" PASS " + label); pass++; } else { System.out.println(" FAIL " + label); fail++; } } public static void main(String[] args) { System.out.println("=== wolfssl-0001: ALPN_find_match O(C×S) defect ===\n"); // wolfSSL uses client-preference order (matches first client name found in server) String[] server = {"h2", "http/1.1", "grpc"}; // Test 1: first client name matches server String[] client1 = {"h2", "ftp"}; check("defective: match h2", "h2".equals(defectiveMatch(server, client1))); check("fixed: match h2", "h2".equals(fixedMatch(server, client1))); // Test 2: second client name matches String[] client2 = {"ftp", "grpc"}; check("defective: match grpc", "grpc".equals(defectiveMatch(server, client2))); check("fixed: match grpc", "grpc".equals(fixedMatch(server, client2))); // Test 3: client-preference wins (wolfSSL: first matching client entry) String[] client3 = {"grpc", "h2"}; check("defective: client-pref → grpc", "grpc".equals(defectiveMatch(server, client3))); check("fixed: client-pref → grpc", "grpc".equals(fixedMatch(server, client3))); // Test 4: no match String[] client4 = {"smtp", "pop3"}; check("defective: no match → null", defectiveMatch(server, client4) == null); check("fixed: no match → null", fixedMatch(server, client4) == null); // Test 5: complexity — adversarial client list int S = 5; int C = 400; String[] bigServer = new String[S]; for (int i = 0; i < S; i++) bigServer[i] = "proto-server-" + i; String[] bigClient = new String[C]; for (int i = 0; i < C - 1; i++) bigClient[i] = "proto-client-" + i; bigClient[C - 1] = bigServer[S - 1]; // match at end — worst case ops[0] = 0; ops[1] = 0; String rd = defectiveCounting(bigServer, bigClient); String rf = fixedCounting(bigServer, bigClient); System.out.println("\n Complexity comparison (S=" + S + ", C=" + C + "):"); System.out.println(" Defective ops: " + ops[0] + " (expected ~" + ((long)(C-1)*S + 1) + ")"); System.out.println(" Fixed ops: " + ops[1] + " (expected ~" + (S + C) + ")"); System.out.printf(" Speedup: %.1fx%n", (double) ops[0] / ops[1]); check("defective and fixed agree on result", java.util.Objects.equals(rd, rf)); check("defective ops > 4x fixed ops (quadratic vs linear)", ops[0] > 4 * ops[1]); System.out.println("\n--- " + (pass + fail) + " tests: " + pass + " passed, " + fail + " failed ---"); if (fail > 0) System.exit(1); } }