Crypto: Only extract checksum when there's one

Specifically, check that there are enough characters to extract the 4-characters
checksum of safe-encoded strings.

The commit also introduces new tests for some parts of the crypto library.
This commit is contained in:
Raphaël Proust 2018-04-17 11:18:59 +08:00 committed by Grégoire Henry
parent 92ee761451
commit cd8a63f543
6 changed files with 262 additions and 7 deletions

View File

@ -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 = ..

View File

@ -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)

View File

@ -0,0 +1,46 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* 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)

View File

@ -0,0 +1,77 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* 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
]

View File

@ -0,0 +1,51 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* 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
]

View File

@ -0,0 +1,58 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* 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
]