From 17ecf12fa377e6ff2b97a14814ef694e2501c467 Mon Sep 17 00:00:00 2001 From: Lesenechal Remi Date: Thu, 21 Nov 2019 17:11:04 +0100 Subject: [PATCH] multisig : non quadratic signature check --- src/test/contracts/multisig.ligo | 29 +++++++------ src/test/multisig_tests.ml | 73 +++++++++++++++++--------------- 2 files changed, 57 insertions(+), 45 deletions(-) diff --git a/src/test/contracts/multisig.ligo b/src/test/contracts/multisig.ligo index e252ba335..90e7e30d7 100644 --- a/src/test/contracts/multisig.ligo +++ b/src/test/contracts/multisig.ligo @@ -12,10 +12,12 @@ type storage_t is record end // I/O types +type message_t is (unit -> list(operation)) +type signatures_t is list(key_hash * signature) type check_message_pt is record counter : counter_t ; - message : (unit -> list(operation)) ; - signatures : list(signature) ; + message : message_t ; + signatures : signatures_t ; end type contract_return_t is (list(operation) * storage_t) @@ -25,7 +27,7 @@ type entry_point_t is function check_message (const param : check_message_pt; const s : storage_t) : contract_return_t is block { - var message : (unit -> list(operation)) := param.message ; + var message : message_t := param.message ; if param.counter =/= s.counter then failwith ("Counters does not match") @@ -34,17 +36,20 @@ function check_message (const param : check_message_pt; bytes_pack((message , param.counter , s.id , get_chain_id)); var valid : nat := 0n ; - for sig in list param.signatures block { - var is_valid : bool := False ; - - for pk in list s.auth block { - if crypto_check(pk,sig,packed_payload) then is_valid := True + var keys : authorized_keys_t := s.auth ; + for pkh_sig in list param.signatures block { + case keys of + | nil -> skip + | key # tl -> block { + keys := tl ; + if pkh_sig.0 = crypto_hash_key(key) then + if crypto_check(key,pkh_sig.1,packed_payload) then valid := valid + 1n ; + else failwith ("Invalid signature") else skip; - }; - - if is_valid then valid := valid + 1n - else failwith ("Invalid signature") + } + end }; + if valid < s.threshold then failwith ("Not enough signatures passed the check") else s.counter := s.counter + 1n ; diff --git a/src/test/multisig_tests.ml b/src/test/multisig_tests.ml index ef3ba594e..af0a1a2da 100644 --- a/src/test/multisig_tests.ml +++ b/src/test/multisig_tests.ml @@ -24,18 +24,18 @@ open Ast_simplified let gen_keys = fun () -> let open Tezos_crypto in - let (_,raw_pk,raw_sk) = Ed25519.generate_key () in - (raw_pk,raw_sk) + let (raw_pkh,raw_pk,raw_sk) = Signature.generate_key () in + (raw_pkh,raw_pk,raw_sk) -let str_keys (raw_pk, raw_sk) = +let str_keys (raw_pkh, raw_pk, raw_sk) = let open Tezos_crypto in - let (pk_str:string) = Base58.simple_encode (Ed25519.Public_key.b58check_encoding) raw_pk in - let (sk_str:string) = Base58.simple_encode (Ed25519.Secret_key.b58check_encoding) raw_sk in - (pk_str,sk_str) + let sk_str = Signature.Secret_key.to_b58check raw_sk in + let pk_str = Signature.Public_key.to_b58check raw_pk in + let pkh_str = Signature.Public_key_hash.to_b58check raw_pkh in + (pkh_str,pk_str,sk_str) -let sign_message (payload : expression) raw_sk : string result = +let sign_message (payload : expression) sk : string result = let open Tezos_crypto in - let (sk : Signature.secret_key) = Signature.Ed25519 raw_sk in let%bind program,_ = get_program () in let%bind code = let env = Ast_typed.program_environment program in @@ -50,7 +50,11 @@ let sign_message (payload : expression) raw_sk : string result = ok signature_str let init_storage threshold counter pkeys = - let keys = List.map (fun el -> e_key @@ fst @@ str_keys el) pkeys in + let keys = List.map + (fun el -> + let (_,pk_str,_) = str_keys el in + e_key @@ pk_str) + pkeys in ez_e_record [ ("id" , e_string "MULTISIG" ) ; ("counter" , e_nat counter ) ; @@ -67,23 +71,25 @@ let chain_id_zero = e_chain_id @@ Tezos_crypto.Base58.simple_encode Tezos_base__TzPervasives.Chain_id.b58check_encoding Tezos_base__TzPervasives.Chain_id.zero -(* sign the same message 'msg' with the secret keys of 'keys' *) -let params counter msg keys = - let aux = fun acc sk -> +(* sign the message 'msg' with 'keys', if 'is_valid'=false the providid signature will be incorrect *) +let params counter msg keys is_validl = + let aux = fun acc (key,is_valid) -> + let (_,_pk,sk) = key in + let (pkh,_,_) = str_keys key in let payload = e_tuple [ msg ; e_nat counter ; - e_string "MULTISIG" ; + e_string (if is_valid then "MULTISIG" else "XX") ; chain_id_zero ] in - let%bind signature = sign_message payload (snd sk) in - ok @@ (e_signature signature)::acc in - let%bind signed_msgs = Trace.bind_fold_list aux [] keys in + let%bind signature = sign_message payload sk in + ok @@ (e_pair (e_key_hash pkh) (e_signature signature))::acc in + let%bind signed_msgs = Trace.bind_fold_list aux [] (List.rev @@ List.combine keys is_validl) in ok @@ e_constructor "CheckMessage" (ez_e_record [ ("counter" , e_nat counter ) ; ("message" , msg) ; - ("signatures" , e_typed_list signed_msgs t_signature ) ; + ("signatures" , e_typed_list signed_msgs (t_pair (t_key_hash,t_signature)) ) ; ]) @@ -92,7 +98,7 @@ let not_enough_1_of_2 () = let%bind program,_ = get_program () in let exp_failwith = "Not enough signatures passed the check" in let keys = gen_keys () in - let%bind test_params = params 0 empty_message [keys] in + let%bind test_params = params 0 empty_message [keys] [true] in let%bind () = expect_string_failwith program "main" (e_pair test_params (init_storage 2 0 [keys;gen_keys()])) exp_failwith in ok () @@ -101,20 +107,20 @@ let unmatching_counter () = let%bind program,_ = get_program () in let exp_failwith = "Counters does not match" in let keys = gen_keys () in - let%bind test_params = params 1 empty_message [keys] in + let%bind test_params = params 1 empty_message [keys] [true] in let%bind () = expect_string_failwith program "main" (e_pair test_params (init_storage 1 0 [keys])) exp_failwith in ok () -(* Provide one invalid signature when the threshold is one of one key *) +(* Provide one invalid signature (correct key but incorrect signature) + when the threshold is one of one key *) let invalid_1_of_1 () = let%bind program,_ = get_program () in let exp_failwith = "Invalid signature" in - let keys = gen_keys () in - let invalid_keys = gen_keys () in - let%bind test_params = params 0 empty_message [keys] in + let keys = [gen_keys ()] in + let%bind test_params = params 0 empty_message keys [false] in let%bind () = expect_string_failwith - program "main" (e_pair test_params (init_storage 1 0 [invalid_keys])) exp_failwith in + program "main" (e_pair test_params (init_storage 1 0 keys)) exp_failwith in ok () (* Provide one valid signature when the threshold is one of one key *) @@ -123,7 +129,7 @@ let valid_1_of_1 () = let keys = gen_keys () in let%bind () = expect_eq_n_trace_aux [0;1;2] program "main" (fun n -> - let%bind params = params n empty_message [keys] in + let%bind params = params n empty_message [keys] [true] in ok @@ e_pair params (init_storage 1 n [keys]) ) (fun n -> @@ -134,11 +140,11 @@ let valid_1_of_1 () = (* Provive two valid signatures when the threshold is two of three keys *) let valid_2_of_3 () = let%bind program,_ = get_program () in - let keys = [gen_keys (); gen_keys ()] in - let st_keys = gen_keys() :: keys in + let param_keys = [gen_keys (); gen_keys ()] in + let st_keys = param_keys @ [gen_keys ()] in let%bind () = expect_eq_n_trace_aux [0;1;2] program "main" (fun n -> - let%bind params = params n empty_message keys in + let%bind params = params n empty_message param_keys [true;true] in ok @@ e_pair params (init_storage 2 n st_keys) ) (fun n -> @@ -147,12 +153,13 @@ let valid_2_of_3 () = ok () (* Provide one invalid signature and two valid signatures when the threshold is two of three keys *) -let invalid_3_of_2 () = +let invalid_3_of_3 () = let%bind program,_ = get_program () in let valid_keys = [gen_keys() ; gen_keys()] in let invalid_key = gen_keys () in - let st_keys = gen_keys () :: valid_keys in - let%bind test_params = params 0 empty_message (invalid_key::valid_keys) in + let param_keys = valid_keys @ [invalid_key] in + let st_keys = valid_keys @ [gen_keys ()] in + let%bind test_params = params 0 empty_message param_keys [false;true;true] in let exp_failwith = "Invalid signature" in let%bind () = expect_string_failwith program "main" (e_pair test_params (init_storage 2 0 st_keys)) exp_failwith in @@ -163,7 +170,7 @@ let not_enough_2_of_3 () = let%bind program,_ = get_program () in let valid_keys = [gen_keys() ; gen_keys()] in let st_keys = gen_keys () :: valid_keys in - let%bind test_params = params 0 empty_message (valid_keys) in + let%bind test_params = params 0 empty_message (valid_keys) [true;true] in let exp_failwith = "Not enough signatures passed the check" in let%bind () = expect_string_failwith program "main" (e_pair test_params (init_storage 3 0 st_keys)) exp_failwith in @@ -176,6 +183,6 @@ let main = test_suite "Multisig" [ test "invalid_1_of_1" invalid_1_of_1 ; test "not_enough_signature" not_enough_1_of_2 ; test "valid_2_of_3" valid_2_of_3 ; - test "invalid_3_of_3" invalid_3_of_2 ; + test "invalid_3_of_3" invalid_3_of_3 ; test "not_enough_2_of_3" not_enough_2_of_3 ; ]