Line data Source code
1 : // Copyright (c) 2012-2020 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include <key.h>
6 :
7 : #include <key_io.h>
8 : #include <streams.h>
9 : #include <test/util/setup_common.h>
10 : #include <uint256.h>
11 : #include <util/strencodings.h>
12 : #include <util/string.h>
13 : #include <util/system.h>
14 :
15 : #include <string>
16 : #include <vector>
17 :
18 : #include <boost/test/unit_test.hpp>
19 :
20 89 : static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
21 89 : static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
22 89 : static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
23 89 : static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g";
24 89 : static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ";
25 89 : static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ";
26 89 : static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
27 89 : static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
28 :
29 89 : static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF";
30 :
31 :
32 89 : BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
33 :
34 95 : BOOST_AUTO_TEST_CASE(key_test1)
35 : {
36 1 : CKey key1 = DecodeSecret(strSecret1);
37 1 : BOOST_CHECK(key1.IsValid() && !key1.IsCompressed());
38 1 : CKey key2 = DecodeSecret(strSecret2);
39 1 : BOOST_CHECK(key2.IsValid() && !key2.IsCompressed());
40 1 : CKey key1C = DecodeSecret(strSecret1C);
41 1 : BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed());
42 1 : CKey key2C = DecodeSecret(strSecret2C);
43 1 : BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed());
44 1 : CKey bad_key = DecodeSecret(strAddressBad);
45 1 : BOOST_CHECK(!bad_key.IsValid());
46 :
47 1 : CPubKey pubkey1 = key1. GetPubKey();
48 1 : CPubKey pubkey2 = key2. GetPubKey();
49 1 : CPubKey pubkey1C = key1C.GetPubKey();
50 1 : CPubKey pubkey2C = key2C.GetPubKey();
51 :
52 1 : BOOST_CHECK(key1.VerifyPubKey(pubkey1));
53 1 : BOOST_CHECK(!key1.VerifyPubKey(pubkey1C));
54 1 : BOOST_CHECK(!key1.VerifyPubKey(pubkey2));
55 1 : BOOST_CHECK(!key1.VerifyPubKey(pubkey2C));
56 :
57 1 : BOOST_CHECK(!key1C.VerifyPubKey(pubkey1));
58 1 : BOOST_CHECK(key1C.VerifyPubKey(pubkey1C));
59 1 : BOOST_CHECK(!key1C.VerifyPubKey(pubkey2));
60 1 : BOOST_CHECK(!key1C.VerifyPubKey(pubkey2C));
61 :
62 1 : BOOST_CHECK(!key2.VerifyPubKey(pubkey1));
63 1 : BOOST_CHECK(!key2.VerifyPubKey(pubkey1C));
64 1 : BOOST_CHECK(key2.VerifyPubKey(pubkey2));
65 1 : BOOST_CHECK(!key2.VerifyPubKey(pubkey2C));
66 :
67 1 : BOOST_CHECK(!key2C.VerifyPubKey(pubkey1));
68 1 : BOOST_CHECK(!key2C.VerifyPubKey(pubkey1C));
69 1 : BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
70 1 : BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
71 :
72 1 : BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(PKHash(pubkey1)));
73 1 : BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(PKHash(pubkey2)));
74 1 : BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(PKHash(pubkey1C)));
75 1 : BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(PKHash(pubkey2C)));
76 :
77 17 : for (int n=0; n<16; n++)
78 : {
79 16 : std::string strMsg = strprintf("Very secret message %i: 11", n);
80 16 : uint256 hashMsg = Hash(strMsg);
81 :
82 : // normal signatures
83 :
84 16 : std::vector<unsigned char> sign1, sign2, sign1C, sign2C;
85 :
86 16 : BOOST_CHECK(key1.Sign (hashMsg, sign1));
87 16 : BOOST_CHECK(key2.Sign (hashMsg, sign2));
88 16 : BOOST_CHECK(key1C.Sign(hashMsg, sign1C));
89 16 : BOOST_CHECK(key2C.Sign(hashMsg, sign2C));
90 :
91 16 : BOOST_CHECK( pubkey1.Verify(hashMsg, sign1));
92 16 : BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));
93 16 : BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));
94 16 : BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));
95 :
96 16 : BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));
97 16 : BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));
98 16 : BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));
99 16 : BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));
100 :
101 16 : BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));
102 16 : BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));
103 16 : BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));
104 16 : BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));
105 :
106 16 : BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));
107 16 : BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));
108 16 : BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));
109 16 : BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C));
110 :
111 : // compact signatures (with key recovery)
112 :
113 16 : std::vector<unsigned char> csign1, csign2, csign1C, csign2C;
114 :
115 16 : BOOST_CHECK(key1.SignCompact (hashMsg, csign1));
116 16 : BOOST_CHECK(key2.SignCompact (hashMsg, csign2));
117 16 : BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));
118 16 : BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));
119 :
120 16 : CPubKey rkey1, rkey2, rkey1C, rkey2C;
121 :
122 16 : BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));
123 16 : BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));
124 16 : BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));
125 16 : BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));
126 :
127 16 : BOOST_CHECK(rkey1 == pubkey1);
128 16 : BOOST_CHECK(rkey2 == pubkey2);
129 16 : BOOST_CHECK(rkey1C == pubkey1C);
130 16 : BOOST_CHECK(rkey2C == pubkey2C);
131 16 : }
132 :
133 : // test deterministic signing
134 :
135 1 : std::vector<unsigned char> detsig, detsigc;
136 1 : std::string strMsg = "Very deterministic message";
137 1 : uint256 hashMsg = Hash(strMsg);
138 1 : BOOST_CHECK(key1.Sign(hashMsg, detsig));
139 1 : BOOST_CHECK(key1C.Sign(hashMsg, detsigc));
140 1 : BOOST_CHECK(detsig == detsigc);
141 1 : BOOST_CHECK(detsig == ParseHex("304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
142 1 : BOOST_CHECK(key2.Sign(hashMsg, detsig));
143 1 : BOOST_CHECK(key2C.Sign(hashMsg, detsigc));
144 1 : BOOST_CHECK(detsig == detsigc);
145 1 : BOOST_CHECK(detsig == ParseHex("3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
146 1 : BOOST_CHECK(key1.SignCompact(hashMsg, detsig));
147 1 : BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc));
148 1 : BOOST_CHECK(detsig == ParseHex("1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
149 1 : BOOST_CHECK(detsigc == ParseHex("205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
150 1 : BOOST_CHECK(key2.SignCompact(hashMsg, detsig));
151 1 : BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc));
152 1 : BOOST_CHECK(detsig == ParseHex("1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
153 1 : BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
154 1 : }
155 :
156 95 : BOOST_AUTO_TEST_CASE(key_signature_tests)
157 : {
158 : // When entropy is specified, we should see at least one high R signature within 20 signatures
159 1 : CKey key = DecodeSecret(strSecret1);
160 1 : std::string msg = "A message to be signed";
161 1 : uint256 msg_hash = Hash(msg);
162 1 : std::vector<unsigned char> sig;
163 : bool found = false;
164 :
165 1 : for (int i = 1; i <=20; ++i) {
166 1 : sig.clear();
167 1 : BOOST_CHECK(key.Sign(msg_hash, sig, false, i));
168 1 : found = sig[3] == 0x21 && sig[4] == 0x00;
169 1 : if (found) {
170 1 : break;
171 : }
172 : }
173 1 : BOOST_CHECK(found);
174 :
175 : // When entropy is not specified, we should always see low R signatures that are less than 70 bytes in 256 tries
176 : // We should see at least one signature that is less than 70 bytes.
177 : found = true;
178 : bool found_small = false;
179 257 : for (int i = 0; i < 256; ++i) {
180 256 : sig.clear();
181 256 : std::string msg = "A message to be signed" + ToString(i);
182 256 : msg_hash = Hash(msg);
183 256 : BOOST_CHECK(key.Sign(msg_hash, sig));
184 256 : found = sig[3] == 0x20;
185 256 : BOOST_CHECK(sig.size() <= 70);
186 256 : found_small |= sig.size() < 70;
187 256 : }
188 1 : BOOST_CHECK(found);
189 1 : BOOST_CHECK(found_small);
190 1 : }
191 :
192 95 : BOOST_AUTO_TEST_CASE(key_key_negation)
193 : {
194 : // create a dummy hash for signature comparison
195 1 : unsigned char rnd[8];
196 1 : std::string str = "Bitcoin key verification\n";
197 1 : GetRandBytes(rnd, sizeof(rnd));
198 1 : uint256 hash;
199 1 : CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
200 :
201 : // import the static test key
202 1 : CKey key = DecodeSecret(strSecret1C);
203 :
204 : // create a signature
205 1 : std::vector<unsigned char> vch_sig;
206 1 : std::vector<unsigned char> vch_sig_cmp;
207 1 : key.Sign(hash, vch_sig);
208 :
209 : // negate the key twice
210 1 : BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
211 1 : key.Negate();
212 : // after the first negation, the signature must be different
213 1 : key.Sign(hash, vch_sig_cmp);
214 1 : BOOST_CHECK(vch_sig_cmp != vch_sig);
215 1 : BOOST_CHECK(key.GetPubKey().data()[0] == 0x02);
216 1 : key.Negate();
217 : // after the second negation, we should have the original key and thus the
218 : // same signature
219 1 : key.Sign(hash, vch_sig_cmp);
220 1 : BOOST_CHECK(vch_sig_cmp == vch_sig);
221 1 : BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
222 1 : }
223 :
224 12 : static CPubKey UnserializePubkey(const std::vector<uint8_t>& data)
225 : {
226 12 : CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
227 12 : stream << data;
228 12 : CPubKey pubkey;
229 12 : stream >> pubkey;
230 : return pubkey;
231 12 : }
232 :
233 6 : static unsigned int GetLen(unsigned char chHeader)
234 : {
235 6 : if (chHeader == 2 || chHeader == 3)
236 2 : return CPubKey::COMPRESSED_SIZE;
237 4 : if (chHeader == 4 || chHeader == 6 || chHeader == 7)
238 3 : return CPubKey::SIZE;
239 1 : return 0;
240 6 : }
241 :
242 12 : static void CmpSerializationPubkey(const CPubKey& pubkey)
243 : {
244 12 : CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
245 12 : stream << pubkey;
246 12 : CPubKey pubkey2;
247 12 : stream >> pubkey2;
248 12 : BOOST_CHECK(pubkey == pubkey2);
249 12 : }
250 :
251 95 : BOOST_AUTO_TEST_CASE(pubkey_unserialize)
252 : {
253 7 : for (uint8_t i = 2; i <= 7; ++i) {
254 6 : CPubKey key = UnserializePubkey({0x02});
255 6 : BOOST_CHECK(!key.IsValid());
256 6 : CmpSerializationPubkey(key);
257 6 : key = UnserializePubkey(std::vector<uint8_t>(GetLen(i), i));
258 6 : CmpSerializationPubkey(key);
259 6 : if (i == 5) {
260 1 : BOOST_CHECK(!key.IsValid());
261 : } else {
262 5 : BOOST_CHECK(key.IsValid());
263 : }
264 6 : }
265 1 : }
266 :
267 89 : BOOST_AUTO_TEST_SUITE_END()
|