diff --git a/src/key.cpp b/src/key.cpp --- a/src/key.cpp +++ b/src/key.cpp @@ -186,7 +186,9 @@ bool CKey::SignECDSA(const uint256 &hash, std::vector &vchSig, uint32_t test_case) const { - if (!fValid) return false; + if (!fValid) { + return false; + } vchSig.resize(72); size_t nSigLen = 72; uint8_t extra_entropy[32] = {0}; @@ -204,7 +206,9 @@ bool CKey::SignSchnorr(const uint256 &hash, std::vector &vchSig, uint32_t test_case) const { - if (!fValid) return false; + if (!fValid) { + return false; + } vchSig.resize(64); uint8_t extra_entropy[32] = {0}; WriteLE32(extra_entropy, test_case); @@ -240,7 +244,9 @@ bool CKey::SignCompact(const uint256 &hash, std::vector &vchSig) const { - if (!fValid) return false; + if (!fValid) { + return false; + } vchSig.resize(65); int rec = -1; secp256k1_ecdsa_recoverable_signature sig; @@ -264,7 +270,9 @@ fCompressed = vchPubKey.IsCompressed(); fValid = true; - if (fSkipCheck) return true; + if (fSkipCheck) { + return true; + } return VerifyPubKey(vchPubKey); } diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -32,6 +32,25 @@ static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"; +// get r value produced by ECDSA signing algorithm +// (assumes ECDSA r is encoded in the canonical manner) +std::vector get_r_ECDSA(std::vector &sigECDSA) { + std::vector ret(32, 0); + + assert(sigECDSA[2] == 2); + int rlen = sigECDSA[3]; + assert(rlen <= 33); + assert(sigECDSA[4 + rlen] == 2); + if (rlen == 33) { + assert(sigECDSA[4] == 0); + std::copy(sigECDSA.begin() + 5, sigECDSA.begin() + 37, ret.begin()); + } else { + std::copy(sigECDSA.begin() + 4, sigECDSA.begin() + 36, + ret.begin() + (32 - rlen)); + } + return ret; +} + BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(key_test1) { @@ -144,33 +163,51 @@ std::vector ssign1, ssign2, ssign1C, ssign2C; - BOOST_CHECK(key1.SignSchnorr(hashMsg, sign1)); - BOOST_CHECK(key2.SignSchnorr(hashMsg, sign2)); - BOOST_CHECK(key1C.SignSchnorr(hashMsg, sign1C)); - BOOST_CHECK(key2C.SignSchnorr(hashMsg, sign2C)); - - BOOST_CHECK(pubkey1.VerifySchnorr(hashMsg, sign1)); - BOOST_CHECK(!pubkey1.VerifySchnorr(hashMsg, sign2)); - BOOST_CHECK(pubkey1.VerifySchnorr(hashMsg, sign1C)); - BOOST_CHECK(!pubkey1.VerifySchnorr(hashMsg, sign2C)); - - BOOST_CHECK(!pubkey2.VerifySchnorr(hashMsg, sign1)); - BOOST_CHECK(pubkey2.VerifySchnorr(hashMsg, sign2)); - BOOST_CHECK(!pubkey2.VerifySchnorr(hashMsg, sign1C)); - BOOST_CHECK(pubkey2.VerifySchnorr(hashMsg, sign2C)); - - BOOST_CHECK(pubkey1C.VerifySchnorr(hashMsg, sign1)); - BOOST_CHECK(!pubkey1C.VerifySchnorr(hashMsg, sign2)); - BOOST_CHECK(pubkey1C.VerifySchnorr(hashMsg, sign1C)); - BOOST_CHECK(!pubkey1C.VerifySchnorr(hashMsg, sign2C)); - - BOOST_CHECK(!pubkey2C.VerifySchnorr(hashMsg, sign1)); - BOOST_CHECK(pubkey2C.VerifySchnorr(hashMsg, sign2)); - BOOST_CHECK(!pubkey2C.VerifySchnorr(hashMsg, sign1C)); - BOOST_CHECK(pubkey2C.VerifySchnorr(hashMsg, sign2C)); + BOOST_CHECK(key1.SignSchnorr(hashMsg, ssign1)); + BOOST_CHECK(key2.SignSchnorr(hashMsg, ssign2)); + BOOST_CHECK(key1C.SignSchnorr(hashMsg, ssign1C)); + BOOST_CHECK(key2C.SignSchnorr(hashMsg, ssign2C)); + + BOOST_CHECK(pubkey1.VerifySchnorr(hashMsg, ssign1)); + BOOST_CHECK(!pubkey1.VerifySchnorr(hashMsg, ssign2)); + BOOST_CHECK(pubkey1.VerifySchnorr(hashMsg, ssign1C)); + BOOST_CHECK(!pubkey1.VerifySchnorr(hashMsg, ssign2C)); + + BOOST_CHECK(!pubkey2.VerifySchnorr(hashMsg, ssign1)); + BOOST_CHECK(pubkey2.VerifySchnorr(hashMsg, ssign2)); + BOOST_CHECK(!pubkey2.VerifySchnorr(hashMsg, ssign1C)); + BOOST_CHECK(pubkey2.VerifySchnorr(hashMsg, ssign2C)); + + BOOST_CHECK(pubkey1C.VerifySchnorr(hashMsg, ssign1)); + BOOST_CHECK(!pubkey1C.VerifySchnorr(hashMsg, ssign2)); + BOOST_CHECK(pubkey1C.VerifySchnorr(hashMsg, ssign1C)); + BOOST_CHECK(!pubkey1C.VerifySchnorr(hashMsg, ssign2C)); + + BOOST_CHECK(!pubkey2C.VerifySchnorr(hashMsg, ssign1)); + BOOST_CHECK(pubkey2C.VerifySchnorr(hashMsg, ssign2)); + BOOST_CHECK(!pubkey2C.VerifySchnorr(hashMsg, ssign1C)); + BOOST_CHECK(pubkey2C.VerifySchnorr(hashMsg, ssign2C)); + + // check deterministicity of ECDSA & Schnorr + BOOST_CHECK(sign1 == sign1C); + BOOST_CHECK(sign2 == sign2C); + BOOST_CHECK(ssign1 == ssign1C); + BOOST_CHECK(ssign2 == ssign2C); + + // Extract r value from ECDSA and Schnorr. Make sure they are + // distinct (nonce reuse would be dangerous and can leak private key). + std::vector rE1 = get_r_ECDSA(sign1); + std::vector rS1(ssign1.begin(), ssign1.begin() + 32); + BOOST_CHECK(rE1.size() == rS1.size()); + BOOST_CHECK(rE1 != rS1); + + std::vector rE2 = get_r_ECDSA(sign2); + std::vector rS2(ssign2.begin(), ssign2.begin() + 32); + BOOST_CHECK(rE2.size() == rS2.size()); + BOOST_CHECK(rE2 != rS2); } - // test deterministic signing + // test deterministic signing expected values std::vector detsig, detsigc; std::string strMsg = "Very deterministic message";