upstream: https://github.com/mirage/mirage-crypto
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(lint): resolve E205 Printf/Format to Fmt in crypto tests

+580 -80
-25
test/check_vectors/check_vectors.ml
··· 1 - let () = 2 - let vx = Ohex.decode in 3 - Crypto_rng_unix.use_default (); 4 - (* ARC4 192-bit *) 5 - let key = vx "0102030405060708090a0b0c0d0e0f101112131415161718" in 6 - let k = Crypto.ARC4.of_secret key in 7 - let pt = String.make 16 '\x00' in 8 - let r = Crypto.ARC4.encrypt ~key:k pt in 9 - Printf.printf "ARC4-192: %s\n" (Ohex.encode r.message); 10 - (* AES-GCM 256 with cafebabe nonce *) 11 - let gkey = 12 - Crypto.AES.GCM.of_secret 13 - (vx "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308") 14 - in 15 - let nonce = vx "cafebabefacedbaddecaf888" in 16 - let p = 17 - vx 18 - "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39" 19 - in 20 - let adata = vx "feedfacedeadbeeffeedfacedeadbeefabaddad2" in 21 - let ct, tag = 22 - Crypto.AES.GCM.authenticate_encrypt_tag ~key:gkey ~nonce ~adata p 23 - in 24 - Printf.printf "GCM-256-CT: %s\n" (Ohex.encode ct); 25 - Printf.printf "GCM-256-Tag: %s\n" (Ohex.encode tag)
-4
test/check_vectors/dune
··· 1 - (executable 2 - (name check_vectors) 3 - (libraries crypto crypto-rng crypto-rng.unix ohex) 4 - (optional))
+87 -15
test/test_ccm.ml
··· 1 1 let vx = Ohex.decode 2 2 3 - let test_encrypt_decrypt () = 4 - let key = vx "404142434445464748494a4b4c4d4e4f" in 5 - let nonce = vx "10111213141516171819202122" in 6 - let adata = vx "0001020304050607" in 7 - let plaintext = vx "20212223" in 8 - let k = Crypto.AES.CCM16.of_secret key in 9 - let ct = 10 - Crypto.AES.CCM16.authenticate_encrypt ~key:k ~nonce ~adata plaintext 11 - in 12 - Alcotest.(check int) "ct length" (4 + 16) (String.length ct); 13 - match Crypto.AES.CCM16.authenticate_decrypt ~key:k ~nonce ~adata ct with 14 - | Some pt -> Alcotest.(check string) "decrypt" plaintext pt 15 - | None -> Alcotest.fail "CCM16 decrypt failed" 16 - 3 + (* CCM16 roundtrip *) 17 4 let test_roundtrip () = 18 5 let key = Crypto_rng.generate 16 in 19 6 let nonce = Crypto_rng.generate 12 in ··· 41 28 in 42 29 Alcotest.(check bool) "tamper rejected" true (Option.is_none result) 43 30 31 + (* Regression: no AD vs empty AD should produce same ciphertext 32 + (https://github.com/mirleft/ocaml-nocrypto/issues/166) *) 33 + let test_no_vs_empty_ad () = 34 + let key = 35 + Crypto.AES.CCM16.of_secret (vx "000102030405060708090a0b0c0d0e0f") 36 + in 37 + let nonce = vx "0001020304050607" in 38 + let plaintext = "hello" in 39 + Alcotest.(check string) 40 + "no vs empty ad" 41 + (Crypto.AES.CCM16.authenticate_encrypt ~key ~nonce plaintext) 42 + (Crypto.AES.CCM16.authenticate_encrypt ~adata:"" ~key ~nonce plaintext) 43 + 44 + (* Regression: empty message encrypt/decrypt *) 45 + let test_empty_message () = 46 + let key = 47 + Crypto.AES.CCM16.of_secret (vx "000102030405060708090a0b0c0d0e0f") 48 + in 49 + let nonce = vx "0001020304050607" in 50 + let adata = "hello" in 51 + let p = "" in 52 + let cipher = Crypto.AES.CCM16.authenticate_encrypt ~adata ~key ~nonce p in 53 + match Crypto.AES.CCM16.authenticate_decrypt ~key ~nonce ~adata cipher with 54 + | Some x -> Alcotest.(check string) "empty msg" p x 55 + | None -> Alcotest.fail "empty message decrypt failed" 56 + 57 + (* Nonce length validation: valid range is 7..13 *) 58 + let test_short_nonce () = 59 + let key = 60 + Crypto.AES.CCM16.of_secret (vx "000102030405060708090a0b0c0d0e0f") 61 + in 62 + let plaintext = "hello" in 63 + Alcotest.check_raises "short nonce" 64 + (Invalid_argument "Crypto: CCM: nonce length not between 7 and 13: 0") 65 + (fun () -> 66 + ignore (Crypto.AES.CCM16.authenticate_encrypt ~key ~nonce:"" plaintext)) 67 + 68 + let test_long_nonce () = 69 + let key = 70 + Crypto.AES.CCM16.of_secret (vx "000102030405060708090a0b0c0d0e0f") 71 + in 72 + let nonce = vx "000102030405060708090a0b0c0d" in 73 + let plaintext = "hello" in 74 + Alcotest.check_raises "long nonce" 75 + (Invalid_argument "Crypto: CCM: nonce length not between 7 and 13: 14") 76 + (fun () -> 77 + ignore (Crypto.AES.CCM16.authenticate_encrypt ~key ~nonce plaintext)) 78 + 79 + (* TLS regression test from mirage-crypto 80 + (discovered while moving ocaml-tls to string) *) 81 + let test_tls_regression () = 82 + let key = 83 + Crypto.AES.CCM16.of_secret (vx "063a96fd15f982d55aad5bf9d0987546") 84 + in 85 + let nonce = vx "81cd47581880 9de0c6557c31" in 86 + let adata = vx "1703030017" in 87 + let data = vx "080000020000 16" in 88 + let expected = vx "94ca065ac948c5d692fd5fabc8500611a07c4f6e071090" in 89 + let cipher = Crypto.AES.CCM16.authenticate_encrypt ~adata ~key ~nonce data in 90 + Alcotest.(check string) "tls encrypt" expected cipher; 91 + match Crypto.AES.CCM16.authenticate_decrypt ~key ~nonce ~adata expected with 92 + | None -> Alcotest.fail "tls decrypt failed" 93 + | Some x -> Alcotest.(check string) "tls decrypt" x data 94 + 95 + (* Tag API roundtrip *) 96 + let test_tag_api () = 97 + let key = Crypto_rng.generate 16 in 98 + let nonce = Crypto_rng.generate 12 in 99 + let adata = "tag api" in 100 + let plaintext = "message" in 101 + let k = Crypto.AES.CCM16.of_secret key in 102 + let ct, tag = 103 + Crypto.AES.CCM16.authenticate_encrypt_tag ~key:k ~nonce ~adata plaintext 104 + in 105 + match 106 + Crypto.AES.CCM16.authenticate_decrypt_tag ~key:k ~nonce ~adata ~tag ct 107 + with 108 + | Some pt -> Alcotest.(check string) "tag api" plaintext pt 109 + | None -> Alcotest.fail "tag API decrypt failed" 110 + 44 111 let suite = 45 112 ( "ccm", 46 113 [ 47 - Alcotest.test_case "encrypt/decrypt" `Quick test_encrypt_decrypt; 48 114 Alcotest.test_case "roundtrip" `Quick test_roundtrip; 49 115 Alcotest.test_case "tamper" `Quick test_tamper; 116 + Alcotest.test_case "no vs empty AD" `Quick test_no_vs_empty_ad; 117 + Alcotest.test_case "empty message" `Quick test_empty_message; 118 + Alcotest.test_case "short nonce" `Quick test_short_nonce; 119 + Alcotest.test_case "long nonce" `Quick test_long_nonce; 120 + Alcotest.test_case "TLS regression" `Quick test_tls_regression; 121 + Alcotest.test_case "tag API" `Quick test_tag_api; 50 122 ] )
+79
test/test_chacha20.ml
··· 18 18 let ct = Crypto.Chacha20.crypt ~key:k ~nonce ~ctr:1L plaintext in 19 19 Alcotest.(check string) "rfc8439" expected ct 20 20 21 + (* draft-strombergson-chacha-test-vectors-01: all-zero key and nonce *) 22 + let test_chacha20_zero () = 23 + let key = vx (String.make 64 '0') in 24 + let nonce = vx (String.make 16 '0') in 25 + let plaintext = String.make 128 '\x00' in 26 + let expected = 27 + vx 28 + ("76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586" 29 + ^ "9f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f" 30 + ) 31 + in 32 + let k = Crypto.Chacha20.of_secret key in 33 + let ct = Crypto.Chacha20.crypt ~key:k ~nonce plaintext in 34 + Alcotest.(check string) "chacha20 all-zero" expected ct 35 + 36 + (* draft-strombergson-chacha-test-vectors-01: key=01000...0 *) 37 + let test_chacha20_key01 () = 38 + let key = vx ("01" ^ String.make 62 '0') in 39 + let nonce = vx (String.make 16 '0') in 40 + let plaintext = String.make 128 '\x00' in 41 + let expected = 42 + vx 43 + ("c5d30a7ce1ec119378c84f487d775a8542f13ece238a9455e8229e888de85bbd29eb63d0a17a5b999b52da22be4023eb07620a54f6fa6ad8737b71eb0464dac0" 44 + ^ "10f656e6d1fd55053e50c4875c9930a33f6d0263bd14dfd6ab8c70521c19338b2308b95cf8d0bb7d202d2102780ea3528f1cb48560f76b20f382b942500fceac" 45 + ) 46 + in 47 + let k = Crypto.Chacha20.of_secret key in 48 + let ct = Crypto.Chacha20.crypt ~key:k ~nonce plaintext in 49 + Alcotest.(check string) "chacha20 key01" expected ct 50 + 51 + (* draft-strombergson-chacha-test-vectors-01: all-ff key and nonce *) 52 + let test_chacha20_all_ff () = 53 + let key = vx (String.make 64 'f') in 54 + let nonce = vx (String.make 16 'f') in 55 + let plaintext = String.make 128 '\x00' in 56 + let expected = 57 + vx 58 + ("d9bf3f6bce6ed0b54254557767fb57443dd4778911b606055c39cc25e674b8363feabc57fde54f790c52c8ae43240b79d49042b777bfd6cb80e931270b7f50eb" 59 + ^ "5bac2acd86a836c5dc98c116c1217ec31d3a63a9451319f097f3b4d6dab0778719477d24d24b403a12241d7cca064f790f1d51ccaff6b1667d4bbca1958c4306" 60 + ) 61 + in 62 + let k = Crypto.Chacha20.of_secret key in 63 + let ct = Crypto.Chacha20.crypt ~key:k ~nonce plaintext in 64 + Alcotest.(check string) "chacha20 all-ff" expected ct 65 + 66 + (* RFC 8439 Section 2.8.2 — ChaCha20-Poly1305 AEAD *) 67 + let test_rfc8439_aead () = 68 + let key = 69 + Crypto.Chacha20.of_secret 70 + (vx "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") 71 + in 72 + let nonce = vx "070000004041424344454647" in 73 + let adata = vx "50515253c0c1c2c3c4c5c6c7" in 74 + let plaintext = 75 + "Ladies and Gentlemen of the class of '99: If I could offer you only one \ 76 + tip for the future, sunscreen would be it." 77 + in 78 + let expected_ct = 79 + vx 80 + "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116" 81 + in 82 + let expected_tag = vx "1ae10b594f09e26a7e902ecbd0600691" in 83 + let ct, tag = 84 + Crypto.Chacha20.authenticate_encrypt_tag ~key ~nonce ~adata plaintext 85 + in 86 + Alcotest.(check string) "rfc8439 aead ct" expected_ct ct; 87 + Alcotest.(check string) "rfc8439 aead tag" expected_tag tag; 88 + match Crypto.Chacha20.authenticate_decrypt_tag ~key ~nonce ~adata ~tag ct with 89 + | Some pt -> Alcotest.(check string) "rfc8439 aead decrypt" plaintext pt 90 + | None -> Alcotest.fail "RFC 8439 AEAD decrypt failed" 91 + 21 92 let test_aead_roundtrip () = 22 93 let key = Crypto_rng.generate 32 in 23 94 let nonce = Crypto_rng.generate 12 in ··· 64 135 let suite = 65 136 ( "chacha20", 66 137 [ 138 + (* RFC 8439 stream cipher *) 67 139 Alcotest.test_case "RFC 8439 stream" `Quick test_rfc8439_stream; 140 + (* draft-strombergson test vectors *) 141 + Alcotest.test_case "all-zero key/nonce" `Quick test_chacha20_zero; 142 + Alcotest.test_case "key 01..0" `Quick test_chacha20_key01; 143 + Alcotest.test_case "all-ff key/nonce" `Quick test_chacha20_all_ff; 144 + (* RFC 8439 AEAD *) 145 + Alcotest.test_case "RFC 8439 AEAD" `Quick test_rfc8439_aead; 146 + (* Roundtrip / tamper *) 68 147 Alcotest.test_case "AEAD roundtrip" `Quick test_aead_roundtrip; 69 148 Alcotest.test_case "AEAD tamper" `Quick test_aead_tamper; 70 149 Alcotest.test_case "AEAD tag API" `Quick test_aead_tag_api;
+269 -19
test/test_cipher_block.ml
··· 5 5 vx 6 6 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" 7 7 8 - let test_aes_ecb () = 8 + (* -- AES ECB ------------------------------------------------------------ *) 9 + 10 + let test_aes_ecb_128 () = 9 11 let key = Crypto.AES.ECB.of_secret (vx "2b7e151628aed2a6abf7158809cf4f3c") in 10 12 let expected = 11 13 vx 12 14 "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4" 13 15 in 14 16 let enc = Crypto.AES.ECB.encrypt ~key nist_plaintext in 15 - Alcotest.(check string) "ecb encrypt" expected enc; 17 + Alcotest.(check string) "ecb-128 encrypt" expected enc; 16 18 let dec = Crypto.AES.ECB.decrypt ~key enc in 17 - Alcotest.(check string) "ecb decrypt" nist_plaintext dec 19 + Alcotest.(check string) "ecb-128 decrypt" nist_plaintext dec 18 20 19 - let test_aes_cbc () = 21 + (* NIST SP 800-38A F.1.3 / F.1.4 — AES-192 ECB *) 22 + let test_aes_ecb_192 () = 23 + let key = 24 + Crypto.AES.ECB.of_secret 25 + (vx "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b") 26 + in 27 + let expected = 28 + vx 29 + "bd334f1d6e45f25ff712a214571fa5cc974104846d0ad3ad7734ecb3ecee4eefef7afd2270e2e60adce0ba2face6444e9a4b41ba738d6c72fb16691603c18e0e" 30 + in 31 + let enc = Crypto.AES.ECB.encrypt ~key nist_plaintext in 32 + Alcotest.(check string) "ecb-192 encrypt" expected enc; 33 + let dec = Crypto.AES.ECB.decrypt ~key enc in 34 + Alcotest.(check string) "ecb-192 decrypt" nist_plaintext dec 35 + 36 + (* NIST SP 800-38A F.1.5 / F.1.6 — AES-256 ECB *) 37 + let test_aes_ecb_256 () = 38 + let key = 39 + Crypto.AES.ECB.of_secret 40 + (vx "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") 41 + in 42 + let expected = 43 + vx 44 + "f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7" 45 + in 46 + let enc = Crypto.AES.ECB.encrypt ~key nist_plaintext in 47 + Alcotest.(check string) "ecb-256 encrypt" expected enc; 48 + let dec = Crypto.AES.ECB.decrypt ~key enc in 49 + Alcotest.(check string) "ecb-256 decrypt" nist_plaintext dec 50 + 51 + (* -- AES CBC ------------------------------------------------------------ *) 52 + 53 + let test_aes_cbc_128 () = 20 54 let key = Crypto.AES.CBC.of_secret (vx "2b7e151628aed2a6abf7158809cf4f3c") in 21 55 let iv = vx "000102030405060708090a0b0c0d0e0f" in 22 56 let expected = ··· 24 58 "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7" 25 59 in 26 60 let enc = Crypto.AES.CBC.encrypt ~key ~iv nist_plaintext in 27 - Alcotest.(check string) "cbc encrypt" expected enc; 61 + Alcotest.(check string) "cbc-128 encrypt" expected enc; 28 62 let dec = Crypto.AES.CBC.decrypt ~key ~iv enc in 29 - Alcotest.(check string) "cbc decrypt" nist_plaintext dec 63 + Alcotest.(check string) "cbc-128 decrypt" nist_plaintext dec 30 64 31 - let test_aes_ctr () = 65 + (* NIST SP 800-38A F.2.3 / F.2.4 — AES-192 CBC *) 66 + let test_aes_cbc_192 () = 67 + let key = 68 + Crypto.AES.CBC.of_secret 69 + (vx "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b") 70 + in 71 + let iv = vx "000102030405060708090a0b0c0d0e0f" in 72 + let expected = 73 + vx 74 + "4f021db243bc633d7178183a9fa071e8b4d9ada9ad7dedf4e5e738763f69145a571b242012fb7ae07fa9baac3df102e008b0e27988598881d920a9e64f5615cd" 75 + in 76 + let enc = Crypto.AES.CBC.encrypt ~key ~iv nist_plaintext in 77 + Alcotest.(check string) "cbc-192 encrypt" expected enc; 78 + let dec = Crypto.AES.CBC.decrypt ~key ~iv enc in 79 + Alcotest.(check string) "cbc-192 decrypt" nist_plaintext dec 80 + 81 + (* NIST SP 800-38A F.2.5 / F.2.6 — AES-256 CBC *) 82 + let test_aes_cbc_256 () = 83 + let key = 84 + Crypto.AES.CBC.of_secret 85 + (vx "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") 86 + in 87 + let iv = vx "000102030405060708090a0b0c0d0e0f" in 88 + let expected = 89 + vx 90 + "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b" 91 + in 92 + let enc = Crypto.AES.CBC.encrypt ~key ~iv nist_plaintext in 93 + Alcotest.(check string) "cbc-256 encrypt" expected enc; 94 + let dec = Crypto.AES.CBC.decrypt ~key ~iv enc in 95 + Alcotest.(check string) "cbc-256 decrypt" nist_plaintext dec 96 + 97 + (* -- AES CTR ------------------------------------------------------------ *) 98 + 99 + let test_aes_ctr_128 () = 32 100 let key = Crypto.AES.CTR.of_secret (vx "2b7e151628aed2a6abf7158809cf4f3c") in 33 101 let ctr = 34 102 Crypto.AES.CTR.ctr_of_octets (vx "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") ··· 38 106 "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee" 39 107 in 40 108 let enc = Crypto.AES.CTR.encrypt ~key ~ctr nist_plaintext in 41 - Alcotest.(check string) "ctr encrypt" expected enc; 109 + Alcotest.(check string) "ctr-128 encrypt" expected enc; 42 110 let dec = Crypto.AES.CTR.decrypt ~key ~ctr enc in 43 - Alcotest.(check string) "ctr decrypt" nist_plaintext dec 111 + Alcotest.(check string) "ctr-128 decrypt" nist_plaintext dec 44 112 45 - let test_aes_gcm_roundtrip () = 113 + (* NIST SP 800-38A F.5.3 / F.5.4 — AES-192 CTR *) 114 + let test_aes_ctr_192 () = 115 + let key = 116 + Crypto.AES.CTR.of_secret 117 + (vx "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b") 118 + in 119 + let ctr = 120 + Crypto.AES.CTR.ctr_of_octets (vx "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") 121 + in 122 + let expected = 123 + vx 124 + "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e941e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050" 125 + in 126 + let enc = Crypto.AES.CTR.encrypt ~key ~ctr nist_plaintext in 127 + Alcotest.(check string) "ctr-192 encrypt" expected enc; 128 + let dec = Crypto.AES.CTR.decrypt ~key ~ctr enc in 129 + Alcotest.(check string) "ctr-192 decrypt" nist_plaintext dec 130 + 131 + (* NIST SP 800-38A F.5.5 / F.5.6 — AES-256 CTR *) 132 + let test_aes_ctr_256 () = 133 + let key = 134 + Crypto.AES.CTR.of_secret 135 + (vx "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") 136 + in 137 + let ctr = 138 + Crypto.AES.CTR.ctr_of_octets (vx "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") 139 + in 140 + let expected = 141 + vx 142 + "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6" 143 + in 144 + let enc = Crypto.AES.CTR.encrypt ~key ~ctr nist_plaintext in 145 + Alcotest.(check string) "ctr-256 encrypt" expected enc; 146 + let dec = Crypto.AES.CTR.decrypt ~key ~ctr enc in 147 + Alcotest.(check string) "ctr-256 decrypt" nist_plaintext dec 148 + 149 + (* -- AES GCM (NIST SP 800-38D) ----------------------------------------- *) 150 + 151 + (* Test Case 1: empty plaintext, no AAD, 128-bit key *) 152 + let test_aes_gcm_nist_1 () = 153 + let key = Crypto.AES.GCM.of_secret (vx "00000000000000000000000000000000") in 154 + let nonce = vx "000000000000000000000000" in 155 + let expected_tag = vx "58e2fccefa7e3061367f1d57a4e7455a" in 156 + let ct, tag = 157 + Crypto.AES.GCM.authenticate_encrypt_tag ~key ~nonce ~adata:"" "" 158 + in 159 + Alcotest.(check string) "gcm-1 ct" "" ct; 160 + Alcotest.(check string) "gcm-1 tag" expected_tag tag; 161 + match 162 + Crypto.AES.GCM.authenticate_decrypt_tag ~key ~nonce ~adata:"" ~tag ct 163 + with 164 + | Some pt -> Alcotest.(check string) "gcm-1 decrypt" "" pt 165 + | None -> Alcotest.fail "GCM test case 1 decrypt failed" 166 + 167 + (* Test Case 2: 16-byte zero plaintext, no AAD *) 168 + let test_aes_gcm_nist_2 () = 169 + let key = Crypto.AES.GCM.of_secret (vx "00000000000000000000000000000000") in 170 + let nonce = vx "000000000000000000000000" in 171 + let p = vx "00000000000000000000000000000000" in 172 + let expected_ct = vx "0388dace60b6a392f328c2b971b2fe78" in 173 + let expected_tag = vx "ab6e47d42cec13bdf53a67b21257bddf" in 174 + let ct, tag = 175 + Crypto.AES.GCM.authenticate_encrypt_tag ~key ~nonce ~adata:"" p 176 + in 177 + Alcotest.(check string) "gcm-2 ct" expected_ct ct; 178 + Alcotest.(check string) "gcm-2 tag" expected_tag tag; 179 + match 180 + Crypto.AES.GCM.authenticate_decrypt_tag ~key ~nonce ~adata:"" ~tag ct 181 + with 182 + | Some pt -> Alcotest.(check string) "gcm-2 decrypt" p pt 183 + | None -> Alcotest.fail "GCM test case 2 decrypt failed" 184 + 185 + (* Test Case 3: 64-byte plaintext, no AAD *) 186 + let test_aes_gcm_nist_3 () = 187 + let key = Crypto.AES.GCM.of_secret (vx "feffe9928665731c6d6a8f9467308308") in 188 + let nonce = vx "cafebabefacedbaddecaf888" in 189 + let p = 190 + vx 191 + "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255" 192 + in 193 + let expected_ct = 194 + vx 195 + "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985" 196 + in 197 + let expected_tag = vx "4d5c2af327cd64a62cf35abd2ba6fab4" in 198 + let ct, tag = 199 + Crypto.AES.GCM.authenticate_encrypt_tag ~key ~nonce ~adata:"" p 200 + in 201 + Alcotest.(check string) "gcm-3 ct" expected_ct ct; 202 + Alcotest.(check string) "gcm-3 tag" expected_tag tag; 203 + match 204 + Crypto.AES.GCM.authenticate_decrypt_tag ~key ~nonce ~adata:"" ~tag ct 205 + with 206 + | Some pt -> Alcotest.(check string) "gcm-3 decrypt" p pt 207 + | None -> Alcotest.fail "GCM test case 3 decrypt failed" 208 + 209 + (* Test Case 4: 60-byte plaintext, 20-byte AAD *) 210 + let test_aes_gcm_nist_4 () = 211 + let key = Crypto.AES.GCM.of_secret (vx "feffe9928665731c6d6a8f9467308308") in 212 + let nonce = vx "cafebabefacedbaddecaf888" in 213 + let p = 214 + vx 215 + "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39" 216 + in 217 + let adata = vx "feedfacedeadbeeffeedfacedeadbeefabaddad2" in 218 + let expected_ct = 219 + vx 220 + "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091" 221 + in 222 + let expected_tag = vx "5bc94fbc3221a5db94fae95ae7121a47" in 223 + let ct, tag = Crypto.AES.GCM.authenticate_encrypt_tag ~key ~nonce ~adata p in 224 + Alcotest.(check string) "gcm-4 ct" expected_ct ct; 225 + Alcotest.(check string) "gcm-4 tag" expected_tag tag; 226 + match Crypto.AES.GCM.authenticate_decrypt_tag ~key ~nonce ~adata ~tag ct with 227 + | Some pt -> Alcotest.(check string) "gcm-4 decrypt" p pt 228 + | None -> Alcotest.fail "GCM test case 4 decrypt failed" 229 + 230 + (* Test Case 7: NIST SP 800-38D — 192-bit key, 60-byte PT, 20-byte AAD *) 231 + let test_aes_gcm_nist_192 () = 232 + let key = 233 + Crypto.AES.GCM.of_secret 234 + (vx "feffe9928665731c6d6a8f9467308308feffe9928665731c") 235 + in 236 + let nonce = vx "cafebabefacedbaddecaf888" in 237 + let p = 238 + vx 239 + "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39" 240 + in 241 + let adata = vx "feedfacedeadbeeffeedfacedeadbeefabaddad2" in 242 + let expected_ct = 243 + vx 244 + "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710" 245 + in 246 + let expected_tag = vx "2519498e80f1478f37ba55bd6d27618c" in 247 + let ct, tag = Crypto.AES.GCM.authenticate_encrypt_tag ~key ~nonce ~adata p in 248 + Alcotest.(check string) "gcm-192 ct" expected_ct ct; 249 + Alcotest.(check string) "gcm-192 tag" expected_tag tag 250 + 251 + (* Test Case 14: NIST SP 800-38D — 256-bit key, 60-byte PT, 20-byte AAD *) 252 + let test_aes_gcm_nist_256 () = 253 + let key = 254 + Crypto.AES.GCM.of_secret 255 + (vx "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308") 256 + in 257 + let nonce = vx "cafebabefacedbaddecaf888" in 258 + let p = 259 + vx 260 + "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39" 261 + in 262 + let adata = vx "feedfacedeadbeeffeedfacedeadbeefabaddad2" in 263 + let expected_ct = 264 + vx 265 + "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662" 266 + in 267 + let expected_tag = vx "76fc6ece0f4e1768cddf8853bb2d551b" in 268 + let ct, tag = Crypto.AES.GCM.authenticate_encrypt_tag ~key ~nonce ~adata p in 269 + Alcotest.(check string) "gcm-256 ct" expected_ct ct; 270 + Alcotest.(check string) "gcm-256 tag" expected_tag tag 271 + 272 + (* GCM tamper detection *) 273 + let test_aes_gcm_tamper () = 46 274 let key = Crypto_rng.generate 16 in 47 275 let nonce = Crypto_rng.generate 12 in 48 276 let adata = "gcm associated data" in 49 - let plaintext = "GCM test plaintext block" in 50 277 let k = Crypto.AES.GCM.of_secret key in 51 - let ct = Crypto.AES.GCM.authenticate_encrypt ~key:k ~nonce ~adata plaintext in 52 - match Crypto.AES.GCM.authenticate_decrypt ~key:k ~nonce ~adata ct with 53 - | Some pt -> Alcotest.(check string) "gcm roundtrip" plaintext pt 54 - | None -> Alcotest.fail "GCM decrypt failed" 278 + let ct = Crypto.AES.GCM.authenticate_encrypt ~key:k ~nonce ~adata "secret" in 279 + let bad = Bytes.of_string ct in 280 + Bytes.set bad 0 (Char.chr (Char.code (Bytes.get bad 0) lxor 1)); 281 + let result = 282 + Crypto.AES.GCM.authenticate_decrypt ~key:k ~nonce ~adata 283 + (Bytes.to_string bad) 284 + in 285 + Alcotest.(check bool) "gcm tamper rejected" true (Option.is_none result) 286 + 287 + (* -- DES ECB ------------------------------------------------------------ *) 55 288 56 289 let test_des_ecb_roundtrip () = 57 290 let key = Crypto_rng.generate 24 in ··· 64 297 let suite = 65 298 ( "cipher_block", 66 299 [ 67 - Alcotest.test_case "AES ECB NIST" `Quick test_aes_ecb; 68 - Alcotest.test_case "AES CBC NIST" `Quick test_aes_cbc; 69 - Alcotest.test_case "AES CTR NIST" `Quick test_aes_ctr; 70 - Alcotest.test_case "AES GCM roundtrip" `Quick test_aes_gcm_roundtrip; 300 + (* AES ECB — NIST SP 800-38A *) 301 + Alcotest.test_case "AES ECB 128 NIST" `Quick test_aes_ecb_128; 302 + Alcotest.test_case "AES ECB 192 NIST" `Quick test_aes_ecb_192; 303 + Alcotest.test_case "AES ECB 256 NIST" `Quick test_aes_ecb_256; 304 + (* AES CBC — NIST SP 800-38A *) 305 + Alcotest.test_case "AES CBC 128 NIST" `Quick test_aes_cbc_128; 306 + Alcotest.test_case "AES CBC 192 NIST" `Quick test_aes_cbc_192; 307 + Alcotest.test_case "AES CBC 256 NIST" `Quick test_aes_cbc_256; 308 + (* AES CTR — NIST SP 800-38A *) 309 + Alcotest.test_case "AES CTR 128 NIST" `Quick test_aes_ctr_128; 310 + Alcotest.test_case "AES CTR 192 NIST" `Quick test_aes_ctr_192; 311 + Alcotest.test_case "AES CTR 256 NIST" `Quick test_aes_ctr_256; 312 + (* AES GCM — NIST SP 800-38D *) 313 + Alcotest.test_case "AES GCM NIST TC1" `Quick test_aes_gcm_nist_1; 314 + Alcotest.test_case "AES GCM NIST TC2" `Quick test_aes_gcm_nist_2; 315 + Alcotest.test_case "AES GCM NIST TC3" `Quick test_aes_gcm_nist_3; 316 + Alcotest.test_case "AES GCM NIST TC4" `Quick test_aes_gcm_nist_4; 317 + Alcotest.test_case "AES GCM NIST 192" `Quick test_aes_gcm_nist_192; 318 + Alcotest.test_case "AES GCM NIST 256" `Quick test_aes_gcm_nist_256; 319 + Alcotest.test_case "AES GCM tamper" `Quick test_aes_gcm_tamper; 320 + (* DES *) 71 321 Alcotest.test_case "DES ECB roundtrip" `Quick test_des_ecb_roundtrip; 72 322 ] )
+70 -4
test/test_cipher_stream.ml
··· 1 1 let vx = Ohex.decode 2 2 3 - (* RFC 6229 — ARC4 with 40-bit key *) 4 - let test_arc4_rfc6229 () = 3 + (* RFC 6229 — ARC4 test vectors (keystream applied to zero plaintext) *) 4 + 5 + (* 40-bit key *) 6 + let test_arc4_rfc6229_40 () = 5 7 let key = vx "0102030405" in 6 8 let k = Crypto.ARC4.of_secret key in 7 9 let plaintext = String.make 16 '\x00' in 8 10 let result = Crypto.ARC4.encrypt ~key:k plaintext in 9 11 let expected = vx "b2396305f03dc027ccc3524a0a1118a8" in 10 - Alcotest.(check string) "rfc6229" expected result.message 12 + Alcotest.(check string) "rfc6229-40" expected result.message 13 + 14 + (* 56-bit key *) 15 + let test_arc4_rfc6229_56 () = 16 + let key = vx "01020304050607" in 17 + let k = Crypto.ARC4.of_secret key in 18 + let plaintext = String.make 16 '\x00' in 19 + let result = Crypto.ARC4.encrypt ~key:k plaintext in 20 + let expected = vx "293f02d47f37c9b633f2af5285feb46b" in 21 + Alcotest.(check string) "rfc6229-56" expected result.message 22 + 23 + (* 64-bit key *) 24 + let test_arc4_rfc6229_64 () = 25 + let key = vx "0102030405060708" in 26 + let k = Crypto.ARC4.of_secret key in 27 + let plaintext = String.make 16 '\x00' in 28 + let result = Crypto.ARC4.encrypt ~key:k plaintext in 29 + let expected = vx "97ab8a1bf0afb96132f2f67258da15a8" in 30 + Alcotest.(check string) "rfc6229-64" expected result.message 31 + 32 + (* 80-bit key *) 33 + let test_arc4_rfc6229_80 () = 34 + let key = vx "0102030405060708090a" in 35 + let k = Crypto.ARC4.of_secret key in 36 + let plaintext = String.make 16 '\x00' in 37 + let result = Crypto.ARC4.encrypt ~key:k plaintext in 38 + let expected = vx "ede3b04643e586cc907dc21851709902" in 39 + Alcotest.(check string) "rfc6229-80" expected result.message 40 + 41 + (* 128-bit key *) 42 + let test_arc4_rfc6229_128 () = 43 + let key = vx "0102030405060708090a0b0c0d0e0f10" in 44 + let k = Crypto.ARC4.of_secret key in 45 + let plaintext = String.make 16 '\x00' in 46 + let result = Crypto.ARC4.encrypt ~key:k plaintext in 47 + let expected = vx "9ac7cc9a609d1ef7b2932899cde41b97" in 48 + Alcotest.(check string) "rfc6229-128" expected result.message 49 + 50 + (* 192-bit key *) 51 + let test_arc4_rfc6229_192 () = 52 + let key = vx "0102030405060708090a0b0c0d0e0f101112131415161718" in 53 + let k = Crypto.ARC4.of_secret key in 54 + let plaintext = String.make 16 '\x00' in 55 + let result = Crypto.ARC4.encrypt ~key:k plaintext in 56 + let expected = vx "0595e57fe5f0bb3c706edac8a4b2db11" in 57 + Alcotest.(check string) "rfc6229-192" expected result.message 58 + 59 + (* 256-bit key *) 60 + let test_arc4_rfc6229_256 () = 61 + let key = 62 + vx "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" 63 + in 64 + let k = Crypto.ARC4.of_secret key in 65 + let plaintext = String.make 16 '\x00' in 66 + let result = Crypto.ARC4.encrypt ~key:k plaintext in 67 + let expected = vx "eaa6bd25880bf93d3f5d1e4ca2611d91" in 68 + Alcotest.(check string) "rfc6229-256" expected result.message 11 69 12 70 let test_arc4_roundtrip () = 13 71 let key = Crypto_rng.generate 16 in ··· 32 90 let suite = 33 91 ( "cipher_stream", 34 92 [ 35 - Alcotest.test_case "ARC4 RFC 6229" `Quick test_arc4_rfc6229; 93 + (* RFC 6229 — ARC4 at various key sizes *) 94 + Alcotest.test_case "ARC4 RFC 6229 40-bit" `Quick test_arc4_rfc6229_40; 95 + Alcotest.test_case "ARC4 RFC 6229 56-bit" `Quick test_arc4_rfc6229_56; 96 + Alcotest.test_case "ARC4 RFC 6229 64-bit" `Quick test_arc4_rfc6229_64; 97 + Alcotest.test_case "ARC4 RFC 6229 80-bit" `Quick test_arc4_rfc6229_80; 98 + Alcotest.test_case "ARC4 RFC 6229 128-bit" `Quick test_arc4_rfc6229_128; 99 + Alcotest.test_case "ARC4 RFC 6229 192-bit" `Quick test_arc4_rfc6229_192; 100 + Alcotest.test_case "ARC4 RFC 6229 256-bit" `Quick test_arc4_rfc6229_256; 101 + (* Roundtrip / stateful *) 36 102 Alcotest.test_case "ARC4 roundtrip" `Quick test_arc4_roundtrip; 37 103 Alcotest.test_case "ARC4 stateful" `Quick test_arc4_stateful; 38 104 ] )
+5 -6
test/test_crypto_ec.ml
··· 11 11 let bbuf = Bytes.unsafe_of_string buf in 12 12 for i = n - 1 downto 0 do 13 13 let byte = Bytes.get_uint8 bbuf i in 14 - Format.fprintf fmt "%02x" byte 14 + Fmt.pf fmt "%02x" byte 15 15 done 16 16 17 17 let pp_result ppf = function 18 18 | Ok cs -> pp_hex_le ppf cs 19 - | Error e -> Format.fprintf ppf "%a" pp_error e 19 + | Error e -> Fmt.pf ppf "%a" pp_error e 20 20 21 21 let key_exchange = 22 22 let test ~name d p ~expected = 23 23 ( name, 24 24 `Quick, 25 25 fun () -> 26 - P256.Dh.key_exchange d p 27 - |> Format.asprintf "%a" pp_result 26 + P256.Dh.key_exchange d p |> Fmt.str "%a" pp_result 28 27 |> Alcotest.check Alcotest.string __LOC__ expected ) 29 28 in 30 29 let kp data = ··· 61 60 | Ok (p, _) -> p 62 61 | Error _ -> assert false 63 62 in 64 - ( Printf.sprintf "Scalar mult (#%d)" n, 63 + ( Fmt.str "Scalar mult (#%d)" n, 65 64 `Quick, 66 65 fun () -> 67 66 P256.Dh.key_exchange scalar point 68 - |> Format.asprintf "%a" pp_result 67 + |> Fmt.str "%a" pp_result 69 68 |> Alcotest.check Alcotest.string __LOC__ expected ) 70 69 in 71 70 let point =
+64 -1
test/test_poly1305.ml
··· 10 10 let tag = Crypto.Poly1305.mac ~key msg in 11 11 Alcotest.(check string) "rfc8439" expected tag 12 12 13 + (* RFC 8439 Appendix A.3 — Test Vector #1: all-zero key, 64-byte zero msg *) 14 + let test_rfc8439_a3_1 () = 15 + let key = vx (String.make 64 '0') in 16 + let msg = vx (String.make 128 '0') in 17 + let expected = vx "00000000000000000000000000000000" in 18 + let tag = Crypto.Poly1305.mac ~key msg in 19 + Alcotest.(check string) "rfc8439-a3-1" expected tag 20 + 21 + (* RFC 8439 Appendix A.3 — Test Vector #2: 22 + r=0, s=36e5f6b5c5e06070f0efca96227a863e *) 23 + let test_rfc8439_a3_2 () = 24 + let key = 25 + vx "0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e" 26 + in 27 + let msg = 28 + "Any submission to the IETF intended by the Contributor for publication as \ 29 + all or part of an IETF Internet-Draft or RFC and any statement made \ 30 + within the context of an IETF activity is considered an \"IETF \ 31 + Contribution\". Such statements include oral statements in IETF sessions, \ 32 + as well as written and electronic communications made at any time or \ 33 + place, which are addressed to" 34 + in 35 + let expected = vx "36e5f6b5c5e06070f0efca96227a863e" in 36 + let tag = Crypto.Poly1305.mac ~key msg in 37 + Alcotest.(check string) "rfc8439-a3-2" expected tag 38 + 39 + (* RFC 8439 Appendix A.3 — Test Vector #3: 40 + r=36e5f6b5c5e06070f0efca96227a863e, s=0 *) 41 + let test_rfc8439_a3_3 () = 42 + let key = 43 + vx "36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000" 44 + in 45 + let msg = 46 + "Any submission to the IETF intended by the Contributor for publication as \ 47 + all or part of an IETF Internet-Draft or RFC and any statement made \ 48 + within the context of an IETF activity is considered an \"IETF \ 49 + Contribution\". Such statements include oral statements in IETF sessions, \ 50 + as well as written and electronic communications made at any time or \ 51 + place, which are addressed to" 52 + in 53 + let expected = vx "f3477e7cd95417af89a6b8794c310cf0" in 54 + let tag = Crypto.Poly1305.mac ~key msg in 55 + Alcotest.(check string) "rfc8439-a3-3" expected tag 56 + 57 + (* RFC 8439 Appendix A.3 — Test Vector #4 *) 58 + let test_rfc8439_a3_4 () = 59 + let key = 60 + vx "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0" 61 + in 62 + let msg = 63 + "'Twas brillig, and the slithy toves\n\ 64 + Did gyre and gimble in the wabe:\n\ 65 + All mimsy were the borogoves,\n\ 66 + And the mome raths outgrabe." 67 + in 68 + let expected = vx "4541669a7eaaee61e708dc7cbcc5eb62" in 69 + let tag = Crypto.Poly1305.mac ~key msg in 70 + Alcotest.(check string) "rfc8439-a3-4" expected tag 71 + 13 72 let test_incremental () = 14 73 let key = 15 74 vx "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b" ··· 39 98 let suite = 40 99 ( "poly1305", 41 100 [ 42 - Alcotest.test_case "RFC 8439" `Quick test_rfc8439; 101 + Alcotest.test_case "RFC 8439 2.5.2" `Quick test_rfc8439; 102 + Alcotest.test_case "RFC 8439 A.3 #1" `Quick test_rfc8439_a3_1; 103 + Alcotest.test_case "RFC 8439 A.3 #2" `Quick test_rfc8439_a3_2; 104 + Alcotest.test_case "RFC 8439 A.3 #3" `Quick test_rfc8439_a3_3; 105 + Alcotest.test_case "RFC 8439 A.3 #4" `Quick test_rfc8439_a3_4; 43 106 Alcotest.test_case "incremental" `Quick test_incremental; 44 107 Alcotest.test_case "maci" `Quick test_maci; 45 108 ] )
+1 -1
tests/test_crypto.ml
··· 682 682 Alcotest.test_case "long_adata" `Quick long_adata; 683 683 ] 684 684 @ List.mapi 685 - (fun i f -> Alcotest.test_case (Printf.sprintf "regr_tls_%d" i) `Quick f) 685 + (fun i f -> Alcotest.test_case (Fmt.str "regr_tls_%d" i) `Quick f) 686 686 regr_tls 687 687 688 688 let gcm_regressions =
+2 -2
tests/test_dh.ml
··· 9 9 let s1, m1 = Dh.gen_key p and s2, m2 = Dh.gen_key p in 10 10 let sh1 = Dh.shared s1 m2 and sh2 = Dh.shared s2 m1 in 11 11 let pp_opt ppf = function 12 - | None -> Format.fprintf ppf "None" 13 - | Some a -> Format.fprintf ppf "Some(%a)" (Ohex.pp_hexdump ()) a 12 + | None -> Fmt.pf ppf "None" 13 + | Some a -> Fmt.pf ppf "Some(%a)" (Ohex.pp_hexdump ()) a 14 14 in 15 15 match (sh1, sh2) with 16 16 | Some a, Some b ->
+1 -1
tests/test_dsa.ml
··· 3217 3217 3218 3218 let to_cases name cases = 3219 3219 List.mapi 3220 - (fun i f -> Alcotest.test_case (Printf.sprintf "%s %d" name i) `Quick f) 3220 + (fun i f -> Alcotest.test_case (Fmt.str "%s %d" name i) `Quick f) 3221 3221 cases 3222 3222 3223 3223 let suite =
+1 -1
tests/test_rsa.ml
··· 93 93 | Error _ -> Alcotest.fail "expected ok" 94 94 | Ok _ -> ()) 95 95 96 - let show_key_size key = Printf.sprintf "(%d bits)" (Rsa.priv_bits key) 96 + let show_key_size key = Fmt.str "(%d bits)" (Rsa.priv_bits key) 97 97 98 98 let pkcs_message_for_bits bits = 99 99 let padding = 12 in
+1 -1
tests/test_uncommon.ml
··· 17 17 ] 18 18 19 19 let xor_test (a, b, c) = 20 - Alcotest.test_case (Printf.sprintf "xor %s ^ %s" a b) `Quick (fun () -> 20 + Alcotest.test_case (Fmt.str "xor %s ^ %s" a b) `Quick (fun () -> 21 21 Alcotest.(check string) "xor" (vx c) (Uncommon.xor (vx a) (vx b))) 22 22 23 23 let suite = ("uncommon", List.map xor_test xor_cases)