diff --git a/src/lib_crypto/base58.ml b/src/lib_crypto/base58.ml index 9b6a483ba..db130c397 100644 --- a/src/lib_crypto/base58.ml +++ b/src/lib_crypto/base58.ml @@ -126,10 +126,12 @@ let safe_encode ?alphabet s = let safe_decode ?alphabet s = raw_decode ?alphabet s |> Option.apply ~f:begin fun s -> let len = String.length s in - let msg = String.sub s 0 (len-4) in - let msg_hash = String.sub s (len-4) 4 in - if msg_hash <> checksum msg then None - else Some msg + if len < 4 then None else + (* only if the string is long enough to extract a checksum do we check it *) + let msg = String.sub s 0 (len-4) in + let msg_hash = String.sub s (len-4) 4 in + if msg_hash <> checksum msg then None + else Some msg end type data = .. diff --git a/src/lib_crypto/test/jbuild b/src/lib_crypto/test/jbuild index 85af0059c..02727b8f9 100644 --- a/src/lib_crypto/test/jbuild +++ b/src/lib_crypto/test/jbuild @@ -1,7 +1,10 @@ (jbuild_version 1) (executables - ((names (test_merkle)) + ((names (test_merkle + test_base58 + test_ed25519 + test_blake2b)) (libraries (tezos-stdlib tezos-crypto alcotest)) @@ -12,15 +15,33 @@ (alias ((name buildtest) - (deps (test_merkle.exe)))) + (deps (test_merkle.exe + test_base58.exe + test_ed25519.exe + test_blake2b.exe)))) (alias ((name runtest_merkle) (action (run ${exe:test_merkle.exe})))) +(alias + ((name runtest_base58) + (action (run ${exe:test_base58.exe})))) + +(alias + ((name runtest_ed25519) + (action (run ${exe:test_ed25519.exe})))) + +(alias + ((name runtest_blake2b) + (action (run ${exe:test_blake2b.exe})))) + (alias ((name runtest) - (deps ((alias runtest_merkle))))) + (deps ((alias runtest_merkle) + (alias runtest_base58) + (alias runtest_ed25519) + (alias runtest_blake2b))))) (alias ((name runtest_indent) diff --git a/src/lib_crypto/test/roundtrips.ml b/src/lib_crypto/test/roundtrips.ml new file mode 100644 index 000000000..796ff642b --- /dev/null +++ b/src/lib_crypto/test/roundtrips.ml @@ -0,0 +1,46 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + + +let test_rt_opt name pp enc dec input = + let encoded = enc input in + match dec encoded with + | Some output -> + if output = input then + () + else + Format.kasprintf failwith + "%s failed for %a: got %a" name pp input pp output + | None -> + Format.kasprintf failwith + "%s failed for %a: unable to decode" name pp input + | exception exc -> + Format.kasprintf failwith + "%s failed for %a: exception whilst decoding: %s" + name pp input (Printexc.to_string exc) + +let test_decode_opt_safe name pp dec encoded = + match dec encoded with + | Some _ | None -> () + | exception exc -> + Format.kasprintf failwith + "%s failed for %a: exception whilst decoding: %s" + name pp encoded (Printexc.to_string exc) + +let test_decode_opt_fail name pp dec encoded = + match dec encoded with + | Some _ -> + Format.kasprintf failwith + "%s failed for %a: successful decoding of invalid input" + name pp encoded + | None -> () + | exception exc -> + Format.kasprintf failwith + "%s failed for %a: exception whilst decoding: %s" + name pp encoded (Printexc.to_string exc) diff --git a/src/lib_crypto/test/test_base58.ml b/src/lib_crypto/test/test_base58.ml new file mode 100644 index 000000000..717435588 --- /dev/null +++ b/src/lib_crypto/test/test_base58.ml @@ -0,0 +1,77 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +let test_roundtrip_safe input = + Roundtrips.test_rt_opt + "safe base58" + Format.pp_print_string + Base58.safe_encode + Base58.safe_decode + input + +let test_roundtrip_raw input = + Roundtrips.test_rt_opt + "raw base58" + Format.pp_print_string + Base58.raw_encode + Base58.raw_decode + input + +let inputs = [ + "abc"; + (string_of_int max_int); + "0"; + "00"; + "000"; + "0000"; + "0000000000000000"; + (String.make 64 '0'); + "1"; + "11"; + "111"; + "1111"; + (String.make 2048 '0'); + "2"; + "22"; + "5"; + "Z"; + (String.make 2048 'Z'); + "z"; + "zz"; + "zzzzzzzz"; + (String.make 2048 'z'); + (*loads of ascii characters: codes between 32 and 126 *) + (String.init 1000 (fun i -> (Char.chr (32 + (i mod (126 - 32)))))); + ""; +] + +let test_roundtrip_safes () = List.iter test_roundtrip_safe inputs + +let test_roundtrip_raws () = List.iter test_roundtrip_raw inputs + + +let test_safety input = + Roundtrips.test_decode_opt_safe + "safe base58" + Format.pp_print_string + Base58.safe_decode + input + +let test_safetys () = List.iter test_safety inputs + +let tests = [ + "safe decoding", `Quick, test_safetys; + "safe encoding/decoding", `Quick, test_roundtrip_safes; + "raw encoding/decoding", `Quick, test_roundtrip_raws; +] + +let () = + Alcotest.run "tezos-crypto" [ + "base58", tests + ] diff --git a/src/lib_crypto/test/test_blake2b.ml b/src/lib_crypto/test/test_blake2b.ml new file mode 100644 index 000000000..c4d44ca22 --- /dev/null +++ b/src/lib_crypto/test/test_blake2b.ml @@ -0,0 +1,51 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +let test_hashed_roundtrip name enc dec input = + (* this wrapper to start with hashing *) + Roundtrips.test_rt_opt + name + (fun fmt (input, _) -> Format.fprintf fmt "%s" input) + (fun (_, hashed) -> enc hashed) + (fun encoded -> match dec encoded with + | None -> None + | Some decoded -> Some (input, decoded) + ) + (input, Blake2B.hash_string [input]) + +let test_roundtrip_hex input = + test_hashed_roundtrip "Hex" Blake2B.to_hex Blake2B.of_hex_opt input + +let test_roundtrip_string input = + test_hashed_roundtrip "String" Blake2B.to_string Blake2B.of_string_opt input + +let inputs = [ + "abc"; + (string_of_int max_int); + "0"; + "00"; + (String.make 64 '0'); + (*loads of ascii characters: codes between 32 and 126 *) + (String.init 1000 (fun i -> (Char.chr (32 + (i mod (126 - 32)))))); + ""; +] + +let test_roundtrip_hexs () = List.iter test_roundtrip_hex inputs + +let test_roundtrip_strings () = List.iter test_roundtrip_string inputs + +let tests = [ + "hash hex/dehex", `Quick, test_roundtrip_hexs; + "hash print/parse", `Quick, test_roundtrip_strings; +] + +let () = + Alcotest.run "tezos-crypto" [ + "blake2b", tests + ] diff --git a/src/lib_crypto/test/test_ed25519.ml b/src/lib_crypto/test/test_ed25519.ml new file mode 100644 index 000000000..572dd0e9a --- /dev/null +++ b/src/lib_crypto/test/test_ed25519.ml @@ -0,0 +1,58 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +let get_keys () = + let seed = Ed25519.Seed.generate () in + Ed25519.generate_seeded_key seed + +module type B58CHECK = sig + type t + val pp: Format.formatter -> t -> unit + include S.B58_DATA with type t := t +end + +let test_b58check_roundtrip + : type t. (module B58CHECK with type t = t) -> t -> unit + = fun m input -> + let module M = (val m) in + Roundtrips.test_rt_opt "b58check" M.pp M.to_b58check M.of_b58check_opt input + +let test_b58check_roundtrips () = + let (pubkey_hash, pubkey, seckey) = get_keys () in + test_b58check_roundtrip (module Ed25519.Public_key_hash) pubkey_hash; + test_b58check_roundtrip (module Ed25519.Public_key) pubkey; + test_b58check_roundtrip (module Ed25519.Secret_key) seckey + + +let test_b58check_invalid input = + Roundtrips.test_decode_opt_fail + "b58check" + Format.pp_print_string + Ed25519.Public_key_hash.of_b58check_opt + input + +let test_b58check_invalids () = + List.iter test_b58check_invalid [ + "ThisIsGarbageNotACheck"; + "\x00"; + (String.make 1000 '\x00'); + (String.make 2048 'a'); + (String.init 2048 (fun _ -> Char.chr (Random.int 256))); + ""; + ] + +let tests = [ + "b58check.roundtrip", `Quick, test_b58check_roundtrips; + "b58check.invalid", `Slow, test_b58check_invalids; +] + +let () = + Alcotest.run "tezos-crypto" [ + "ed25519", tests + ]