From a53fd4148596f5814409e15647714bdd2a71468b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 6 Nov 2014 06:54:50 -0800 Subject: Deterministic signing --- src/key.cpp | 29 ++++++++++++++++++----------- src/key.h | 8 ++++++-- src/test/key_tests.cpp | 23 +++++++++++++++++++++++ src/test/script_tests.cpp | 3 ++- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/key.cpp b/src/key.cpp index 9b3cf8f019..0fb7a5c7c5 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -5,6 +5,7 @@ #include "key.h" #include "crypto/hmac_sha512.h" +#include "crypto/rfc6979_hmac_sha256.h" #include "eccryptoverify.h" #include "pubkey.h" #include "random.h" @@ -71,19 +72,22 @@ CPubKey CKey::GetPubKey() const { return result; } -bool CKey::Sign(const uint256 &hash, std::vector& vchSig) const { +bool CKey::Sign(const uint256 &hash, std::vector& vchSig, uint32_t test_case) const { if (!fValid) return false; vchSig.resize(72); - int nSigLen = 72; - CKey nonce; + RFC6979_HMAC_SHA256 prng(begin(), 32, (unsigned char*)&hash, 32); do { - nonce.MakeNewKey(true); - if (secp256k1_ecdsa_sign((const unsigned char*)&hash, 32, (unsigned char*)&vchSig[0], &nSigLen, begin(), nonce.begin())) - break; + uint256 nonce; + prng.Generate((unsigned char*)&nonce, 32); + nonce += test_case; + int nSigLen = 72; + int ret = secp256k1_ecdsa_sign((const unsigned char*)&hash, 32, (unsigned char*)&vchSig[0], &nSigLen, begin(), (unsigned char*)&nonce); + vchSig.resize(nSigLen); + nonce = 0; + if (ret) + return true; } while(true); - vchSig.resize(nSigLen); - return true; } bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) const { @@ -91,10 +95,13 @@ bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) return false; vchSig.resize(65); int rec = -1; - CKey nonce; + RFC6979_HMAC_SHA256 prng(begin(), 32, (unsigned char*)&hash, 32); do { - nonce.MakeNewKey(true); - if (secp256k1_ecdsa_sign_compact((const unsigned char*)&hash, 32, &vchSig[1], begin(), nonce.begin(), &rec)) + uint256 nonce; + prng.Generate((unsigned char*)&nonce, 32); + int ret = secp256k1_ecdsa_sign_compact((const unsigned char*)&hash, 32, &vchSig[1], begin(), (unsigned char*)&nonce, &rec); + nonce = 0; + if (ret) break; } while(true); assert(rec != -1); diff --git a/src/key.h b/src/key.h index 0bb05482c9..463b373153 100644 --- a/src/key.h +++ b/src/key.h @@ -121,8 +121,12 @@ public: */ CPubKey GetPubKey() const; - //! Create a DER-serialized signature. - bool Sign(const uint256& hash, std::vector& vchSig) const; + /** + * Create a DER-serialized signature. + * The test_case parameter tweaks the deterministic nonce, and is only for + * testing. It should be zero for normal use. + */ + bool Sign(const uint256& hash, std::vector& vchSig, uint32_t test_case = 0) const; /** * Create a compact signature (65 bytes), which allows reconstructing the used public key. diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index b32f3774fe..4708936837 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -8,6 +8,7 @@ #include "script/script.h" #include "uint256.h" #include "util.h" +#include "utilstrencodings.h" #include #include @@ -142,6 +143,28 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(rkey1C == pubkey1C); BOOST_CHECK(rkey2C == pubkey2C); } + + // test deterministic signing + + std::vector detsig, detsigc; + string strMsg = "Very deterministic message"; + uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); + BOOST_CHECK(key1.Sign(hashMsg, detsig)); + BOOST_CHECK(key1C.Sign(hashMsg, detsigc)); + BOOST_CHECK(detsig == detsigc); + BOOST_CHECK(detsig == ParseHex("304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); + BOOST_CHECK(key2.Sign(hashMsg, detsig)); + BOOST_CHECK(key2C.Sign(hashMsg, detsigc)); + BOOST_CHECK(detsig == detsigc); + BOOST_CHECK(detsig == ParseHex("3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); + BOOST_CHECK(key1.SignCompact(hashMsg, detsig)); + BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc)); + BOOST_CHECK(detsig == ParseHex("1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); + BOOST_CHECK(detsigc == ParseHex("205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6")); + BOOST_CHECK(key2.SignCompact(hashMsg, detsig)); + BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc)); + BOOST_CHECK(detsig == ParseHex("1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); + BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 36aaa6903f..d3a48234c6 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -248,8 +248,9 @@ public: { uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType); std::vector vchSig, r, s; + uint32_t iter = 0; do { - key.Sign(hash, vchSig); + key.Sign(hash, vchSig, iter++); if ((lenS == 33) != (vchSig[5 + vchSig[3]] == 33)) { NegateSignatureS(vchSig); } -- cgit v1.2.3