diff --git a/CMakeLists.txt b/CMakeLists.txt index ec4320e..196f1fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,35 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.27) + +# Fix for check_source_compiles: C: needs to be enabled before use. +# set(CMAKE_USER_MAKE_RULES_OVERRIDE "cmake_cpp_rules.cmake") + project(mpc-lib LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_VERBOSE_MAKEFILE ON) + +set(CMAKE_INCLUDE_CURRENT_DIR ON)## Always include the current directory + +set(OPENSSL_USE_STATIC_LIBS TRUE) +find_package(OpenSSL REQUIRED) -if(NOT TARGET OpenSSL::Crypto) - set(OPENSSL_USE_STATIC_LIBS TRUE) - find_package(OpenSSL 1.1.1 EXACT REQUIRED) +set(CMAKE_VERBOSE_MAKEFILE ON) + +if(WIN32) + message("https://cmake.org/cmake/help/latest/variable/WIN32.html?highlight=win32") +elseif(APPLE) + message("https://cmake.org/cmake/help/latest/variable/APPLE.html?highlight=apple") +elseif(UNIX) + message("https://cmake.org/cmake/help/latest/variable/UNIX.html?highlight=unix") + check_library_exists(snappy snappy_compress "" HAVE_SNAPPY) endif() + +# set fpic +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + add_subdirectory(src/common) +enable_testing() +add_subdirectory(test) -if(NOT MPC_LIB_SKIP_TESTS) - enable_testing() - add_subdirectory(test) -endif() diff --git a/diagrams/ecdsa-activity.png b/diagrams/ecdsa-activity.png new file mode 100644 index 0000000..8beb030 Binary files /dev/null and b/diagrams/ecdsa-activity.png differ diff --git a/diagrams/ecdsa-activity.puml b/diagrams/ecdsa-activity.puml new file mode 100644 index 0000000..a5f5567 --- /dev/null +++ b/diagrams/ecdsa-activity.puml @@ -0,0 +1,183 @@ +@startuml +title ECDSA key setup for tests + + + + +package setup { + + abstract class setup_key_persistency { + store_key() + store_key_metadata() + store_auxiliary_keys() + store_keyid_tenant_id() + store_setup_data() + load_setup_data() + store_setup_commitments() + setup_commitments() + delete_temporary_key_data() + } + + setup_key_persistency --|> cmp_key_persistency + + abstract class platform_service { + gen_random() + get_current_tenantid() + get_id_from_keyid() + derive_initial_share() + encrypt_for_player() + decrypt_message() + backup_key() + start_signing() + fill_signing_info_from_metadata() + is_client_id() + } + + class cmp_setup_service { + generate_setup_commitments() + store_setup_commitments() + generate_setup_proofs() + verify_setup_proofs() + create_secret() + + add_user_request() + add_user() + } + + cmp_setup_service --> platform_service + cmp_setup_service --> setup_key_persistency +} + +class cmp_ecdsa_signing_service { + create_mta_request() + ack_mta_request() + create_mta_response() + mta_verify() + + calc_R() + derivation_key_delta() + make_sig_s_positive() + build_aad() + get_algebra() + + platform_service _service + cmp_key_persistency _key_persistency +} + + +package offline { + + class cmp_signature_preprocessed_data { + elliptic_curve_scalar k + elliptic_curve_scalar chi + elliptic_curve_point R + } + + abstract class preprocessing_persistency { + store_preprocessing_metadata() + load_preprocessing_metadata() + + store_preprocessing_data() + load_preprocessing_data() + delete_preprocessing_data() + + create_preprocessed_data() + store_preprocessed_data() + load_preprocessed_data() + delete_preprocessed_data() + } + + class cmp_ecdsa_offline_signing_service { + start_ecdsa_signature_preprocessing() + offline_mta_response() + offline_mta_verify() + + store_presigning_data() + ecdsa_sign() + ecdsa_offline_signature() + cancel_preprocessing() + preprocessing_persistency _preprocessing_persistency + mutex _timing_map_lock + map _timing_map + } + cmp_ecdsa_offline_signing_service --> preprocessing_persistency + + cmp_ecdsa_offline_signing_service::start_ecdsa_signature_preprocessing .. cmp_signature_preprocessed_data +} + +cmp_ecdsa_offline_signing_service --> cmp_ecdsa_signing_service + +class offline_siging_info +{ + offline_siging_info(uint64_t id, const cmp_key_persistency& key_persistency)\n: platform_service(id), signing_service(platform_service, key_persistency, persistency) + sign_platform platform_service + preprocessing_persistency persistency + cmp_ecdsa_offline_signing_service signing_service +} + +offline_siging_info --> cmp_setup_service +offline_siging_info --> cmp_ecdsa_offline_signing_service + +struct players_setup_info { + map players_setup_info +} + +class create_secret { + + // sets up a service for each player + map> services + + create_secret(players, ECDSA_SECP256K1, keyid, pubkey); +} + + +create_secret --> offline_siging_info :uses 1 per player +create_secret --> cmp_setup_service::generate_setup_commitments: calls +create_secret --> cmp_setup_service::store_setup_commitments: calls +create_secret --> cmp_setup_service::generate_setup_proofs: calls +create_secret --> cmp_setup_service::verify_setup_proofs: calls +create_secret --> cmp_setup_service::create_secret: calls + + +class add_user { + add_user(players, new_players, ECDSA_SECP256K1, keyid, new_keyid, pubkey) +} + + +class ecdsa_preprocess{ + ecdsa_preprocess\n(map> services, const string keyid, uint32_t start, uint32_t count, uint32_t total) + + /' + create_preprocessed_data + create_mta_request + + '/ +} +ecdsa_preprocess --> cmp_ecdsa_offline_signing_service::start_ecdsa_signature_preprocessing +' offline_mta_response + + +class ecdsa_sign { + ecdsa_sign(players, ECDSA_SECP256K1, keyid, 1, pubkey, chaincode, {path}) + map> mta_requests + + + /' + (i->second->signing_service.start_signing(keyid, txid, type, data, "", players_str, players_ids, request)) + (i->second->signing_service.mta_response(txid, mta_requests, MPC_CMP_ONLINE_VERSION, response)) + (i->second->signing_service.mta_verify(txid, mta_responses, delta)) + '/ +} + +ecdsa_sign --> start_signing + +class test { + players_setup_info players + ' map players_setup_info +} +test .. players_setup_info: uses +test --> create_secret: calls +test --> ecdsa_sign: calls +test --> add_user: calls +test --> ecdsa_preprocess: calls +@enduml \ No newline at end of file diff --git a/diagrams/ecdsa-msc.puml b/diagrams/ecdsa-msc.puml new file mode 100644 index 0000000..1494845 --- /dev/null +++ b/diagrams/ecdsa-msc.puml @@ -0,0 +1,44 @@ +@startuml + +title ecdsa message sequence chart +hide footbox + +participant test as t + +participant ecdsa_offline_test as ot +participant cmp_ecdsa_offline_signing_service as ss + +participant cmp_ecdsa_signing_service as core +participant persistency as p + +t -> ot : ecdsa_preprocess() + +ot -> ss : start_ecdsa_signature_preprocessing\n(mta_requests) +ss -> p: load_key_metadata() +p --> ss: metadata +ss -> p: create_preprocessed_data() +p --> ss +ss -> core : create_mta_request() +ss -> p: store_preprocessing_data() +p --> ss +core --> ot: mta_requests + +ot -> ss: offline_mta_response(mta_requests) +ss --> ot + +ot -> ss: offline_mta_verify(mta_responses) +ss --> ot + +ot -> ss: store_presigning_data +ss --> ot + + + +t -> ot: ecdsa_sign(partial_sigs) +ot -> ss: ecdsa_sign(partial_sigs) +ss -> p: load_key_meta_data() +p --> ss: metadata +ss --> ot: partial_sigs +ot -> ss: ecdsa_offline_signature\n(partial_sigs, sigs) +ss -> ss: add_scalar\n(&sig.s, sig.s, it->second[i].s) +@enduml \ No newline at end of file diff --git a/diagrams/eddsa.png b/diagrams/eddsa.png new file mode 100644 index 0000000..d2c5726 Binary files /dev/null and b/diagrams/eddsa.png differ diff --git a/diagrams/eddsa.puml b/diagrams/eddsa.puml new file mode 100644 index 0000000..f4ade7d --- /dev/null +++ b/diagrams/eddsa.puml @@ -0,0 +1,105 @@ +@startuml +title EDDSA + +struct asymmetric_eddsa_signature_data { + elliptic_curve_scalar k + elliptic_curve_point R + vector path + byte_vector_t message + uint32_t flags +} + +struct asymmetric_eddsa_signing_metadata { + string key_id + HDChaincode chaincode + vector sig_data + set signers_ids + uint32_t version + uint32_t start_index +} + +asymmetric_eddsa_signing_metadata --> asymmetric_eddsa_signature_data + +struct eddsa_commitment + +class signing_persistency { + create_preprocessed_data() + store_preprocessed_data() + load_preprocessed_data() + delete_preprocessed_data() + + store_commitments() + load_commitments() + delete_commitments() + + store_signing_data() + load_signing_data() + delete_signing_data() +} +signing_persistency --> asymmetric_eddsa_signing_metadata +signing_persistency --> eddsa_commitment + +struct Rs_and_commitments { + vector Rs + eddsa_commitment R_commitment +} + +class asymmetric_eddsa_cosigner +{ + derivation_key_delta() + commit_to_r() + + verify_commit_to_r() + verify_commit_to_r() + + platform_service _service + cmp_key_persistency _key_persistency + elliptic_curve256_algebra_ctx_t _ctx +} + + +asymmetric_eddsa_cosigner --> cmp_key_persistency +asymmetric_eddsa_cosigner --> platform_service + + +abstract class preprocessing_persistency { + create_preprocessed_data() + store_preprocessed_data() + load_preprocessed_data() + delete_preprocessed_data() +} + +class asymmetric_eddsa_cosigner_client { + start_signature_preprocessing() + eddsa_sign_offline() + + preprocessing_persistency _preprocessing_persistency +} +asymmetric_eddsa_cosigner_client --|> asymmetric_eddsa_cosigner +asymmetric_eddsa_cosigner_client --> preprocessing_persistency + + +class asymmetric_eddsa_cosigner_server { + store_presigning_data() + + eddsa_sign_offline() + decommit_r() + broadcast_r() + broadcast_si() + get_eddsa_signature() + + cancel_signing() + + signing_persistency _signing_persistency + mutex _timing_map_lock + map _timing_map +} + + +asymmetric_eddsa_cosigner_server --|> asymmetric_eddsa_cosigner +asymmetric_eddsa_cosigner_server --> signing_persistency +asymmetric_eddsa_cosigner_server --> eddsa_signature +asymmetric_eddsa_cosigner_server --> Rs_and_commitments + + +@enduml diff --git a/diagrams/mpc-lib.png b/diagrams/mpc-lib.png new file mode 100644 index 0000000..7103150 Binary files /dev/null and b/diagrams/mpc-lib.png differ diff --git a/diagrams/mpc-lib.puml b/diagrams/mpc-lib.puml new file mode 100644 index 0000000..8932b60 --- /dev/null +++ b/diagrams/mpc-lib.puml @@ -0,0 +1,356 @@ +@startuml + +title mpc-lib +'- cmp_signature_preprocessed_data.h + + + + +'- key id +'- request id +' void cmp_ecdsa_offline_signing_service::ecdsa_sign + +' cmp_ecdsa_online_signing_service::get_si( +' clac sig.s = k(m + r * delta) +r(k * x + Chi) + +' s = k ^-1 e + r (k^-1 *aplha + Beta - Beta) +' where e is message +' Calculate s = k−1 (z + r dA) mod n. If s=0, go back to step 3. +' r is x of public hey + + +/' +throw_cosigner_exception(GFp_curve_algebra_mul_scalars(curve, &tmp, sig.r, sizeof(elliptic_curve256_scalar_t), delta.data, sizeof(elliptic_curve256_scalar_t))); + +'/ +package mta { + struct cmp_mta_message { + byte_vector_t message + byte_vector_t commitment + byte_vector_t proof + } + + + struct cmp_mta_request { + cmp_mta_message mta + std::map mta_proofs + elliptic_curve_point A + elliptic_curve_point B + elliptic_curve_point Z + } + + cmp_mta_request --> cmp_mta_message + + + + struct cmp_mta_response { + map k_gamma_mta + map k_x_mta + elliptic_curve_point GAMMA + map gamma_proofs + } + + struct cmp_mta_responses { + commitments_sha256_t ack + vector response + } + + cmp_mta_responses --> cmp_mta_response + + struct cmp_mta_deltas { + elliptic_curve_scalar delta + elliptic_curve_point DELTA + byte_vector_t proof + } + +} + +package types { + enum SIGNING_FLAGS { + NONE + POSITIVE_R + EDDSA_KECCAK + } + + struct signing_block_data { + byte_vector_t data + vector path + } + + struct signing_data + { + HDChaincode chaincode + vector blocks + } + + signing_data --> signing_block_data + + struct recoverable_signature { + elliptic_curve256_scalar_t r + elliptic_curve256_scalar_t s + uint8_t v + } + + struct eddsa_signature { + ed25519_point_t R + ed25519_scalar_t s + } + + struct ecdsa_signing_public_data { + elliptic_curve_point A + elliptic_curve_point B + elliptic_curve_point Z + elliptic_curve_point GAMMA + byte_vector_t gamma_commitment + } + + struct ecdsa_signing_data { + elliptic_curve_scalar k + elliptic_curve_scalar gamma + elliptic_curve_scalar a + elliptic_curve_scalar b + elliptic_curve_scalar delta + elliptic_curve_scalar chi + elliptic_curve_point GAMMA + byte_vector_t mta_request + map G_proofs + map public_data + } + + ecdsa_signing_data --> ecdsa_signing_public_data +} + +class cmp_player_info { + elliptic_curve_point public_share + paillier_public_key paillier + ring_pedersen_public ring_pedersen +} + +class cmp_key_metadata{ + elliptic_curve256_point_t public_key + uint8_t t + uint8_t n + cosigner_sign_algorithm algorithm + uint64_t ttl + commitments_sha256_t seed + map players_info +} + +cmp_key_metadata --> cmp_player_info + + +struct auxiliary_keys { + shared_ptr paillier + shared_ptr ring_pedersen +} + + +abstract class platform_service { + gen_random() + get_current_tenantid() + get_id_from_keyid() + derive_initial_share() + encrypt_for_player() + decrypt_message() + backup_key() + start_signing() + fill_signing_info_from_metadata() + is_client_id() +} +platform_service -> cmp_key_metadata + +abstract class cmp_key_persistency { + key_exist() + load_key() + get_tenantid_from_keyid() + + load_key_metadata() + load_auxiliary_keys() +} +cmp_key_persistency --> auxiliary_keys +cmp_key_persistency --> cmp_key_metadata + +package setup { + + abstract class setup_key_persistency { + store_key() + store_key_metadata() + store_auxiliary_keys() + store_keyid_tenant_id() + store_setup_data() + load_setup_data() + store_setup_commitments() + setup_commitments() + delete_temporary_key_data() + } + + setup_key_persistency --|> cmp_key_persistency + + + class cmp_setup_service { + generate_setup_commitments() + store_setup_commitments() + generate_setup_proofs() + verify_setup_proofs() + create_secret() + + add_user_request() + add_user() + } + + cmp_setup_service --> platform_service + cmp_setup_service --> setup_key_persistency +} + +class eddsa_signature_data { + elliptic_curve_scalar k + elliptic_curve_point R + elliptic_curve_scalar s + vector path + byte_vector_t message + uint32_t flags +} + +class eddsa_signing_metadata { + string key_id + HDChaincode chaincode + vector sig_data + set signers_ids + uint32_t version +} + +eddsa_signing_metadata --> eddsa_signature_data + +abstract class signing_persistency { + store_signing_data() + load_signing_data() + update_signing_data() + store_signing_commitments() + load_signing_commitments() + delete_signing_data() +} + +signing_persistency --> eddsa_signing_metadata + + +class cmp_ecdsa_online_signing_service { + start_signing() + store_commitments() + broadcast_si() + get_eddsa_signature() + + cancel_signing() + + platform_service _service + cmp_key_persistency _key_persistency + signing_persistency _signing_persistency +} + +cmp_ecdsa_online_signing_service --> signing_persistency + +package offline { + + class cmp_signature_preprocessed_data { + elliptic_curve_scalar k + elliptic_curve_scalar chi + elliptic_curve_point R + } + + abstract class preprocessing_persistency { + store_preprocessing_metadata() + load_preprocessing_metadata() + + store_preprocessing_data() + load_preprocessing_data() + delete_preprocessing_data() + + create_preprocessed_data() + store_preprocessed_data() + load_preprocessed_data() + delete_preprocessed_data() + } + + preprocessing_persistency --> cmp_signature_preprocessed_data + + + class cmp_ecdsa_offline_signing_service { + start_ecdsa_signature_preprocessing() + offline_mta_response() + offline_mta_verify() + + store_presigning_data() + ecdsa_sign() + ecdsa_offline_signature() + cancel_preprocessing() + preprocessing_persistency _preprocessing_persistency + mutex _timing_map_lock + map _timing_map + } + + cmp_ecdsa_offline_signing_service --> preprocessing_persistency + + + abstract class offline_refresh_key_persistency { + load_refresh_key_seeds() + + store_refresh_key_seeds() + delete_refresh_key_seeds() + + transform_preprocessed_data_and_store_temporary() + commit() + + delete_temporary_key() + store_temporary_key() + } + + + class cmp_offline_refresh_service { + refresh_key_request() + + refresh_key() + refresh_key_fast_ack() + cancel_refresh_key() + + get_algebra() + + platform_service _service + cmp_key_persistency _key_persistency + offline_refresh_key_persistency _refresh_key_persistency + } + cmp_offline_refresh_service --> offline_refresh_key_persistency + cmp_offline_refresh_service --> cmp_key_persistency + +} + +class cmp_ecdsa_signing_service { + create_mta_request() + ack_mta_request() + create_mta_response() + mta_verify() + + calc_R() + derivation_key_delta() + make_sig_s_positive() + build_aad() + get_algebra() + + platform_service _service + cmp_key_persistency _key_persistency +} +note right +this class holds the common functionality for +* cmp_ecdsa_online_signing_service and +* cmp_ecdsa_offline_signing_service +end note + + +cmp_ecdsa_signing_service --> platform_service +cmp_ecdsa_signing_service --> cmp_key_persistency +cmp_ecdsa_signing_service --> cmp_mta_request + +cmp_ecdsa_offline_signing_service --|> cmp_ecdsa_signing_service +cmp_ecdsa_online_signing_service --|> cmp_ecdsa_signing_service + + + +@enduml diff --git a/diagrams/tests.png b/diagrams/tests.png new file mode 100644 index 0000000..b030ad8 Binary files /dev/null and b/diagrams/tests.png differ diff --git a/diagrams/tests.puml b/diagrams/tests.puml new file mode 100644 index 0000000..2f003db --- /dev/null +++ b/diagrams/tests.puml @@ -0,0 +1,56 @@ +@startuml +title Tests + +state eddsa { + state eddsa_offline_test { + } + + state eddsa_online_test { + } + +} +note bottom of eddsa +Not drawn as we are not interested in eddsa +end note + +state setup_test { + + state setup { + [*] --> Section_secp256k1 + Section_secp256k1 --> Section_ed25519: create_secret\n(players, ECDSA_SECP256K1, keyid, pubkey) + Section_ed25519 --> Section_stark: create_secret\n(players, ECDSA_SECP256R1, keyid, pubkey) + Section_stark --> Section_3of3: create_secret\n(players, ECDSA_STARK, keyid, pubkey) + Section_3of3 --> [*] : create_secret\n(players, ECDSA_SECP256K1, keyid, pubkey) + } + + state add_user { + [*] --> Section_secp256k1_1 + Section_secp256k1_1 --> Section_secp256k1_2: create_secret\n(players, ECDSA_SECP256K1, keyid, pubkey) + Section_secp256k1_2 --> Section_ed25519_1: add_user\n(players, new_players, ECDSA_SECP256K1, keyid, new_keyid, pubkey) + Section_ed25519_1 --> Section_ed25519_2: create_secret\n(players, ECDSA_SECP256R1, keyid, pubkey) + Section_ed25519_2 --> Section_stark_1: add_user\n(players, new_players, ECDSA_SECP256R1, keyid, new_keyid, pubkey) + Section_stark_1 --> Section_stark_2: create_secret\n(players, ECDSA_STARK, keyid, pubkey) + Section_stark_2 --> [*]: add_user\n(players, new_players, ECDSA_STARK, keyid, new_keyid, pubkey) + } +} + +state ecdsa_online_test { + [*] --> create_secret + create_secret --> sign: create_secret\n(players, ECDSA_SECP256K1, keyid, pubkey) + sign --> add_user_1: eddsa_sign\n(players, keyid, 1, pubkey, chaincode, path) + add_user_1 --> sign_multiple: add_user\n(players, new_players, EDDSA_ED25519, keyid, new_keyid, pubkey)\neddsa_sign\n(new_players, new_keyid, 1, pubkey, chaincode, {path}); + sign_multiple --> mt: eddsa_sign\n(players, keyid, COUNT, pubkey, chaincode, derivation_paths) + mt --> keccek: pthread_create\n(threads + i, NULL, sign_thread, ¶m) + keccek --> [*]: eddsa_sign\n(players, keyid, 1, pubkey, chaincode, {path}, true) + +} + +state ecdsa_offline_test { + + [*] --> Section_secp256k1_a + Section_secp256k1_a --> mt_a: create_secret\n(players, ECDSA_SECP256K1, keyid, pubkey)\n\necdsa_preprocess\n(services, keyid, 0, BLOCK_SIZE, BLOCK_SIZE)\n\necdsa_sign\n(services, ECDSA_SECP256K1, keyid, 0, 1, pubkey, chaincode, path)\n\nkey_refresh\n(refresh_info, keyid, pubkey)\n\necdsa_sign\n(services, ECDSA_SECP256K1, keyid, 9, 1, pubkey, chaincode, derivation_paths) + mt_a --> secp256r1_a: create_secret\n(players, ECDSA_SECP256K1, keyid, pubkey)\n\npthread_create\n(threads + i, NULL, sign_thread, ¶m)\n\necdsa_sign\n(services, ECDSA_SECP256K1, keyid, 0, derivation_paths.size(), pubkey, chaincode, derivation_paths) + secp256r1_a --> stark_a: create_secret\n(players, ECDSA_SECP256R1, keyid, pubkey)\n\necdsa_preprocess\n(services, keyid, 0, BLOCK_SIZE, BLOCK_SIZE)\n\n ecdsa_sign\n(services, ECDSA_SECP256R1, keyid, 0, 1, pubkey, chaincode, {path})\n\nadd_user\n(players, new_players, ECDSA_SECP256R1, keyid, new_keyid, pubkey)\n\necdsa_preprocess\n(new_services, new_keyid, 0, BLOCK_SIZE, BLOCK_SIZE)\n\necdsa_sign\n(new_services, ECDSA_SECP256R1, new_keyid, 0, 1, pubkey, chaincode, {path}) + stark_a --> [*]: create_secre\n(players, ECDSA_STARK, keyid, pubkey)\n\necdsa_preprocess\n(services, keyid, 0, BLOCK_SIZE, BLOCK_SIZE)\n\necdsa_sign\n(services, ECDSA_STARK, keyid, 0, 1, pubkey, chaincode, {path}) +} +@enduml \ No newline at end of file diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 47227d6..76e2d45 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -43,9 +43,9 @@ target_compile_options(cosigner PRIVATE ) set(LINKER_VERSION_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/lib.lds) -target_link_options(cosigner PRIVATE - "LINKER:--version-script=${LINKER_VERSION_SCRIPT}" - "LINKER:--no-undefined") +#target_link_options(cosigner PRIVATE +# "LINKER:--version-script=${LINKER_VERSION_SCRIPT}" +# "LINKER:--no-undefined") set_target_properties(cosigner PROPERTIES LINK_DEPENDS ${LINKER_VERSION_SCRIPT}) target_include_directories(cosigner PUBLIC ${PROJECT_SOURCE_DIR}/include) diff --git a/src/common/crypto/GFp_curve_algebra/GFp_curve_algebra.c b/src/common/crypto/GFp_curve_algebra/GFp_curve_algebra.c index 7c77a83..3ac9971 100644 --- a/src/common/crypto/GFp_curve_algebra/GFp_curve_algebra.c +++ b/src/common/crypto/GFp_curve_algebra/GFp_curve_algebra.c @@ -2,7 +2,22 @@ #include #include + +#if HAVE_BYTESWAP_H #include +#else +#define bswap_16(value) \ +((((value) & 0xff) << 8) | ((value) >> 8)) + +#define bswap_32(value) \ +(((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \ +(uint32_t)bswap_16((uint16_t)((value) >> 16))) + +#define bswap_64(value) \ +(((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) \ +<< 32) | \ +(uint64_t)bswap_32((uint32_t)((value) >> 32))) +#endif #include #include diff --git a/src/common/crypto/ed25519_algebra/ed25519_algebra.c b/src/common/crypto/ed25519_algebra/ed25519_algebra.c index cb9b115..2b50361 100644 --- a/src/common/crypto/ed25519_algebra/ed25519_algebra.c +++ b/src/common/crypto/ed25519_algebra/ed25519_algebra.c @@ -3,7 +3,21 @@ #include "crypto/keccak1600/keccak1600.h" #include "curve25519.c" +#if HAVE_BYTESWAP_H #include +#else +#define bswap_16(value) \ +((((value) & 0xff) << 8) | ((value) >> 8)) + +#define bswap_32(value) \ +(((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \ +(uint32_t)bswap_16((uint16_t)((value) >> 16))) + +#define bswap_64(value) \ +(((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) \ +<< 32) | \ +(uint64_t)bswap_32((uint32_t)((value) >> 32))) +#endif #include #include diff --git a/src/common/crypto/zero_knowledge_proof/diffie_hellman_log.c b/src/common/crypto/zero_knowledge_proof/diffie_hellman_log.c index 8eefd5d..e9636f3 100644 --- a/src/common/crypto/zero_knowledge_proof/diffie_hellman_log.c +++ b/src/common/crypto/zero_knowledge_proof/diffie_hellman_log.c @@ -1,7 +1,22 @@ #include "crypto/zero_knowledge_proof/diffie_hellman_log.h" #include "crypto/drng/drng.h" +#if HAVE_BYTESWAP_H #include +#else +#define bswap_16(value) \ +((((value) & 0xff) << 8) | ((value) >> 8)) + +#define bswap_32(value) \ +(((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \ +(uint32_t)bswap_16((uint16_t)((value) >> 16))) + +#define bswap_64(value) \ +(((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) \ +<< 32) | \ +(uint64_t)bswap_32((uint32_t)((value) >> 32))) +#endif #include + #include #define LOG_ZKP_SALT "diffie hellman discrete log zkp" diff --git a/test/cosigner/CMakeLists.txt b/test/cosigner/CMakeLists.txt index 73fa251..8ef8645 100644 --- a/test/cosigner/CMakeLists.txt +++ b/test/cosigner/CMakeLists.txt @@ -1,8 +1,8 @@ add_executable(cosigner_test ecdsa_offline_test.cpp ecdsa_online_test.cpp - eddsa_offline_test.cpp - eddsa_online_test.cpp + #eddsa_offline_test.cpp + #eddsa_online_test.cpp main.cpp setup_test.cpp ) @@ -15,3 +15,8 @@ pkg_check_modules(UUID REQUIRED IMPORTED_TARGET uuid) target_link_libraries(cosigner_test PRIVATE cosigner Threads::Threads PkgConfig::UUID) add_test(NAME cosigner_test COMMAND cosigner_test) + + +add_executable(murphy_cosigner test_info.h signing_test.h setup_test_info.cc signing_test.cc murphy_ecdsa_test.cc) +target_link_libraries(murphy_cosigner PRIVATE OpenSSL::Crypto cosigner) + diff --git a/test/cosigner/eddsa_offline_test.cpp b/test/cosigner/eddsa_offline_test.cpp index a1058b6..219c977 100644 --- a/test/cosigner/eddsa_offline_test.cpp +++ b/test/cosigner/eddsa_offline_test.cpp @@ -69,7 +69,8 @@ class client_persistency : public asymmetric_eddsa_cosigner_client::preprocessin std::lock_guard lock(_mutex); if (_preprocessed_data.find(key_id) != _preprocessed_data.end()) throw cosigner_exception(cosigner_exception::INVALID_TRANSACTION); - _preprocessed_data.emplace(key_id, std::move(std::vector(size))); + //_preprocessed_data.emplace(key_id, std::move(std::vector(size))); + _preprocessed_data.emplace(key_id, std::vector(size)); } void store_preprocessed_data(const std::string& key_id, uint64_t index, const ed25519_scalar_t& k) override diff --git a/test/cosigner/murphy_ecdsa_test.cc b/test/cosigner/murphy_ecdsa_test.cc new file mode 100644 index 0000000..3b0a717 --- /dev/null +++ b/test/cosigner/murphy_ecdsa_test.cc @@ -0,0 +1,108 @@ +#include +#include +#include +#include + +#include "cosigner/cmp_ecdsa_offline_signing_service.h" +#include "cosigner/cosigner_exception.h" +#include "cosigner/cmp_signature_preprocessed_data.h" +#include "cosigner/cmp_offline_refresh_service.h" +#include "cosigner/types.h" +#include "test_info.h" +#include "signing_test.h" +#include "crypto/elliptic_curve_algebra/elliptic_curve256_algebra.h" +#include "crypto/GFp_curve_algebra/GFp_curve_algebra.h" +#include "cosigner/cmp_key_persistency.h" +#include "cosigner/mpc_globals.h" + + + +using Clock = std::conditional::type; + +const uint32_t BLOCK_SIZE = 10; + +constexpr char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + +std::string binTohexStr(const std::unique_ptr& data, int len) +{ + std::string s(len * 2, ' '); + for (int i = 0; i < len; ++i) { + s[2 * i] = hexmap[(data.get()[i] & 0xF0) >> 4]; + s[2 * i + 1] = hexmap[data.get()[i] & 0x0F]; + } + return s; +} + +std::string UintToHex(const std::vector& UintRep){ + std::unique_ptr uncharRep (new unsigned char[UintRep.size()]); + int index(0); + for(std::vector::const_iterator iter = UintRep.begin(); iter != UintRep.end(); ++iter){ + uncharRep[index++] = *iter; + } + return (binTohexStr(uncharRep, UintRep.size())); +} + +std::string ecpoint_TohexStr(const elliptic_curve256_point_t& data, int len) +{ + std::string s(len * 2, ' '); + for (int i = 0; i < len; ++i) { + s[2 * i] = hexmap[(data[i] & 0xF0) >> 4]; + s[2 * i + 1] = hexmap[data[i] & 0x0F]; + } + return s; +} + +int main(int argc, char* argv[]){ + std::cout << "hello" << std::endl; + fireblocks::common::cosigner::byte_vector_t chaincode(32, '\0'); + std::vector path = {44, 0, 0, 0, 0}; + char keyid[37] = {0}; + elliptic_curve256_point_t pubkey; + + // typedef std::map players_setup_info; + // setup_persistency has an internal structure with the private keys + players_setup_info players; + + uuid_t uid; + uuid_generate_random(uid); +#if 0 + std::cout << std::hex << std::setfill('0'); ; + + for (int i = 0; i < sizeof(uid); i++) { + std::cout << std::setw(2) << static_cast(uid[i]); + if (i == 3 || i == 5 || i == 7 || i == 9) { + printf("-"); + } + } +#endif + std::cout << std::endl; + uuid_unparse(uid, keyid); + std::cout << keyid << std::endl; + players.clear(); + players[1]; + players[2]; + players[3]; + create_secret(players, keyid, pubkey); + for(auto i = players.begin(); i != players.end(); ++ i){ + std::cout << i->first << "\t" << i->second.dump_key(keyid) << std::endl; + std::cout << "Public Key -> " << ecpoint_TohexStr(pubkey, 33) << std::endl; + } + + std::map> services; + for (auto i = players.begin(); i != players.end(); ++i) + { + auto info = std::make_unique(i->first, i->second); + services.emplace(i->first, move(info)); + } + + auto before = Clock::now(); + ecdsa_preprocess(services, keyid, 0, BLOCK_SIZE, BLOCK_SIZE); + auto after = Clock::now(); + std::cout << "ECDSA preprocessing took: " << std::chrono::duration_cast(after - before).count() << " ms" << std::endl; + + ecdsa_sign(services, ECDSA_SECP256K1, keyid, 0, 1, pubkey, chaincode, {path}); + + return 0; +} \ No newline at end of file diff --git a/test/cosigner/setup_test_info.cc b/test/cosigner/setup_test_info.cc new file mode 100644 index 0000000..cdc35dc --- /dev/null +++ b/test/cosigner/setup_test_info.cc @@ -0,0 +1,184 @@ +#include +#include +#include + +#include "cosigner/cosigner_exception.h" +#include "cosigner/cmp_key_persistency.h" + + +std::string setup_persistency::dump_key(const std::string& key_id) const + { + auto it = _keys.find(key_id); + if (it == _keys.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::BAD_KEY); + return HexStr(it->second.private_key, &it->second.private_key[sizeof(elliptic_curve256_scalar_t)]); + } + +bool setup_persistency::key_exist(const std::string& key_id) const +{ + return _keys.find(key_id) != _keys.end(); +} + +void setup_persistency::load_key(const std::string& key_id, cosigner_sign_algorithm& algorithm, elliptic_curve256_scalar_t& private_key) const +{ + auto it = _keys.find(key_id); + if (it == _keys.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::BAD_KEY); + memcpy(private_key, it->second.private_key, sizeof(elliptic_curve256_scalar_t)); + algorithm = it->second.algorithm; +} + +const std::string setup_persistency::get_tenantid_from_keyid(const std::string& key_id) const +{ + return TENANT_ID; +} + +void setup_persistency::load_key_metadata(const std::string& key_id, fireblocks::common::cosigner::cmp_key_metadata& metadata, bool full_load) const +{ + auto it = _keys.find(key_id); + if (it == _keys.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::BAD_KEY); + metadata = it->second.metadata; +} + +void setup_persistency::load_auxiliary_keys(const std::string& key_id, fireblocks::common::cosigner::auxiliary_keys& aux) const +{ + auto it = _keys.find(key_id); + if (it == _keys.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::BAD_KEY); + aux = it->second.aux_keys; +} + +void setup_persistency::store_key(const std::string& key_id, cosigner_sign_algorithm algorithm, const elliptic_curve256_scalar_t& private_key, uint64_t ttl) +{ + auto& info = _keys[key_id]; + memcpy(info.private_key, private_key, sizeof(elliptic_curve256_scalar_t)); + info.algorithm = algorithm; +} + +void setup_persistency::store_key_metadata(const std::string& key_id, const fireblocks::common::cosigner::cmp_key_metadata& metadata) +{ + auto& info = _keys[key_id]; + info.metadata = metadata; +} + +void setup_persistency::store_auxiliary_keys(const std::string& key_id, const fireblocks::common::cosigner::auxiliary_keys& aux) +{ + auto& info = _keys[key_id]; + info.aux_keys = aux; +} + +void setup_persistency::store_keyid_tenant_id(const std::string& key_id, const std::string& tenant_id) {} + +void setup_persistency::store_setup_data(const std::string& key_id, const fireblocks::common::cosigner::setup_data& metadata) +{ + _setup_data[key_id] = metadata; +} + +void setup_persistency::load_setup_data(const std::string& key_id, fireblocks::common::cosigner::setup_data& metadata) +{ + metadata = _setup_data[key_id]; +} + +void setup_persistency::store_setup_commitments(const std::string& key_id, const std::map& commitments) +{ + _commitments[key_id] = commitments; +} + +void setup_persistency::load_setup_commitments(const std::string& key_id, std::map& commitments) +{ + commitments = _commitments[key_id]; +} + +void setup_persistency::delete_temporary_key_data(const std::string& key_id, bool delete_key) +{ + _setup_data.erase(key_id); + _commitments.erase(key_id); + if (delete_key) + _keys.erase(key_id); +} + +void create_secret(players_setup_info& players, const std::string& keyid, elliptic_curve256_point_t& pubkey){ + + // hard-coded to work only with secp256k1 + std::unique_ptr algebra(elliptic_curve256_new_secp256k1_algebra(), elliptic_curve256_algebra_ctx_free); + const size_t PUBKEY_SIZE = algebra->point_size(algebra.get()); + memset(pubkey, 0, sizeof(elliptic_curve256_point_t)); + + std::cout << "keyid = " << keyid << std::endl; + std::vector players_ids; + + + std::map> services; + for (auto i = players.begin(); i != players.end(); ++i) + { + std::cout << "Setting up the services " << std::endl; + services.emplace(i->first, std::make_unique(i->first, i->second)); + players_ids.push_back(i->first); + } + + std::map commitments; + for (auto i = services.begin(); i != services.end(); ++i) + { + fireblocks::common::cosigner::commitment& commitment = commitments[i->first]; + //REQUIRE_NOTHROW(i->second->setup_service.generate_setup_commitments(keyid, TENANT_ID, type, players_ids, players_ids.size(), 0, {}, commitment)); + i->second->setup_service.generate_setup_commitments(keyid, TENANT_ID, ECDSA_SECP256K1, players_ids, players_ids.size(), 0, {}, commitment); + } + + std::map decommitments; + for (auto i = services.begin(); i != services.end(); ++i) + { + fireblocks::common::cosigner::setup_decommitment& decommitment = decommitments[i->first]; + //REQUIRE_NOTHROW(i->second->setup_service.store_setup_commitments(keyid, commitments, decommitment)); + i->second->setup_service.store_setup_commitments(keyid, commitments, decommitment); + } + commitments.clear(); + + std::map proofs; + for (auto i = services.begin(); i != services.end(); ++i) + { + fireblocks::common::cosigner::setup_zk_proofs& proof = proofs[i->first]; + //REQUIRE_NOTHROW(i->second->setup_service.generate_setup_proofs(keyid, decommitments, proof)); + i->second->setup_service.generate_setup_proofs(keyid, decommitments, proof); + } + decommitments.clear(); + + std::map> paillier_large_factor_proofs; + for (auto i = services.begin(); i != services.end(); ++i) + { + auto& proof = paillier_large_factor_proofs[i->first]; + //REQUIRE_NOTHROW(i->second->setup_service.verify_setup_proofs(keyid, proofs, proof)); + i->second->setup_service.verify_setup_proofs(keyid, proofs, proof); + } + proofs.clear(); + + bool first = true; + for (auto i = services.begin(); i != services.end(); ++i) + { + std::string public_key; + cosigner_sign_algorithm algorithm; + + //REQUIRE_NOTHROW(i->second->setup_service.create_secret(keyid, paillier_large_factor_proofs, public_key, algorithm)); + i->second->setup_service.create_secret(keyid, paillier_large_factor_proofs, public_key, algorithm); + assert(algorithm == ECDSA_SECP256K1); + + assert(public_key.size() == PUBKEY_SIZE); + if (first) + { + first = false; + memcpy(pubkey, public_key.data(), PUBKEY_SIZE); + } + else + { + assert(memcmp(pubkey, public_key.data(), PUBKEY_SIZE) == 0); + } + } + paillier_large_factor_proofs.clear(); + + std::cout << "public key: " << HexStr(pubkey, &pubkey[PUBKEY_SIZE]) << std::endl; + for (auto i = players.begin(); i != players.end(); ++i) + { + std::cout << "player " << i->first << " share: " << i->second.dump_key(keyid) << std::endl; + } + return; +} \ No newline at end of file diff --git a/test/cosigner/signing_test.cc b/test/cosigner/signing_test.cc new file mode 100644 index 0000000..15c7e06 --- /dev/null +++ b/test/cosigner/signing_test.cc @@ -0,0 +1,174 @@ +#include +#include "signing_test.h" +#include "crypto/GFp_curve_algebra/GFp_curve_algebra.h" + #include +#include + +void ecdsa_preprocess(std::map>& services, const std::string& keyid, uint32_t start, uint32_t count, uint32_t total){ + uuid_t uid; + char request[37] = {0}; + uuid_generate_random(uid); + uuid_unparse(uid, request); + std::cout << "request id = " << request << std::endl; + + std::set players_ids; + for (auto i = services.begin(); i != services.end(); ++i) + players_ids.insert(i->first); + + std::map> mta_requests; + for (auto i = services.begin(); i != services.end(); ++i){ + auto& mta_request = mta_requests[i->first]; + //REQUIRE_NOTHROW(i->second->signing_service.start_ecdsa_signature_preprocessing(TENANT_ID, keyid, request, start, count, total, players_ids, mta_request)); + i->second->signing_service.start_ecdsa_signature_preprocessing(TENANT_ID, keyid, request, start, count, total, players_ids, mta_request); + } + + std::map mta_responses; + for (auto i = services.begin(); i != services.end(); ++i) + { + auto& response = mta_responses[i->first]; + i->second->signing_service.offline_mta_response(request, mta_requests, response); + } + mta_requests.clear(); + + std::map> deltas; + for (auto i = services.begin(); i != services.end(); ++i){ + auto& delta = deltas[i->first]; + //REQUIRE_NOTHROW(i->second->signing_service.offline_mta_verify(request, mta_responses, delta)); + i->second->signing_service.offline_mta_verify(request, mta_responses, delta); + } + mta_responses.clear(); + + std::map> sis; + for (auto i = services.begin(); i != services.end(); ++i){ + auto& si = sis[i->first]; + std::string key_id; + //REQUIRE_NOTHROW(i->second->signing_service.store_presigning_data(request, deltas, key_id)); + i->second->signing_service.store_presigning_data(request, deltas, key_id); + assert(key_id == keyid); + } +} + +void ecdsa_sign(std::map>& services, cosigner_sign_algorithm type, + const std::string& keyid, uint32_t start_index, uint32_t count, const elliptic_curve256_point_t& pubkey, + const fireblocks::common::cosigner::byte_vector_t& chaincode, const std::vector>& paths, bool positive_r){ + uuid_t uid; + char txid[37] = {0}; + uuid_generate_random(uid); + uuid_unparse(uid, txid); + std::cout << "txid id = " << txid << std::endl; + + std::set players_ids; + std::set players_str; + for (auto i = services.begin(); i != services.end(); ++i){ + players_ids.insert(i->first); + players_str.insert(std::to_string(i->first)); + i->second->platform_service.set_positive_r(positive_r); + } + + assert(chaincode.size() == sizeof(HDChaincode)); + fireblocks::common::cosigner::signing_data data; + memcpy(data.chaincode, chaincode.data(), sizeof(HDChaincode)); + for (size_t i = 0; i < count; i++) + { + fireblocks::common::cosigner::signing_block_data block; + block.data.insert(block.data.begin(), 32, '0'); + block.path = paths[i]; + data.blocks.push_back(block); + } + + std::map> partial_sigs; + for (auto i = services.begin(); i != services.end(); ++i){ + auto& sigs = partial_sigs[i->first]; + std::string key_id; + //REQUIRE_NOTHROW(i->second->signing_service.ecdsa_sign(keyid, txid, data, "", players_str, players_ids, start_index, sigs)); + i->second->signing_service.ecdsa_sign(keyid, txid, data, "", players_str, players_ids, start_index, sigs); + } + + std::vector sigs; + for (auto i = services.begin(); i != services.end(); ++i){ + //REQUIRE_NOTHROW(i->second->signing_service.ecdsa_offline_signature(keyid, txid, type, partial_sigs, sigs)); + i->second->signing_service.ecdsa_offline_signature(keyid, txid, type, partial_sigs, sigs); + } + + //std::unique_ptr algebra(create_algebra(type), elliptic_curve256_algebra_ctx_free); + std::unique_ptr algebra(elliptic_curve256_new_secp256k1_algebra(), elliptic_curve256_algebra_ctx_free); + + std::cout << "Value of count -> " << count << std::endl; + for (size_t i = 0; i < count; i++) + { + elliptic_curve256_scalar_t msg; + assert(data.blocks[i].data.size() == sizeof(elliptic_curve256_scalar_t)); + memcpy(msg, data.blocks[i].data.data(), sizeof(elliptic_curve256_scalar_t)); + std::cout << "sig r: " << HexStr(sigs[i].r, &sigs[i].r[sizeof(elliptic_curve256_scalar_t)]) << std::endl; + std::cout << "sig s: " << HexStr(sigs[i].s, &sigs[i].s[sizeof(elliptic_curve256_scalar_t)]) << std::endl; + + PubKey derived_key; + assert(derive_public_key_generic(algebra.get(), derived_key, pubkey, data.chaincode, paths[i].data(), paths[i].size()) == HD_DERIVE_SUCCESS); + std::cout << "derived public_key: " << HexStr(derived_key, &derived_key[sizeof(PubKey)]) << std::endl; + + assert(GFp_curve_algebra_verify_signature((GFp_curve_algebra_ctx_t*)algebra->ctx, &derived_key, &msg, &sigs[i].r, &sigs[i].s) == ELLIPTIC_CURVE_ALGEBRA_SUCCESS); + + std::cout << "Signature verified" << std::endl; + if (positive_r){ + assert(is_positive(sigs[i].r)); + } + + std::cout << "Verifying with openssl" << std::endl; +#if 0 + int ECDSA_verify(int type, const unsigned char *dgst, + int dgstlen, const unsigned char *sig, + int siglen, EC_KEY *eckey); +#endif + { + // Allocate for CTX + std::unique_ptr ctxptr (BN_CTX_new(), &BN_CTX_free ); + if (ctxptr == nullptr) { + std::cout << "Failed to create BN context " << std::endl; + return; + } + + EC_GROUP * gp = EC_GROUP_new_by_curve_name(NID_secp256k1); + std::string pubkey_hex = HexStr(derived_key, &derived_key[sizeof(PubKey)]); + std::cout << "PUBKEY_HERE -> " << pubkey_hex << std::endl; + EC_POINT * ec = EC_POINT_hex2point(gp, pubkey_hex.c_str(), NULL, ctxptr.get()); + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); + + if (EC_KEY_set_public_key(ec_key, ec) == 0){ + std::cout << "Failed to convert public key" << std::endl; + } + uint8_t raw_sig[sizeof(elliptic_curve256_scalar_t) * 2]; + memcpy(raw_sig, sigs[i].r, sizeof(elliptic_curve256_scalar_t)); + memcpy(&raw_sig[sizeof(elliptic_curve256_scalar_t)], sigs[i].s, sizeof(elliptic_curve256_scalar_t)); + elliptic_curve256_scalar_t digest; + memcpy(msg, data.blocks[0].data.data(), sizeof(elliptic_curve256_scalar_t)); + // create an EC_Point from a hex string + int ret = ECDSA_verify(0, digest, sizeof(elliptic_curve256_scalar_t), raw_sig, sizeof(elliptic_curve256_scalar_t) * 2, ec_key); + std::cout << "result of verify -> " << ret << std::endl; + EC_KEY_free(ec_key); + EC_POINT_free(ec); + EC_GROUP_free(gp); + } +#ifdef USE_SECP256K1 + + + std::unique_ptr secp_ctx(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY), secp256k1_context_destroy); + if (type == ECDSA_SECP256K1) + { + uint8_t raw_sig[sizeof(elliptic_curve256_scalar_t) * 2]; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey public_key; + memcpy(raw_sig, sigs[i].r, sizeof(elliptic_curve256_scalar_t)); + memcpy(&raw_sig[sizeof(elliptic_curve256_scalar_t)], sigs[i].s, sizeof(elliptic_curve256_scalar_t)); + REQUIRE(secp256k1_ec_pubkey_parse(secp_ctx.get(), &public_key, derived_key, sizeof(PubKey))); + REQUIRE(secp256k1_ecdsa_signature_parse_compact(secp_ctx.get(), &sig, raw_sig)); + REQUIRE(secp256k1_ecdsa_verify(secp_ctx.get(), &sig, msg, &public_key)); + secp256k1_ecdsa_recoverable_signature recoverable_sig; + secp256k1_pubkey recoveredPubKey = {0}; + int retVal = secp256k1_ecdsa_recoverable_signature_parse_compact(secp_ctx.get(), &recoverable_sig, raw_sig, sigs[i].v); + REQUIRE(secp256k1_ecdsa_recover(secp_ctx.get(), &recoveredPubKey, &recoverable_sig, msg)); + REQUIRE(memcmp(recoveredPubKey.data, public_key.data, sizeof(secp256k1_pubkey)) == 0); + + } +#endif + } +} diff --git a/test/cosigner/signing_test.h b/test/cosigner/signing_test.h new file mode 100644 index 0000000..16934c7 --- /dev/null +++ b/test/cosigner/signing_test.h @@ -0,0 +1,250 @@ +#ifndef __SIGNING_TEST_H__ +#define __SIGNING_TEST_H__ + +#include +#include +#include +#include +#include "cosigner/cmp_setup_service.h" +#include "cosigner/cmp_ecdsa_offline_signing_service.h" +#include "cosigner/cmp_signature_preprocessed_data.h" +#include "cosigner/cmp_offline_refresh_service.h" + +#include + +class sign_platform : public fireblocks::common::cosigner::platform_service +{ +public: + sign_platform(uint64_t id) : _id(id), _positive_r(false) {} + void set_positive_r(bool positive_r) {_positive_r = positive_r;} +private: + void gen_random(size_t len, uint8_t* random_data) const + { + RAND_bytes(random_data, len); + } + + const std::string get_current_tenantid() const {return TENANT_ID;} + uint64_t get_id_from_keyid(const std::string& key_id) const {return _id;} + void derive_initial_share(const fireblocks::common::cosigner::share_derivation_args& derive_from, cosigner_sign_algorithm algorithm, elliptic_curve256_scalar_t* key) const {assert(0);} + fireblocks::common::cosigner::byte_vector_t encrypt_for_player(uint64_t id, const fireblocks::common::cosigner::byte_vector_t& data) const {return data;} + fireblocks::common::cosigner::byte_vector_t decrypt_message(const fireblocks::common::cosigner::byte_vector_t& encrypted_data) const {return encrypted_data;} + bool backup_key(const std::string& key_id, cosigner_sign_algorithm algorithm, const elliptic_curve256_scalar_t& private_key, const fireblocks::common::cosigner::cmp_key_metadata& metadata, const fireblocks::common::cosigner::auxiliary_keys& aux) {return true;} + void start_signing(const std::string& key_id, const std::string& txid, const fireblocks::common::cosigner::signing_data& data, const std::string& metadata_json, const std::set& players) { std::cout << "HERE IN SIGNING - DOING FUCK ALL" << std::endl;} + void fill_signing_info_from_metadata(const std::string& metadata, std::vector& flags) const + { + for (auto i = flags.begin(); i != flags.end(); ++i) + *i = _positive_r ? fireblocks::common::cosigner::POSITIVE_R : 0; + } + bool is_client_id(uint64_t player_id) const override {return false;} + + const uint64_t _id; + bool _positive_r; +}; + +static inline bool is_positive(const elliptic_curve256_scalar_t& n) +{ + return (n[0] & 0x80) == 0; +} + +static uint8_t ZERO[sizeof(fireblocks::common::cosigner::cmp_signature_preprocessed_data)] = {0}; + +class key_refresh_persistency; + +class preprocessing_persistency : public fireblocks::common::cosigner::cmp_ecdsa_offline_signing_service::preprocessing_persistency +{ + void store_preprocessing_metadata(const std::string& request_id, const fireblocks::common::cosigner::preprocessing_metadata& data, bool override) override + { + std::unique_lock lock(_mutex); + if (!override && _metadata.find(request_id) != _metadata.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + _metadata[request_id] = data; + } + + void load_preprocessing_metadata(const std::string& request_id, fireblocks::common::cosigner::preprocessing_metadata& data) const override + { + std::shared_lock lock(_mutex); + auto it = _metadata.find(request_id); + if (it == _metadata.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + data = it->second; + } + + void store_preprocessing_data(const std::string& request_id, uint64_t index, const fireblocks::common::cosigner::ecdsa_signing_data& data) override + { + std::unique_lock lock(_mutex); + _signing_data[request_id][index] = data; + } + + void load_preprocessing_data(const std::string& request_id, uint64_t index, fireblocks::common::cosigner::ecdsa_signing_data& data) const override + { + std::shared_lock lock(_mutex); + auto it = _signing_data.find(request_id); + if (it == _signing_data.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + auto index_it = it->second.find(index); + if (index_it == it->second.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + data = index_it->second; + } + + void delete_preprocessing_data(const std::string& request_id) override + { + std::unique_lock lock(_mutex); + _metadata.erase(request_id); + _signing_data.erase(request_id); + } + + void create_preprocessed_data(const std::string& key_id, uint64_t size) override + { + std::unique_lock lock(_mutex); + auto it = _preprocessed_data.find(key_id); + if (it != _preprocessed_data.end()) + { + if (it->second.size() != size) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + } + else + _preprocessed_data.emplace(key_id, std::move(std::vector(size))); + } + + void store_preprocessed_data(const std::string& key_id, uint64_t index, const fireblocks::common::cosigner::cmp_signature_preprocessed_data& data) override + { + std::unique_lock lock(_mutex); + auto it = _preprocessed_data.find(key_id); + if (it == _preprocessed_data.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + if (index >= it->second.size()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_PRESIGNING_INDEX); + it->second[index] = data; + } + + void load_preprocessed_data(const std::string& key_id, uint64_t index, fireblocks::common::cosigner::cmp_signature_preprocessed_data& data) override + { + std::unique_lock lock(_mutex); + auto it = _preprocessed_data.find(key_id); + if (it == _preprocessed_data.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + if (index >= it->second.size() || memcmp(it->second[index].k.data, ZERO, sizeof(fireblocks::common::cosigner::cmp_signature_preprocessed_data)) == 0) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_PRESIGNING_INDEX); + data = it->second[index]; + memset(it->second[index].k.data, 0, sizeof(fireblocks::common::cosigner::cmp_signature_preprocessed_data)); + } + + void delete_preprocessed_data(const std::string& key_id) override + { + std::unique_lock lock(_mutex); + _preprocessed_data.erase(key_id); + } + + mutable std::shared_mutex _mutex; + std::map _metadata; + std::map> _signing_data; + std::map> _preprocessed_data; + friend class key_refresh_persistency; +}; + +class key_refresh_persistency : public fireblocks::common::cosigner::cmp_offline_refresh_service::offline_refresh_key_persistency +{ +public: + key_refresh_persistency(preprocessing_persistency& preproc_persistency, fireblocks::common::cosigner::cmp_setup_service::setup_key_persistency& setup_persistency) : + _preprocessing_persistency(preproc_persistency), _setup_persistency(setup_persistency) {} +private: + void load_refresh_key_seeds(const std::string& request_id, std::map& player_id_to_seed) const override + { + std::lock_guard lock(_mutex); + auto it = _seeds.find(request_id); + if (it == _seeds.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + player_id_to_seed = it->second; + } + + void store_refresh_key_seeds(const std::string& request_id, const std::map& player_id_to_seed) override + { + std::lock_guard lock(_mutex); + if (_seeds.find(request_id) != _seeds.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + _seeds[request_id] = player_id_to_seed; + } + + void transform_preprocessed_data_and_store_temporary(const std::string& key_id, const std::string& request_id, const fireblocks::common::cosigner::cmp_offline_refresh_service::preprocessed_data_handler &fn) override + { + std::unique_lock lock(_preprocessing_persistency._mutex); + auto it = _preprocessing_persistency._preprocessed_data.find(key_id); + if (it == _preprocessing_persistency._preprocessed_data.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + const auto& preprocessed_data = it->second; + it = _temp_preprocessed_data.find(key_id); + if (it != _temp_preprocessed_data.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::INVALID_TRANSACTION); + + std::vector temp(preprocessed_data); + for (size_t i = 0; i < temp.size(); i++) + { + if (memcmp(temp[i].k.data, ZERO, sizeof(fireblocks::common::cosigner::cmp_signature_preprocessed_data)) != 0) + { + fn(i, temp[i]); + } + } + std::lock_guard lg(_mutex); + _temp_preprocessed_data[key_id] = temp; + } + + void commit(const std::string& key_id, const std::string& request_id) override + { + std::unique_lock lock(_preprocessing_persistency._mutex); + std::lock_guard lg(_mutex); + auto it = _temp_keys.find(request_id); + if (it == _temp_keys.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::BAD_KEY); + _preprocessing_persistency._preprocessed_data[key_id] = _temp_preprocessed_data[key_id]; + _temp_preprocessed_data.erase(key_id); + _setup_persistency.store_key(key_id, it->second.second, it->second.first); + _temp_keys.erase(request_id); + } + + void delete_refresh_key_seeds(const std::string& request_id) override + { + std::lock_guard lock(_mutex); + _temp_preprocessed_data.erase(request_id); + } + + void delete_temporary_key(const std::string& key_id) override + { + std::lock_guard lock(_mutex); + _temp_keys.erase(key_id); + } + + void store_temporary_key(const std::string& key_id, cosigner_sign_algorithm algorithm, const fireblocks::common::cosigner::elliptic_curve_scalar& private_key) override + { + std::lock_guard lock(_mutex); + if (_temp_keys.find(key_id) != _temp_keys.end()) + throw fireblocks::common::cosigner::cosigner_exception(fireblocks::common::cosigner::cosigner_exception::BAD_KEY); + auto& val = _temp_keys[key_id]; + memcpy(val.first, private_key.data, sizeof(elliptic_curve256_scalar_t)); + val.second = algorithm; + } + + mutable std::mutex _mutex; + preprocessing_persistency& _preprocessing_persistency; + fireblocks::common::cosigner::cmp_setup_service::setup_key_persistency& _setup_persistency; + std::map> _seeds; + std::map> _temp_preprocessed_data; + std::map> _temp_keys; +}; + +struct offline_siging_info +{ + offline_siging_info(uint64_t id, const fireblocks::common::cosigner::cmp_key_persistency& key_persistency) : platform_service(id), signing_service(platform_service, key_persistency, persistency) {} + sign_platform platform_service; + preprocessing_persistency persistency; + fireblocks::common::cosigner::cmp_ecdsa_offline_signing_service signing_service; +}; + +void ecdsa_preprocess(std::map>& services, const std::string& keyid, uint32_t start, uint32_t count, uint32_t total); + + +void ecdsa_sign(std::map>& services, cosigner_sign_algorithm type, const std::string& keyid, + uint32_t start_index, uint32_t count, const elliptic_curve256_point_t& pubkey, + const fireblocks::common::cosigner::byte_vector_t& chaincode, const std::vector>& paths, bool positive_r = false); + +#endif //#ifndef __SIGNING_TEST_H__ diff --git a/test/cosigner/test_info.h b/test/cosigner/test_info.h new file mode 100644 index 0000000..4316b2b --- /dev/null +++ b/test/cosigner/test_info.h @@ -0,0 +1,110 @@ +#ifndef __TEST_INFO_H__ +#define __TEST_INFO_H__ + +#include +#include +#include + +#include "cosigner/cmp_setup_service.h" +#include "crypto/elliptic_curve_algebra/elliptic_curve256_algebra.h" +#include + + +static std::string TENANT_ID("test tenant"); + + +class setup_persistency : public fireblocks::common::cosigner::cmp_setup_service::setup_key_persistency +{ +public: + // debug only + std::string dump_key(const std::string& key_id) const; +private: + bool key_exist(const std::string& key_id) const override; + void load_key(const std::string& key_id, cosigner_sign_algorithm& algorithm, elliptic_curve256_scalar_t& private_key) const override; + const std::string get_tenantid_from_keyid(const std::string& key_id) const override; + void load_key_metadata(const std::string& key_id, fireblocks::common::cosigner::cmp_key_metadata& metadata, bool full_load) const override; + void load_auxiliary_keys(const std::string& key_id, fireblocks::common::cosigner::auxiliary_keys& aux) const override; + void store_key(const std::string& key_id, cosigner_sign_algorithm algorithm, const elliptic_curve256_scalar_t& private_key, uint64_t ttl = 0) override; + void store_key_metadata(const std::string& key_id, const fireblocks::common::cosigner::cmp_key_metadata& metadata) override; + void store_auxiliary_keys(const std::string& key_id, const fireblocks::common::cosigner::auxiliary_keys& aux) override; + void store_keyid_tenant_id(const std::string& key_id, const std::string& tenant_id) override; + void store_setup_data(const std::string& key_id, const fireblocks::common::cosigner::setup_data& metadata) override; + void load_setup_data(const std::string& key_id, fireblocks::common::cosigner::setup_data& metadata) override; + void store_setup_commitments(const std::string& key_id, const std::map& commitments) override; + void load_setup_commitments(const std::string& key_id, std::map& commitments) override; + void delete_temporary_key_data(const std::string& key_id, bool delete_key = false) override; + + struct key_info + { + cosigner_sign_algorithm algorithm; + elliptic_curve256_scalar_t private_key; + fireblocks::common::cosigner::cmp_key_metadata metadata; + fireblocks::common::cosigner::auxiliary_keys aux_keys; + }; + + std::map _keys; + std::map _setup_data; + std::map> _commitments; +}; + +typedef std::map players_setup_info; + +template +std::string HexStr(const T itbegin, const T itend) +{ + std::string rv; + static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + rv.reserve((itend-itbegin)*3); + for(T it = itbegin; it < itend; ++it) + { + unsigned char val = (unsigned char)(*it); + rv.push_back(hexmap[val>>4]); + rv.push_back(hexmap[val&15]); + } + + return rv; +} + +template +inline std::string HexStr(const T& vch) +{ + return HexStr(vch.begin(), vch.end()); +} + +class platform : public fireblocks::common::cosigner::platform_service +{ +public: + platform(uint64_t id) : _id(id) {} +private: + void gen_random(size_t len, uint8_t* random_data) const + { + RAND_bytes(random_data, len); + } + + const std::string get_current_tenantid() const {return TENANT_ID;} + uint64_t get_id_from_keyid(const std::string& key_id) const {return _id;} + void derive_initial_share(const fireblocks::common::cosigner::share_derivation_args& derive_from, cosigner_sign_algorithm algorithm, elliptic_curve256_scalar_t* key) const {assert(0);} + fireblocks::common::cosigner::byte_vector_t encrypt_for_player(uint64_t id, const fireblocks::common::cosigner::byte_vector_t& data) const {return data;} + fireblocks::common::cosigner::byte_vector_t decrypt_message(const fireblocks::common::cosigner::byte_vector_t& encrypted_data) const {return encrypted_data;} + bool backup_key(const std::string& key_id, cosigner_sign_algorithm algorithm, const elliptic_curve256_scalar_t& private_key, const fireblocks::common::cosigner::cmp_key_metadata& metadata, const fireblocks::common::cosigner::auxiliary_keys& aux) {return true;} + void start_signing(const std::string& key_id, const std::string& txid, const fireblocks::common::cosigner::signing_data& data, const std::string& metadata_json, const std::set& players) {} + void fill_signing_info_from_metadata(const std::string& metadata, std::vector& flags) const {assert(0);} + bool is_client_id(uint64_t player_id) const override {return false;} + + uint64_t _id; +}; + +struct setup_info +{ + setup_info(uint64_t id, setup_persistency& persistency) : platform_service(id), setup_service(platform_service, persistency){ + return; + } + + platform platform_service; + fireblocks::common::cosigner::cmp_setup_service setup_service; +}; + + +void create_secret(players_setup_info& players, const std::string& keyid, elliptic_curve256_point_t& pubkey); +#endif //#ifndef __TEST_INFO_H__ diff --git a/test/crypto/ed25519_algebra/main.cpp b/test/crypto/ed25519_algebra/main.cpp index f988734..b8cadc6 100644 --- a/test/crypto/ed25519_algebra/main.cpp +++ b/test/crypto/ed25519_algebra/main.cpp @@ -4,7 +4,21 @@ #include #include +#if HAVE_BYTESWAP_H #include +#else +#define bswap_16(value) \ +((((value) & 0xff) << 8) | ((value) >> 8)) + +#define bswap_32(value) \ +(((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \ +(uint32_t)bswap_16((uint16_t)((value) >> 16))) + +#define bswap_64(value) \ +(((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) \ +<< 32) | \ +(uint64_t)bswap_32((uint32_t)((value) >> 32))) +#endif #define CATCH_CONFIG_MAIN #include diff --git a/test/crypto/secp256k1_algebra/main.cpp b/test/crypto/secp256k1_algebra/main.cpp index 447b2ae..44cfb16 100644 --- a/test/crypto/secp256k1_algebra/main.cpp +++ b/test/crypto/secp256k1_algebra/main.cpp @@ -5,8 +5,21 @@ #include #include +#if HAVE_BYTESWAP_H #include - +#else +#define bswap_16(value) \ +((((value) & 0xff) << 8) | ((value) >> 8)) + +#define bswap_32(value) \ +(((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \ +(uint32_t)bswap_16((uint16_t)((value) >> 16))) + +#define bswap_64(value) \ +(((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) \ +<< 32) | \ +(uint64_t)bswap_32((uint32_t)((value) >> 32))) +#endif #define CATCH_CONFIG_MAIN #include diff --git a/test/crypto/shamir_secret_sharing/CMakeLists.txt b/test/crypto/shamir_secret_sharing/CMakeLists.txt index 5559401..e53a5ac 100644 --- a/test/crypto/shamir_secret_sharing/CMakeLists.txt +++ b/test/crypto/shamir_secret_sharing/CMakeLists.txt @@ -12,3 +12,7 @@ target_compile_options(shamir_secret_sharing_test PRIVATE -Wall -Wextra) target_link_libraries(shamir_secret_sharing_test PRIVATE OpenSSL::Crypto) add_test(NAME shamir_secret_sharing_test COMMAND shamir_secret_sharing_test) + +add_executable(simple_test murphy_test.cc) +target_include_directories(simple_test PRIVATE ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(simple_test PRIVATE OpenSSL::Crypto cosigner) diff --git a/test/crypto/shamir_secret_sharing/murphy_test.cc b/test/crypto/shamir_secret_sharing/murphy_test.cc new file mode 100644 index 0000000..9aaa461 --- /dev/null +++ b/test/crypto/shamir_secret_sharing/murphy_test.cc @@ -0,0 +1,26 @@ +#include +#include "crypto/shamir_secret_sharing/verifiable_secret_sharing.h" +#include "crypto/elliptic_curve_algebra/elliptic_curve256_algebra.h" +#include + +#include + +std::unique_ptr secp256k1(elliptic_curve256_new_secp256k1_algebra(), elliptic_curve256_algebra_ctx_free); + +int main(int argc, char*argv[]){ + std::cout << "hello" << std::endl; + + const unsigned char secret[33] = "01234567890123456789012345678912"; + unsigned char secret2[33] = {0}; + verifiable_secret_sharing_t *shamir; + shamir_secret_share_t share[3]; + uint32_t size; + + if (verifiable_secret_sharing_split(secp256k1.get(), secret, sizeof(secret) - 1, 3, 5, &shamir) + == VERIFIABLE_SECRET_SHARING_SUCCESS){ + + std::cout << "sucess of some description" << std::endl; + } + + return 0; +} \ No newline at end of file