From 4dd4a1b1c7f46e0c55a940bff481564697be0a73 Mon Sep 17 00:00:00 2001 From: Oleh Nikolaiev Date: Fri, 7 May 2021 16:25:34 +0300 Subject: [PATCH 1/4] SKALE-4169 extend is_well_formed check --- deps/build.sh | 4 ++-- dkg/dkg.cpp | 8 ++++++++ dkg/dkg.h | 2 ++ test/unit_tests_dkg.cpp | 20 +++++++------------- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/deps/build.sh b/deps/build.sh index 52f56523..56ee5f94 100755 --- a/deps/build.sh +++ b/deps/build.sh @@ -576,8 +576,8 @@ then if [ ! -f "boost_1_68_0.tar.bz2" ]; then echo -e "${COLOR_INFO}downloading it${COLOR_DOTS}...${COLOR_RESET}" - # $WGET https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz - $WGET https://boostorg.jfrog.io/artifactory/main/release/1.68.0/source/boost_1_68_0.tar.bz2 + # $WGET https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.gz + $WGET https://boostorg.jfrog.io/artifactory/main/release/1.68.0/source/boost_1_68_0.tar.bz2 fi echo -e "${COLOR_INFO}unpacking it${COLOR_DOTS}...${COLOR_RESET}" tar -xf boost_1_68_0.tar.bz2 diff --git a/dkg/dkg.cpp b/dkg/dkg.cpp index 85d21762..1ae9c81e 100644 --- a/dkg/dkg.cpp +++ b/dkg/dkg.cpp @@ -110,6 +110,9 @@ bool Dkg::Verification( size_t idx, libff::alt_bn128_Fr share, // idx-th node verifies that share corresponds to the verification vector libff::alt_bn128_G2 value = libff::alt_bn128_G2::zero(); for ( size_t i = 0; i < this->t_; ++i ) { + if ( !this->isG2( verification_vector[i] ) ) { + return false; + } value = value + power( libff::alt_bn128_Fr( idx + 1 ), i ) * verification_vector[i]; } @@ -131,4 +134,9 @@ size_t Dkg::GetN() const { return this->n_; } +bool Dkg::isG2( const libff::alt_bn128_G2& point ) { + return point.is_well_formed() && + libff::alt_bn128_modulus_r * point == libff::alt_bn128_G2::zero(); +} + } // namespace signatures diff --git a/dkg/dkg.h b/dkg/dkg.h index 5a79ff69..23f324c4 100644 --- a/dkg/dkg.h +++ b/dkg/dkg.h @@ -58,6 +58,8 @@ class Dkg { size_t GetN() const; + static bool isG2( const libff::alt_bn128_G2& point ); + private: const size_t t_ = 0; diff --git a/test/unit_tests_dkg.cpp b/test/unit_tests_dkg.cpp index f7c0ce91..b4957fbb 100644 --- a/test/unit_tests_dkg.cpp +++ b/test/unit_tests_dkg.cpp @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE( ZeroSecret ) { } } -libff::alt_bn128_Fq SpoilSignCoord( libff::alt_bn128_Fq& sign_coord ) { +libff::alt_bn128_Fq SpoilCoord( libff::alt_bn128_Fq& sign_coord ) { libff::alt_bn128_Fq bad_coord = sign_coord; size_t n_bad_bit = rand_gen() % ( bad_coord.size_in_bits() ) + 1; @@ -157,28 +157,22 @@ std::vector< libff::alt_bn128_G2 > SpoilVerifVector( std::vector< libff::alt_bn128_G2 > bad_verif_vect = verif_vect; switch ( bad_coord_num ) { case 0: - bad_verif_vect.at( elem_to_spoil ).X.c0 = - SpoilSignCoord( verif_vect.at( elem_to_spoil ).X.c0 ); + bad_verif_vect.at( elem_to_spoil ).X.c0 = SpoilCoord( verif_vect.at( elem_to_spoil ).X.c0 ); break; case 1: - bad_verif_vect.at( elem_to_spoil ).X.c1 = - SpoilSignCoord( verif_vect.at( elem_to_spoil ).X.c1 ); + bad_verif_vect.at( elem_to_spoil ).X.c1 = SpoilCoord( verif_vect.at( elem_to_spoil ).X.c1 ); break; case 2: - bad_verif_vect.at( elem_to_spoil ).Y.c0 = - SpoilSignCoord( verif_vect.at( elem_to_spoil ).Y.c0 ); + bad_verif_vect.at( elem_to_spoil ).Y.c0 = SpoilCoord( verif_vect.at( elem_to_spoil ).Y.c0 ); break; case 3: - bad_verif_vect.at( elem_to_spoil ).Y.c1 = - SpoilSignCoord( verif_vect.at( elem_to_spoil ).Y.c1 ); + bad_verif_vect.at( elem_to_spoil ).Y.c1 = SpoilCoord( verif_vect.at( elem_to_spoil ).Y.c1 ); break; case 4: - bad_verif_vect.at( elem_to_spoil ).Z.c0 = - SpoilSignCoord( verif_vect.at( elem_to_spoil ).Z.c0 ); + bad_verif_vect.at( elem_to_spoil ).Z.c0 = SpoilCoord( verif_vect.at( elem_to_spoil ).Z.c0 ); break; case 5: - bad_verif_vect.at( elem_to_spoil ).Z.c1 = - SpoilSignCoord( verif_vect.at( elem_to_spoil ).Z.c1 ); + bad_verif_vect.at( elem_to_spoil ).Z.c1 = SpoilCoord( verif_vect.at( elem_to_spoil ).Z.c1 ); break; } return bad_verif_vect; From d9852c4f5f4bd9000159a9411964efaa35a4a427 Mon Sep 17 00:00:00 2001 From: Oleh Nikolaiev Date: Tue, 11 May 2021 11:12:19 +0300 Subject: [PATCH 2/4] SKALE-4162 add attack to cmake --- CMakeLists.txt | 7 ++ test/dkg_attack.cpp | 237 +++++++++++++++++++++++--------------------- 2 files changed, 133 insertions(+), 111 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5366be2d..4bf6a1eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,10 +185,17 @@ if(BUILD_TESTS) add_test(NAME bls_test COMMAND bls_test) + add_executable(dkg_attack test/dkg_attack.cpp) + target_include_directories(dkg_attack PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_link_libraries(dkg_attack PRIVATE bls ff ${GMP_LIBRARY} ${GMPXX_LIBRARY} ${BOOST_LIBS_4_BLS}) + + add_test(NAME dkg_attack COMMAND dkg_attack) + add_custom_target(all_bls_tests COMMAND ./bls_unit_test COMMAND ./dkg_unit_test COMMAND ./bls_test + COMMAND ./dkg_attack DEPENDS bls_unit_test dkg_unit_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Run all BLS and DKG tests" diff --git a/test/dkg_attack.cpp b/test/dkg_attack.cpp index b78ff1c2..a5622218 100644 --- a/test/dkg_attack.cpp +++ b/test/dkg_attack.cpp @@ -1,139 +1,149 @@ -#include -#include -#include #include #include #include #include #include +#include +#include +#include -#include #include +#include -int main(int argc, char const* argv[]) -{ - //Initialize paring parameters +int main( int argc, char const* argv[] ) { + // Initialize paring parameters libff::alt_bn128_pp::init_public_params(); // (num_signed, num_all)=(11,13) - size_t num_signed=11; - size_t num_all=13; + size_t num_signed = 11; + size_t num_all = 13; // Initialize dkgs, secret_shares, public_shares, common_public_key_point, // private_keys, public_keys - std::vector dkgs; - std::vector> secret_shares_all; - std::vector> public_shares_all; + std::vector< DKGBLSWrapper > dkgs; + std::vector< std::vector< libff::alt_bn128_Fr > > secret_shares_all; + std::vector< std::vector< libff::alt_bn128_G2 > > public_shares_all; libff::alt_bn128_G2 common_public_key_point; - std::vector private_keys; - std::vector public_keys; + std::vector< BLSPrivateKeyShare > private_keys; + std::vector< BLSPublicKeyShare > public_keys; // Create ifstream from 'parameters.json' - std::ifstream* malicious_parameters_if = new std::ifstream("parameters.json", std::ifstream::binary ); + std::ifstream* malicious_parameters_if = + new std::ifstream( "parameters.json", std::ifstream::binary ); // Initialize malicious_parameters json, malicious_polynomial, subgroupPoint nlohmann::json malicious_parameters; - std::vector malicious_polynomial; + std::vector< libff::alt_bn128_Fr > malicious_polynomial; libff::alt_bn128_G2 subgroupPoint; // Read 'parameters.json' stream into malicious_parameters *malicious_parameters_if >> malicious_parameters; // Write json into stdout - std::cout<< malicious_parameters; - + std::cout << malicious_parameters; + // Load malicious polynomial coefficients into malicious_polynomial - for (size_t i=0; i< num_signed;i++){ - malicious_polynomial.push_back(libff::alt_bn128_Fr( - malicious_parameters["polynomial"][i].get().c_str())); + for ( size_t i = 0; i < num_signed; i++ ) { + malicious_polynomial.push_back( libff::alt_bn128_Fr( + malicious_parameters["polynomial"][i].get< std::string >().c_str() ) ); } // Initialize subgroupPoint with coordinates - subgroupPoint=libff::alt_bn128_G2( + subgroupPoint = libff::alt_bn128_G2( libff::alt_bn128_Fq2( - libff::alt_bn128_Fq(malicious_parameters["point"]["x"][0].get().c_str()), - libff::alt_bn128_Fq(malicious_parameters["point"]["x"][1].get().c_str()) - ), + libff::alt_bn128_Fq( + malicious_parameters["point"]["x"][0].get< std::string >().c_str() ), + libff::alt_bn128_Fq( + malicious_parameters["point"]["x"][1].get< std::string >().c_str() ) ), libff::alt_bn128_Fq2( - libff::alt_bn128_Fq(malicious_parameters["point"]["y"][0].get().c_str()), - libff::alt_bn128_Fq(malicious_parameters["point"]["y"][1].get().c_str()) - ), - libff::alt_bn128_Fq2( - libff::alt_bn128_Fq(1), - libff::alt_bn128_Fq(0) - ) - ); - + libff::alt_bn128_Fq( + malicious_parameters["point"]["y"][0].get< std::string >().c_str() ), + libff::alt_bn128_Fq( + malicious_parameters["point"]["y"][1].get< std::string >().c_str() ) ), + libff::alt_bn128_Fq2( libff::alt_bn128_Fq( 1 ), libff::alt_bn128_Fq( 0 ) ) ); + // Check that the subgroupPoint is in the correct subgroup // and passes the is_well_formed check - std::cout<< "\nChecking that subgroupPoint is in subgroup of order 10069: " << - (libff::alt_bn128_Fr(10069)*subgroupPoint).is_zero() << - "\nChecking that the point passes `is_well_formed`: " << - subgroupPoint.is_well_formed() << "\n"; + std::cout << "\nChecking that subgroupPoint is in subgroup of order 10069: " + << ( libff::alt_bn128_Fr( 10069 ) * subgroupPoint ).is_zero() + << "\nChecking that the point passes `is_well_formed`: " + << subgroupPoint.is_well_formed() << "\n"; // Create dkgs, secret shares and public shares of honest participants (num_singed - 1) - for (size_t i=0; i> secret_shares_ptr= dkg_wrap.createDKGSecretShares(); + std::shared_ptr< std::vector< libff::alt_bn128_Fr > > secret_shares_ptr = + dkg_wrap.createDKGSecretShares(); - std::shared_ptr> public_shares_ptr= dkg_wrap.createDKGPublicShares(); + std::shared_ptr< std::vector< libff::alt_bn128_G2 > > public_shares_ptr = + dkg_wrap.createDKGPublicShares(); - secret_shares_all.push_back(*secret_shares_ptr); - public_shares_all.push_back(*public_shares_ptr); + secret_shares_all.push_back( *secret_shares_ptr ); + public_shares_all.push_back( *public_shares_ptr ); } // Create dkg, secret shares and public shares of the active adversary - DKGBLSWrapper malicious_dkg_wrap(num_signed,num_all); - + DKGBLSWrapper malicious_dkg_wrap( num_signed, num_all ); + // Set active adversary's polynomial to loaded malicious polynomial - malicious_dkg_wrap.setDKGSecret(std::make_shared>(malicious_polynomial)); - - dkgs.push_back(malicious_dkg_wrap); - - std::shared_ptr> malicious_secret_shares = malicious_dkg_wrap.createDKGSecretShares(); - std::shared_ptr> malicious_public_shares = malicious_dkg_wrap.createDKGPublicShares(); - + malicious_dkg_wrap.setDKGSecret( + std::make_shared< std::vector< libff::alt_bn128_Fr > >( malicious_polynomial ) ); + + dkgs.push_back( malicious_dkg_wrap ); + + std::shared_ptr< std::vector< libff::alt_bn128_Fr > > malicious_secret_shares = + malicious_dkg_wrap.createDKGSecretShares(); + std::shared_ptr< std::vector< libff::alt_bn128_G2 > > malicious_public_shares = + malicious_dkg_wrap.createDKGPublicShares(); + // Add subgroupPoint*k_i to the i-th public share of the active adversary - for (size_t i=0; i> secret_shares_ptr= dkg_wrap.createDKGSecretShares(); + std::shared_ptr< std::vector< libff::alt_bn128_Fr > > secret_shares_ptr = + dkg_wrap.createDKGSecretShares(); - std::shared_ptr> public_shares_ptr= dkg_wrap.createDKGPublicShares(); + std::shared_ptr< std::vector< libff::alt_bn128_G2 > > public_shares_ptr = + dkg_wrap.createDKGPublicShares(); - secret_shares_all.push_back(*secret_shares_ptr); - public_shares_all.push_back(*public_shares_ptr); + secret_shares_all.push_back( *secret_shares_ptr ); + public_shares_all.push_back( *public_shares_ptr ); } // First verify secret shares of all the honest members and all passive adversaries - for (size_t i=0; i>(public_shares_all.at(i)))); + for ( size_t i = 0; i < num_all; i++ ) { + if ( i == ( num_signed - 1 ) ) + continue; // Skip checking active adversary's share + for ( size_t j = 0; j < num_all; j++ ) { + assert( dkgs.at( i ).VerifyDKGShare( j, secret_shares_all.at( i ).at( j ), + std::make_shared< std::vector< libff::alt_bn128_G2 > >( + public_shares_all.at( i ) ) ) ); } - } // Then only honest participants verify the active adversary's secret shares - for (size_t i=0; i>(public_shares_all.at(num_signed-1)))); + for ( size_t i = 0; i < num_signed - 1; i++ ) { + assert( dkgs.at( num_signed - 1 ) + .VerifyDKGShare( i, secret_shares_all.at( num_signed - 1 ).at( i ), + std::make_shared< std::vector< libff::alt_bn128_G2 > >( + public_shares_all.at( num_signed - 1 ) ) ) ); } - // Uncomment this to see that the check fails if adversaries start checking active adversary's shares + // Uncomment this to see that the check fails if adversaries start checking active adversary's + // shares /* for (size_t i=num_signed-1; i> secret_key_shares; + std::vector< std::vector< libff::alt_bn128_Fr > > secret_key_shares; // Construct secret_key_shares - for (size_t i=0; i < num_all; i++){ - std::vector secret_key_contribution; - for (size_t j=0; j secret_key_contribution; + for ( size_t j = 0; j < num_all; j++ ) { + secret_key_contribution.push_back( secret_shares_all.at( j ).at( i ) ); } - secret_key_shares.push_back(secret_key_contribution); + secret_key_shares.push_back( secret_key_contribution ); } // Compute public and private key shares - for (size_t i=0; i< num_all; i++){ - BLSPrivateKeyShare private_key_share=dkgs.at(i).CreateBLSPrivateKeyShare( - std::make_shared>(secret_key_shares.at(i))); - BLSPublicKeyShare public_key_share=BLSPublicKeyShare( - *private_key_share.getPrivateKey(),num_signed,num_all); - - private_keys.push_back(private_key_share); - public_keys.push_back(public_key_share); - + for ( size_t i = 0; i < num_all; i++ ) { + BLSPrivateKeyShare private_key_share = dkgs.at( i ).CreateBLSPrivateKeyShare( + std::make_shared< std::vector< libff::alt_bn128_Fr > >( secret_key_shares.at( i ) ) ); + BLSPublicKeyShare public_key_share = + BLSPublicKeyShare( *private_key_share.getPrivateKey(), num_signed, num_all ); + + private_keys.push_back( private_key_share ); + public_keys.push_back( public_key_share ); } // Let's try to sign some message // Initialize a hash array and set all bytes to 0xff - std::array hash_byte_arr; - for (size_t i=0; i<32; i++)hash_byte_arr[i]=0xff; - std::shared_ptr> hash_ptr = std::make_shared< std::array >(hash_byte_arr); - + std::array< uint8_t, 32 > hash_byte_arr; + for ( size_t i = 0; i < 32; i++ ) + hash_byte_arr[i] = 0xff; + std::shared_ptr< std::array< uint8_t, 32 > > hash_ptr = + std::make_shared< std::array< uint8_t, 32 > >( hash_byte_arr ); + // Create signature shares - std::vector signature_shares; - for (size_t i=0; i signature_shares; + for ( size_t i = 0; i < num_all; i++ ) { + if ( i == num_signed - 1 ) + continue; // Active adversary doesn't have to sign, passive advesaries behave + signature_shares.push_back( *private_keys.at( i ).sign( hash_ptr, i + 1 ) ); } // Construct signature share set (active adversary didn't take part) - BLSSigShareSet signature_share_set=BLSSigShareSet(num_signed,num_all); - for (size_t i=0; i(signature_shares.at(i))); + BLSSigShareSet signature_share_set = BLSSigShareSet( num_signed, num_all ); + for ( size_t i = 0; i < num_all && !signature_share_set.isEnough(); i++ ) { + signature_share_set.addSigShare( + std::make_shared< BLSSigShare >( signature_shares.at( i ) ) ); } // Construct the final signature - std::shared_ptr signature=signature_share_set.merge(); + std::shared_ptr< BLSSignature > signature = signature_share_set.merge(); // This assertion will fail - assert(common_public_key.VerifySig(hash_ptr,signature,num_signed,num_all)); - delete (std::ifstream*) malicious_parameters_if; + assert( common_public_key.VerifySig( hash_ptr, signature, num_signed, num_all ) ); + delete ( std::ifstream* ) malicious_parameters_if; return 0; } \ No newline at end of file From 77d931b983c72f0806d2c451735193f7068fb15b Mon Sep 17 00:00:00 2001 From: Oleh Nikolaiev Date: Tue, 11 May 2021 11:13:14 +0300 Subject: [PATCH 3/4] SKALE-4162 add attack to tests --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 79ec9a4c..77d1cb7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,7 @@ matrix: - if [ $TRAVIS_EVENT_TYPE = "cron" ]; then $NIGHTLY_BUILD_FLAGS ./threshold_encryption/te_unit_test || travis_terminate 1; else ./threshold_encryption/te_unit_test || travis_terminate 1; fi - if [ $TRAVIS_EVENT_TYPE = "cron" ]; then $NIGHTLY_BUILD_FLAGS ./threshold_encryption/te_test || travis_terminate 1; else ./threshold_encryption/te_test || travis_terminate 1; fi - if [ $TRAVIS_EVENT_TYPE = "cron" ]; then $NIGHTLY_BUILD_FLAGS ./threshold_encryption/dkg_te_unit_test || travis_terminate 1; else ./threshold_encryption/dkg_te_unit_test || travis_terminate 1; fi + - if [ $TRAVIS_EVENT_TYPE = "cron" ]; then $NIGHTLY_BUILD_FLAGS ./dkg_attack || travis_terminate 1; else ./dkg_attack || travis_terminate 1; fi - cd .. - ./get_code_cov - echo "========================================= after_success (coverage gathered to gcov files)" From a8d6e9c6bb645b0ebdeca5d15b673d7bcc1f7577 Mon Sep 17 00:00:00 2001 From: Oleh Nikolaiev Date: Tue, 11 May 2021 14:32:00 +0300 Subject: [PATCH 4/4] SKALE-4162 add attack to tests --- .travis.yml | 1 + dkg/dkg.cpp | 2 +- scripts/parameters.json | 1 + test/dkg_attack.cpp | 24 +++++++++++++++++------- 4 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 scripts/parameters.json diff --git a/.travis.yml b/.travis.yml index 77d1cb7d..5c921843 100644 --- a/.travis.yml +++ b/.travis.yml @@ -128,6 +128,7 @@ script: - if [ "$TRAVIS_OS_NAME" != "osx" ]; then make bls-format-check || travis_terminate 1; fi - cmake --build . -- -j$CPU_COUNT - cd .. + - cp scripts/parameters.json build/ - echo "========================================= script (2)" notifications: email: diff --git a/dkg/dkg.cpp b/dkg/dkg.cpp index 1ae9c81e..93701ccd 100644 --- a/dkg/dkg.cpp +++ b/dkg/dkg.cpp @@ -136,7 +136,7 @@ size_t Dkg::GetN() const { bool Dkg::isG2( const libff::alt_bn128_G2& point ) { return point.is_well_formed() && - libff::alt_bn128_modulus_r * point == libff::alt_bn128_G2::zero(); + libff::alt_bn128_G2::order() * point == libff::alt_bn128_G2::zero(); } } // namespace signatures diff --git a/scripts/parameters.json b/scripts/parameters.json new file mode 100644 index 00000000..233d47b7 --- /dev/null +++ b/scripts/parameters.json @@ -0,0 +1 @@ +{"polynomial": ["1", "7385", "9262", "7386", "8974", "2709", "2641", "5869", "6713", "1818", "7656"], "point": {"x": ["14951876894662146982452956082095430578834435966656124631738629043850247642055", "5692668362891430507399762658312539696803125283949888411716432106777825057673"], "y": ["439364695721629759277132290701500175662826626035846918502631974016681187267", "2580895763205929217614668676698834270431892898301973053304132099881352692750"]}} diff --git a/test/dkg_attack.cpp b/test/dkg_attack.cpp index a5622218..89d29337 100644 --- a/test/dkg_attack.cpp +++ b/test/dkg_attack.cpp @@ -10,13 +10,13 @@ #include #include -int main( int argc, char const* argv[] ) { +int main() { // Initialize paring parameters libff::alt_bn128_pp::init_public_params(); // (num_signed, num_all)=(11,13) size_t num_signed = 11; - size_t num_all = 13; + size_t num_all = 16; // Initialize dkgs, secret_shares, public_shares, common_public_key_point, // private_keys, public_keys @@ -134,11 +134,19 @@ int main( int argc, char const* argv[] ) { } // Then only honest participants verify the active adversary's secret shares + // modified by SKALE + size_t verified = 0; for ( size_t i = 0; i < num_signed - 1; i++ ) { - assert( dkgs.at( num_signed - 1 ) - .VerifyDKGShare( i, secret_shares_all.at( num_signed - 1 ).at( i ), - std::make_shared< std::vector< libff::alt_bn128_G2 > >( - public_shares_all.at( num_signed - 1 ) ) ) ); + verified += dkgs.at( num_signed - 1 ) + .VerifyDKGShare( i, secret_shares_all.at( num_signed - 1 ).at( i ), + std::make_shared< std::vector< libff::alt_bn128_G2 > >( + public_shares_all.at( num_signed - 1 ) ) ); + + if ( verified == 0 ) { + // SKALE fixed + std::cout << "ATTACK TEST PASSED\n"; + return 0; + } } @@ -214,8 +222,10 @@ int main( int argc, char const* argv[] ) { // Construct the final signature std::shared_ptr< BLSSignature > signature = signature_share_set.merge(); + std::cout << "isG2:" << signatures::Dkg::isG2( *( common_public_key.getPublicKey() ) ); + // This assertion will fail assert( common_public_key.VerifySig( hash_ptr, signature, num_signed, num_all ) ); delete ( std::ifstream* ) malicious_parameters_if; return 0; -} \ No newline at end of file +}