From e08b8227f7c9c02add02e460a9b2ac30964720ae Mon Sep 17 00:00:00 2001 From: Hai Nguyen Van Date: Thu, 24 Sep 2020 17:11:46 +0200 Subject: [PATCH] Testing: Better comments in lib_crypto --- src/lib_crypto/test/test_base58.ml | 13 ++ src/lib_crypto/test/test_blake2b.ml | 10 ++ src/lib_crypto/test/test_crypto_box.ml | 23 ++++ .../test/test_deterministic_nonce.ml | 8 ++ src/lib_crypto/test/test_ed25519.ml | 14 +++ src/lib_crypto/test/test_hacl.ml | 114 +++++++++++------- src/lib_crypto/test/test_merkle.ml | 22 ++++ src/lib_crypto/test/test_pvss.ml | 19 ++- 8 files changed, 174 insertions(+), 49 deletions(-) diff --git a/src/lib_crypto/test/test_base58.ml b/src/lib_crypto/test/test_base58.ml index b39fede4e4ab..0f15292f660b 100644 --- a/src/lib_crypto/test/test_base58.ml +++ b/src/lib_crypto/test/test_base58.ml @@ -23,6 +23,14 @@ (* *) (*****************************************************************************) +(** Testing + ------- + Component: Crypto + Invocation: dune build @src/lib_crypto/runtest + Dependencies: src/lib_crypto/test/roundtrips.ml + Subject: Encoding in Base58 +*) + let test_roundtrip_safe input = Roundtrips.test_rt_opt "safe base58" @@ -66,8 +74,12 @@ let inputs = String.init 1000 (fun i -> Char.chr (32 + (i mod (126 - 32)))); "" ] +(** Safe Base58Check-encoding then decoding (provided with error + detections) +*) let test_roundtrip_safes () = List.iter test_roundtrip_safe inputs +(** Base58-encoding then decoding (no error detection) *) let test_roundtrip_raws () = List.iter test_roundtrip_raw inputs let test_safety input = @@ -77,6 +89,7 @@ let test_safety input = Base58.safe_decode input +(** Safe Base58Check-decoding (provided with error detections) *) let test_safetys () = List.iter test_safety inputs let tests = diff --git a/src/lib_crypto/test/test_blake2b.ml b/src/lib_crypto/test/test_blake2b.ml index 015da37a3785..6d16d941386f 100644 --- a/src/lib_crypto/test/test_blake2b.ml +++ b/src/lib_crypto/test/test_blake2b.ml @@ -23,6 +23,14 @@ (* *) (*****************************************************************************) +(** Testing + ------- + Component: Crypto + Invocation: dune build @src/lib_crypto/runtest + Dependencies: src/lib_crypto/test/roundtrips.ml + Subject: On the hash function BLAKE2b +*) + let test_hashed_roundtrip name enc dec input = (* this wrapper to start with hashing *) Roundtrips.test_rt_opt @@ -55,8 +63,10 @@ let inputs = String.init 1000 (fun i -> Char.chr (32 + (i mod (126 - 32)))); "" ] +(** Roundtrips of hexadecimal (en/de)coding of Blake2b hash. *) let test_roundtrip_hexs () = List.iter test_roundtrip_hex inputs +(** Roundtrips of string (en/de)coding of Blake2b hash. *) let test_roundtrip_strings () = List.iter test_roundtrip_string inputs let tests = diff --git a/src/lib_crypto/test/test_crypto_box.ml b/src/lib_crypto/test/test_crypto_box.ml index 73fa4103aee7..6c00cc35d284 100644 --- a/src/lib_crypto/test/test_crypto_box.ml +++ b/src/lib_crypto/test/test_crypto_box.ml @@ -23,6 +23,13 @@ (* *) (*****************************************************************************) +(** Testing + ------- + Component: Crypto + Invocation: dune build @src/lib_crypto/runtest + Subject: Roundtrips for functions built on the HACL* NaCl API. +*) + let check_bytes = Alcotest.testable (fun fmt x -> Hex.pp fmt (Hex.of_bytes x)) Bytes.equal @@ -32,6 +39,10 @@ let zero_nonce = Crypto_box.zero_nonce let chkey = Crypto_box.precompute sk pk +(** The test defines a proof-of-work target, generates a proof-of-work + for that target, and then verifies it the proof of work is accepted + by [Crypto_box.check_proof_of_work]. +*) let test_check_pow () = let open Lwt.Infix in let target = Crypto_box.make_target 2. in @@ -42,6 +53,9 @@ let test_check_pow () = (Crypto_box.check_proof_of_work pk pow target) true +(** Checks the neuterize function, i.e. the [pk] corresponds to the + generated public key from secret key [sk]. +*) let test_neuterize sk pk () = Alcotest.check (Alcotest.testable Crypto_box.pp_pk Crypto_box.equal) @@ -49,6 +63,9 @@ let test_neuterize sk pk () = (Crypto_box.neuterize sk) pk +(** Checks that the [pkh] corresponds to the generated hash of the + public key [pk]. +*) let test_hash pk pkh () = Alcotest.check (Alcotest.testable @@ -58,6 +75,9 @@ let test_hash pk pkh () = (Crypto_box.hash pk) pkh +(** Encrypts then decrypts the message [msg] with authentication + (with side-effects, in-place changes). +*) let test_fast_box_noalloc msg () = let buf = Bytes.copy msg in let tag = Bytes.make Crypto_box.tag_length '\x00' in @@ -66,6 +86,9 @@ let test_fast_box_noalloc msg () = assert (Crypto_box.fast_box_open_noalloc chkey zero_nonce tag buf) ; Alcotest.check check_bytes "test_fast_box_noalloc" buf msg +(** Encrypts then decrypts the message [msg] with authentication. + Returns a new buffer for ciphertext. +*) let test_fast_box msg () = let cmsg = Crypto_box.fast_box chkey zero_nonce msg in match Crypto_box.fast_box_open chkey zero_nonce cmsg with diff --git a/src/lib_crypto/test/test_deterministic_nonce.ml b/src/lib_crypto/test/test_deterministic_nonce.ml index 90f9c61701c0..4c1b2eb5ef2f 100644 --- a/src/lib_crypto/test/test_deterministic_nonce.ml +++ b/src/lib_crypto/test/test_deterministic_nonce.ml @@ -23,6 +23,14 @@ (* *) (*****************************************************************************) +(** Testing + ------- + Component: Crypto + Invocation: dune build @src/lib_crypto/runtest + Subject: On hash functions with deterministic nonce +*) + +(** Deterministic nonce generation using HMAC-SHA256 *) let test_hash_matches (module X : S.SIGNATURE) () = let (_, _, sk) = X.generate_key () in let data = Bytes.of_string "ce input sa pun eu aici oare?" in diff --git a/src/lib_crypto/test/test_ed25519.ml b/src/lib_crypto/test/test_ed25519.ml index 987ff7497d57..58a78d65cb7f 100644 --- a/src/lib_crypto/test/test_ed25519.ml +++ b/src/lib_crypto/test/test_ed25519.ml @@ -23,6 +23,14 @@ (* *) (*****************************************************************************) +(** Testing + ------- + Component: Crypto + Invocation: dune build @src/lib_crypto/runtest + Dependencies: src/lib_crypto/test/roundtrips.ml + Subject: Checking Base58 encodings for Ed25519 keys. +*) + module type B58CHECK = sig type t @@ -43,6 +51,9 @@ let test_b58check_roundtrip : M.of_b58check_opt input +(** Ensures that B58Check-roundtrip (encoding then decoding) is sound + for pkh, pk and sk in Ed25519 +*) let test_b58check_roundtrips () = let (pubkey_hash, pubkey, seckey) = Ed25519.generate_key () in test_b58check_roundtrip (module Ed25519.Public_key_hash) pubkey_hash ; @@ -56,6 +67,9 @@ let test_b58check_invalid input = Ed25519.Public_key_hash.of_b58check_opt input +(** Testing with invalid values, mostly random bytes and wrong + sizes, which are not accepted as Ed25519 keys. +*) let test_b58check_invalids () = List.iter test_b58check_invalid diff --git a/src/lib_crypto/test/test_hacl.ml b/src/lib_crypto/test/test_hacl.ml index b54efe136b6e..2932fa18e963 100644 --- a/src/lib_crypto/test/test_hacl.ml +++ b/src/lib_crypto/test/test_hacl.ml @@ -20,6 +20,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *) +(** Testing + ------- + Component: Crypto + Invocation: dune build @src/lib_crypto/runtest + Subject: Checking all of the HACL* primitives used in lib_crypto: + hashing, HMAC, NaCl, Ed25519, and P-256. +*) + open Hacl let hex s = Hex.to_bytes (`Hex s) @@ -82,38 +90,30 @@ let randmsg = let randmsg_len = Bytes.length randmsg -let sha256 () = +(** Checks that the SHA256-digest from [msg] corresponds to [expected_value], + whether using [digest] or with [init]/[update]. Same for [randmsg]. +*) +let test_sha256 () = let open Hash.SHA256 in - let resp = + let expected_value = of_hex "d8d219deae87c5e5fffbc0a0a38986de266427b2e08be9f9d22a07b91099dbfe" - in - let randresp = + and rand_expected_value = of_hex "9f043732d7117fa402d24e7343108976524b097390b0b160df42b0fa5bc6425c" in - let st = init () in - Printf.printf "Init done\n" ; - update st msg ; - print_endline "Update done." ; - let d = finish st in - Printf.printf "Digest size %d\n" (Bytes.length d) ; - print_endline "Finish done." ; - Alcotest.(check check_bytes "sha256" resp d) ; - let d = digest msg in - print_endline "Direct hash done." ; - Alcotest.(check check_bytes "sha256" resp d) ; - let st = init () in - Printf.printf "Init done\n" ; - update st randmsg ; - print_endline "Update done." ; - let d = finish st in - Printf.printf "Digest size %d\n" (Bytes.length d) ; - print_endline "Finish done." ; - Alcotest.(check check_bytes "sha256" randresp d) ; - let d = digest randmsg in - print_endline "Direct hash done." ; - Alcotest.(check check_bytes "sha256" randresp d) + let init_finish_digest (value, msg) = + let st = init () in + update st msg ; + let d = finish st in + Alcotest.(check check_bytes "sha256" value d) ; + let d = digest msg in + Alcotest.(check check_bytes "sha256" value d) + in + List.iter + init_finish_digest + [(expected_value, msg); (rand_expected_value, randmsg)] -let sha256_seq () = +(** Checks SHA256 incremental hashing with 2 updates. *) +let test_sha256_seq () = let open Hash.SHA256 in let bothresp = of_hex "ddabe6c4552e944d927bd0b03dd5ab95ecdfa5a135b6c3b60416dbde57b38416" @@ -128,7 +128,8 @@ let sha256_seq () = print_endline "Finish done." ; Alcotest.(check check_bytes "sha256_seq" bothresp d) -let sha512 () = +(** Checks SHA512 hash function. *) +let test_sha512 () = let resp = of_hex "b4686c597b48c05f9d79f933611343e00985967c16f81a301269c75065ed05067dc547b1b36ec1822cc19a78df691e30fdb739ffb6b2a0ea6533ff20a2202e51" @@ -136,7 +137,8 @@ let sha512 () = let digest = Hash.SHA512.digest msg in Alcotest.(check check_bytes "sha512" resp digest) -let hmac_sha256 () = +(** Checks HMAC-SHA256 with a fixed message and key. *) +let test_hmac_sha256 () = let key = Bytes.unsafe_of_string "key" in let msg = Bytes.unsafe_of_string "The quick brown fox jumps over the lazy dog" @@ -147,7 +149,8 @@ let hmac_sha256 () = let digest = Hash.SHA256.HMAC.digest ~key ~msg in Alcotest.(check check_bytes "hmac_sha256" resp digest) -let hmac_sha512 () = +(** Checks HMAC-SHA512. *) +let test_hmac_sha512 () = let vectors = [ ( Bytes.unsafe_of_string "key", Bytes.unsafe_of_string "The quick brown fox jumps over the lazy dog", @@ -166,14 +169,16 @@ let hmac_sha512 () = Alcotest.(check check_bytes "hmac_sha512" resp digest)) vectors -let sha3_256 () = +(** Checks SHA3-256 hash function. *) +let test_sha3_256 () = let resp = of_hex "c0bc8a6fc1d24c6d8aba95294d86159807aacb95eff450367e807c76fdf98037" in let digest = Hash.SHA3_256.digest msg in Alcotest.(check check_bytes "sha3_256" resp digest) -let sha3_512 () = +(** Checks SHA3-512 hash function. *) +let test_sha3_512 () = let resp = of_hex "5d64d3ef8598612744af86fb24d9ad792e0064544a97c149ff8aaedf35c2717d105a2ae191aa11e08c525c28433687c044a8e81271ab9a668ba531091823dfe7" @@ -181,7 +186,8 @@ let sha3_512 () = let digest = Hash.SHA3_512.digest msg in Alcotest.(check check_bytes "sha3_512" resp digest) -let keccak_256 () = +(** Checks Keccak-256 hash function. *) +let test_keccak_256 () = let resp = of_hex "9f3afe7d35d9bbc4efd98252357e73e85ce1234a48603a063bb7079174aafa68" in @@ -189,15 +195,18 @@ let keccak_256 () = Alcotest.(check check_bytes "keccak_256" resp digest) let hash = - [ ("hmac_sha256", `Quick, hmac_sha256); - ("hmac_sha512", `Quick, hmac_sha512); - ("sha256", `Quick, sha256); - ("sha256_seq", `Quick, sha256_seq); - ("sha512", `Quick, sha512); - ("sha3_256", `Quick, sha3_256); - ("sha3_512", `Quick, sha3_512); - ("keccak_256", `Quick, keccak_256) ] - + [ ("hmac_sha256", `Quick, test_hmac_sha256); + ("hmac_sha512", `Quick, test_hmac_sha512); + ("sha256", `Quick, test_sha256); + ("sha256_seq", `Quick, test_sha256_seq); + ("sha512", `Quick, test_sha512); + ("sha3_256", `Quick, test_sha3_256); + ("sha3_512", `Quick, test_sha3_512); + ("keccak_256", `Quick, test_keccak_256) ] + +(** Compares a Blake2b hash from [data_in] with [key] to the expected + output [data_out]. +*) let test_blake2b_direct {data_in; data_key; data_out} = let (Blake2b.Hash h) = Blake2b.direct @@ -207,12 +216,14 @@ let test_blake2b_direct {data_in; data_key; data_out} = in assert (Bytes.(equal data_out h)) +(** Tests Blake2b using [vectors]. *) let blake2b_tests = List.mapi (fun i v -> (string_of_int i, `Quick, fun () -> test_blake2b_direct v)) vectors -let secretbox () = +(** Encrypts then decrypts a message using the Secretbox module. *) +let test_secretbox () = let open Secretbox in let key = genkey () in let nonce = Nonce.gen () in @@ -222,9 +233,12 @@ let secretbox () = assert (secretbox_open ~key ~nonce ~cmsg ~msg:decrypted_msg) ; Alcotest.check check_bytes "secretbox_decrypt" msg decrypted_msg -let secretbox = [("secretbox", `Quick, secretbox)] +let secretbox = [("secretbox", `Quick, test_secretbox)] -let box () = +(** Using Box's precomputation inferface. Encrypts and decrypts + [msg_orig], ensuring the result is the same. +*) +let test_box () = let open Box in let (pk, sk) = keypair () in let k = dh pk sk in @@ -236,10 +250,14 @@ let box () = assert (box_open ~k ~nonce ~cmsg ~msg:decrypted_msg) ; Alcotest.check check_bytes "box" msg_orig decrypted_msg -let box = [("box", `Quick, box)] +let box = [("box", `Quick, test_box)] open Ed25519 +(** Checks that neuterize is deterministic. With the same seed, + generates two keypairs. Checks that they are identical. The public + key has the expected length. +*) let test_keypair_ed25519 () = let seed = Hacl.Rand.gen 32 in match (sk_of_bytes seed, sk_of_bytes seed) with @@ -254,11 +272,15 @@ let test_keypair_ed25519 () = | _ -> assert false +(** Signs the message [msg] with [Sign.sign] and then verifies that it + is accepted by [Sign.verify]. +*) let test_sign_ed25519 () = let (pk, sk) = keypair () in let signature = sign ~sk ~msg in assert (verify ~pk ~msg ~signature) +(** Checks the neuterize function for public key generation. *) let test_public_ed25519 () = let (pk, sk) = keypair () in let pk' = to_bytes pk in diff --git a/src/lib_crypto/test/test_merkle.ml b/src/lib_crypto/test/test_merkle.ml index 8aa820f33e4b..92bf63fe43a5 100644 --- a/src/lib_crypto/test/test_merkle.ml +++ b/src/lib_crypto/test/test_merkle.ml @@ -23,6 +23,13 @@ (* *) (*****************************************************************************) +(** Testing + ------- + Component: Crypto + Invocation: dune build @src/lib_crypto/runtest + Subject: Merkle tree +*) + open Utils.Infix type tree = Empty | Leaf of int | Node of tree * tree @@ -49,6 +56,12 @@ module Merkle = Blake2B.Generic_Merkle_tree (struct let node x y = Node (x, y) end) +(** [compare_list xs ys] returns true if [ys = xs @ tl], where [tl] is + a (potentially empty) repetition of the last element of [xs]; + + e.g., [compare_list [1;2;3] [1;2;3]], + [compare_list [1;2;3] [1;2;3;3;3]] both return true. +*) let rec compare_list xs ys = match (xs, ys) with | ([], []) -> @@ -74,6 +87,9 @@ let check_size i = Format.pp_print_int) l2 +(** A Merkle tree - computed from a range list - that is recast into + a list, yields the same range list. +*) let test_compute _ = List.iter check_size (0 -- 99) let check_path i = @@ -87,6 +103,12 @@ let check_path i = else Format.kasprintf failwith "Failed for %d in %d." j i) l +(** Checks paths in the generated Merkle trees. For each element, + compute its path. Then use check_path to reconstruct the tree and + compute the position of the element. Assert that the reconstructed + tree equals the original tree, and that computed position equals + the original position of the element. +*) let test_path _ = List.iter check_path (0 -- 128) let tests = [("compute", `Quick, test_compute); ("path", `Quick, test_path)] diff --git a/src/lib_crypto/test/test_pvss.ml b/src/lib_crypto/test/test_pvss.ml index 327f310ed34e..9303f12aa1fb 100644 --- a/src/lib_crypto/test/test_pvss.ml +++ b/src/lib_crypto/test/test_pvss.ml @@ -23,7 +23,12 @@ (* *) (*****************************************************************************) -(* pvss tests here *) +(** Testing + ------- + Component: Crypto + Invocation: dune build @src/lib_crypto/runtest + Subject: On Publicly Verifiable Secret Sharing [Schoenmakers, 1999] +*) module Pvss = Pvss_secp256k1 module Sp = Secp256k1_group @@ -135,6 +140,7 @@ end = struct keypairs end +(** Checks the dealer's proof of validity of encrypted shares. *) let test_dealer_proof () = let shr = (Setup.shares, Setup.other_shares) and cmt = (Setup.commitments, Setup.other_commitments) @@ -169,6 +175,9 @@ module Proof = struct let mangle : t -> t = fun (e, es) -> (G.Scalar.(mul e e), es) end +(** A dealer's proof which is meant to be invalid by falsifying it + with [mangle]. +*) let test_invalid_dealer_proof () = let proof : Proof.t = Setup.convert_encoding Pvss.proof_encoding Proof.encoding Setup.proof @@ -185,8 +194,10 @@ let test_invalid_dealer_proof () = ~proof:mangled ~public_keys:Setup.public_keys) ) +(** Checks revealing shares, i.e. each participant honestly decrypts + its share. +*) let test_share_reveal () = - (* check reveal shares *) let shares_valid = List.map2 (fun (share, (reveal, proof)) public_key -> @@ -206,6 +217,7 @@ module Encrypted_share = struct let mangle : t -> t = fun share -> Sp.Group.(share + share) end +(** A dishonestly-revealed share can be checked. *) let test_invalid_share_reveal () = let mangle_share : Pvss.Encrypted_share.t -> Pvss.Encrypted_share.t = fun share -> @@ -235,6 +247,7 @@ let test_invalid_share_reveal () = assert (not b)) shares_valid +(** Reconstruct the shared secret. *) let test_reconstruct () = let indices = [0; 1; 2; 3; 4] in let reconstructed = @@ -257,8 +270,8 @@ let test_reconstruct () = Setup.group_encoding Setup.public_secret) ) +(** Try to reconstruct with n < threshold. *) let test_invalid_reconstruct () = - (* try to reconstruct with n < threshold *) let indices = [0; 1; 2; 3] in let reconstructed = Pvss.reconstruct -- GitLab