Line data Source code
1 : // Copyright (c) 2012-2021 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/random.h>
10 : #include <test/util/setup_common.h>
11 : #include <uint256.h>
12 : #include <util/strencodings.h>
13 : #include <util/string.h>
14 : #include <util/system.h>
15 :
16 : #include <string>
17 : #include <vector>
18 :
19 : #include <boost/test/unit_test.hpp>
20 :
21 146 : static const std::string strSecret1 = "7qh6LYnLN2w2ntz2wwUhRUEgkQ2j8XB16FGw77ZRDZmC29bn7cD";
22 146 : static const std::string strSecret2 = "7rve4MxeWFQHGbSYH6J2yaaZd3MBUqoDEwN6ZAZ6ZHmhTT4r3hW";
23 146 : static const std::string strSecret1C = "XBuxZHH6TqXUuaSjbVTFR1DQSYecxCB9QA1Koyx5tTc3ddhqEnhm";
24 146 : static const std::string strSecret2C = "XHMkZqWcY6Zkoq1j42NBijD8z5N5FtNy2Wx7WyAfXX2HZgxry8cr";
25 146 : static const std::string addr1 = "Xywgfc872nn5CKtpATCoAjZCc4v96pJczy";
26 146 : static const std::string addr2 = "XpmouUj9KKJ99ZuU331ZS1KqsboeFnLGgK";
27 146 : static const std::string addr1C = "XxV9h4Xmv6Pup8tVAQmH97K6grzvDwMG9F";
28 146 : static const std::string addr2C = "Xn7ZrYdExuk79Dm7CJCw7sfUWi2qWJSbRy";
29 :
30 146 : static const std::string strAddressBad = "Xta1praZQjyELweyMByXyiREw1ZRsjXzVP";
31 :
32 :
33 146 : BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
34 :
35 149 : BOOST_AUTO_TEST_CASE(key_test1)
36 : {
37 1 : CKey key1 = DecodeSecret(strSecret1);
38 1 : BOOST_CHECK(key1.IsValid() && !key1.IsCompressed());
39 1 : CKey key2 = DecodeSecret(strSecret2);
40 1 : BOOST_CHECK(key2.IsValid() && !key2.IsCompressed());
41 1 : CKey key1C = DecodeSecret(strSecret1C);
42 2 : BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed());
43 1 : CKey key2C = DecodeSecret(strSecret2C);
44 2 : BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed());
45 1 : CKey bad_key = DecodeSecret(strAddressBad);
46 1 : BOOST_CHECK(!bad_key.IsValid());
47 :
48 1 : CPubKey pubkey1 = key1. GetPubKey();
49 1 : CPubKey pubkey2 = key2. GetPubKey();
50 1 : CPubKey pubkey1C = key1C.GetPubKey();
51 1 : CPubKey pubkey2C = key2C.GetPubKey();
52 :
53 1 : BOOST_CHECK(key1.VerifyPubKey(pubkey1));
54 1 : BOOST_CHECK(!key1.VerifyPubKey(pubkey1C));
55 1 : BOOST_CHECK(!key1.VerifyPubKey(pubkey2));
56 1 : BOOST_CHECK(!key1.VerifyPubKey(pubkey2C));
57 :
58 1 : BOOST_CHECK(!key1C.VerifyPubKey(pubkey1));
59 1 : BOOST_CHECK(key1C.VerifyPubKey(pubkey1C));
60 1 : BOOST_CHECK(!key1C.VerifyPubKey(pubkey2));
61 1 : BOOST_CHECK(!key1C.VerifyPubKey(pubkey2C));
62 :
63 1 : BOOST_CHECK(!key2.VerifyPubKey(pubkey1));
64 1 : BOOST_CHECK(!key2.VerifyPubKey(pubkey1C));
65 1 : BOOST_CHECK(key2.VerifyPubKey(pubkey2));
66 1 : BOOST_CHECK(!key2.VerifyPubKey(pubkey2C));
67 :
68 1 : BOOST_CHECK(!key2C.VerifyPubKey(pubkey1));
69 1 : BOOST_CHECK(!key2C.VerifyPubKey(pubkey1C));
70 1 : BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
71 1 : BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
72 :
73 1 : BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(PKHash(pubkey1)));
74 1 : BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(PKHash(pubkey2)));
75 1 : BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(PKHash(pubkey1C)));
76 1 : BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(PKHash(pubkey2C)));
77 :
78 17 : for (int n=0; n<16; n++)
79 : {
80 16 : std::string strMsg = strprintf("Very secret message %i: 11", n);
81 16 : uint256 hashMsg = Hash(strMsg);
82 :
83 : // normal signatures
84 :
85 16 : std::vector<unsigned char> sign1, sign2, sign1C, sign2C;
86 :
87 16 : BOOST_CHECK(key1.Sign (hashMsg, sign1));
88 16 : BOOST_CHECK(key2.Sign (hashMsg, sign2));
89 16 : BOOST_CHECK(key1C.Sign(hashMsg, sign1C));
90 16 : BOOST_CHECK(key2C.Sign(hashMsg, sign2C));
91 :
92 16 : BOOST_CHECK( pubkey1.Verify(hashMsg, sign1));
93 16 : BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));
94 16 : BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));
95 16 : BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));
96 :
97 16 : BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));
98 16 : BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));
99 16 : BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));
100 16 : BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));
101 :
102 16 : BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));
103 16 : BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));
104 16 : BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));
105 16 : BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));
106 :
107 16 : BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));
108 16 : BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));
109 16 : BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));
110 16 : BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C));
111 :
112 : // compact signatures (with key recovery)
113 :
114 16 : std::vector<unsigned char> csign1, csign2, csign1C, csign2C;
115 :
116 16 : BOOST_CHECK(key1.SignCompact (hashMsg, csign1));
117 16 : BOOST_CHECK(key2.SignCompact (hashMsg, csign2));
118 16 : BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));
119 16 : BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));
120 :
121 16 : CPubKey rkey1, rkey2, rkey1C, rkey2C;
122 :
123 16 : BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));
124 16 : BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));
125 16 : BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));
126 16 : BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));
127 :
128 16 : BOOST_CHECK(rkey1 == pubkey1);
129 16 : BOOST_CHECK(rkey2 == pubkey2);
130 16 : BOOST_CHECK(rkey1C == pubkey1C);
131 16 : BOOST_CHECK(rkey2C == pubkey2C);
132 16 : }
133 :
134 : // test deterministic signing
135 :
136 1 : std::vector<unsigned char> detsig, detsigc;
137 1 : std::string strMsg = "Very deterministic message";
138 1 : uint256 hashMsg = Hash(strMsg);
139 1 : BOOST_CHECK(key1.Sign(hashMsg, detsig));
140 1 : BOOST_CHECK(key1C.Sign(hashMsg, detsigc));
141 1 : BOOST_CHECK(detsig == detsigc);
142 1 : BOOST_CHECK(detsig == ParseHex("304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
143 1 : BOOST_CHECK(key2.Sign(hashMsg, detsig));
144 1 : BOOST_CHECK(key2C.Sign(hashMsg, detsigc));
145 1 : BOOST_CHECK(detsig == detsigc);
146 1 : BOOST_CHECK(detsig == ParseHex("3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
147 1 : BOOST_CHECK(key1.SignCompact(hashMsg, detsig));
148 1 : BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc));
149 1 : BOOST_CHECK(detsig == ParseHex("1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
150 1 : BOOST_CHECK(detsigc == ParseHex("205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
151 1 : BOOST_CHECK(key2.SignCompact(hashMsg, detsig));
152 1 : BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc));
153 1 : BOOST_CHECK(detsig == ParseHex("1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
154 1 : BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
155 1 : }
156 :
157 149 : BOOST_AUTO_TEST_CASE(key_signature_tests)
158 : {
159 : // When entropy is specified, we should see at least one high R signature within 20 signatures
160 1 : CKey key = DecodeSecret(strSecret1);
161 1 : std::string msg = "A message to be signed";
162 1 : uint256 msg_hash = Hash(msg);
163 1 : std::vector<unsigned char> sig;
164 1 : bool found = false;
165 :
166 1 : for (int i = 1; i <=20; ++i) {
167 1 : sig.clear();
168 1 : BOOST_CHECK(key.Sign(msg_hash, sig, false, i));
169 1 : found = sig[3] == 0x21 && sig[4] == 0x00;
170 1 : if (found) {
171 1 : break;
172 : }
173 0 : }
174 1 : BOOST_CHECK(found);
175 :
176 : // When entropy is not specified, we should always see low R signatures that are less than or equal to 70 bytes in 256 tries
177 : // The low R signatures should always have the value of their "length of R" byte less than or equal to 32
178 : // We should see at least one signature that is less than 70 bytes.
179 1 : bool found_small = false;
180 1 : bool found_big = false;
181 1 : bool bad_sign = false;
182 257 : for (int i = 0; i < 256; ++i) {
183 256 : sig.clear();
184 256 : std::string msg = "A message to be signed" + ToString(i);
185 256 : msg_hash = Hash(msg);
186 256 : if (!key.Sign(msg_hash, sig)) {
187 0 : bad_sign = true;
188 0 : break;
189 : }
190 : // sig.size() > 70 implies sig[3] > 32, because S is always low.
191 : // But check both conditions anyway, just in case this implication is broken for some reason
192 256 : if (sig[3] > 32 || sig.size() > 70) {
193 0 : found_big = true;
194 0 : break;
195 : }
196 256 : found_small |= sig.size() < 70;
197 256 : }
198 1 : BOOST_CHECK(!bad_sign);
199 1 : BOOST_CHECK(!found_big);
200 1 : BOOST_CHECK(found_small);
201 1 : }
202 :
203 149 : BOOST_AUTO_TEST_CASE(key_key_negation)
204 : {
205 : // create a dummy hash for signature comparison
206 : unsigned char rnd[8];
207 1 : std::string str = "Bitcoin key verification\n";
208 1 : GetRandBytes(rnd);
209 1 : uint256 hash{Hash(str, rnd)};
210 :
211 : // import the static test key
212 1 : CKey key = DecodeSecret(strSecret1C);
213 :
214 : // create a signature
215 1 : std::vector<unsigned char> vch_sig;
216 1 : std::vector<unsigned char> vch_sig_cmp;
217 1 : key.Sign(hash, vch_sig);
218 :
219 : // negate the key twice
220 1 : BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
221 1 : key.Negate();
222 : // after the first negation, the signature must be different
223 1 : key.Sign(hash, vch_sig_cmp);
224 1 : BOOST_CHECK(vch_sig_cmp != vch_sig);
225 1 : BOOST_CHECK(key.GetPubKey().data()[0] == 0x02);
226 1 : key.Negate();
227 : // after the second negation, we should have the original key and thus the
228 : // same signature
229 1 : key.Sign(hash, vch_sig_cmp);
230 1 : BOOST_CHECK(vch_sig_cmp == vch_sig);
231 1 : BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
232 1 : }
233 :
234 12 : static CPubKey UnserializePubkey(const std::vector<uint8_t>& data)
235 : {
236 12 : CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
237 12 : stream << data;
238 12 : CPubKey pubkey;
239 12 : stream >> pubkey;
240 : return pubkey;
241 12 : }
242 :
243 6 : static unsigned int GetLen(unsigned char chHeader)
244 : {
245 6 : if (chHeader == 2 || chHeader == 3)
246 2 : return CPubKey::COMPRESSED_SIZE;
247 4 : if (chHeader == 4 || chHeader == 6 || chHeader == 7)
248 3 : return CPubKey::SIZE;
249 1 : return 0;
250 6 : }
251 :
252 12 : static void CmpSerializationPubkey(const CPubKey& pubkey)
253 : {
254 12 : CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
255 12 : stream << pubkey;
256 12 : CPubKey pubkey2;
257 12 : stream >> pubkey2;
258 12 : BOOST_CHECK(pubkey == pubkey2);
259 12 : }
260 :
261 149 : BOOST_AUTO_TEST_CASE(pubkey_unserialize)
262 : {
263 7 : for (uint8_t i = 2; i <= 7; ++i) {
264 6 : CPubKey key = UnserializePubkey({0x02});
265 6 : BOOST_CHECK(!key.IsValid());
266 6 : CmpSerializationPubkey(key);
267 6 : key = UnserializePubkey(std::vector<uint8_t>(GetLen(i), i));
268 6 : CmpSerializationPubkey(key);
269 6 : if (i == 5) {
270 1 : BOOST_CHECK(!key.IsValid());
271 1 : } else {
272 5 : BOOST_CHECK(key.IsValid());
273 : }
274 6 : }
275 1 : }
276 :
277 149 : BOOST_AUTO_TEST_CASE(key_ellswift)
278 : {
279 5 : for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
280 4 : CKey key = DecodeSecret(secret);
281 4 : BOOST_CHECK(key.IsValid());
282 :
283 4 : uint256 ent32 = InsecureRand256();
284 4 : auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32}));
285 :
286 4 : CPubKey decoded_pubkey = ellswift.Decode();
287 4 : if (!key.IsCompressed()) {
288 : // The decoding constructor returns a compressed pubkey. If the
289 : // original was uncompressed, we must decompress the decoded one
290 : // to compare.
291 2 : decoded_pubkey.Decompress();
292 2 : }
293 4 : BOOST_CHECK(key.GetPubKey() == decoded_pubkey);
294 4 : }
295 1 : }
296 :
297 146 : BOOST_AUTO_TEST_SUITE_END()
|