Branch data 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 <compressor.h>
6 : : #include <script/script.h>
7 : : #include <test/util/random.h>
8 : : #include <test/util/setup_common.h>
9 : :
10 : : #include <stdint.h>
11 : :
12 : : #include <boost/test/unit_test.hpp>
13 : :
14 : : // amounts 0.00000001 .. 0.00100000
15 : : #define NUM_MULTIPLES_UNIT 100000
16 : :
17 : : // amounts 0.01 .. 100.00
18 : : #define NUM_MULTIPLES_CENT 10000
19 : :
20 : : // amounts 1 .. 10000
21 : : #define NUM_MULTIPLES_1BTC 10000
22 : :
23 : : // amounts 50 .. 21000000
24 : : #define NUM_MULTIPLES_50BTC 420000
25 : :
26 : : BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup)
27 : :
28 : 540000 : bool static TestEncode(uint64_t in) {
29 : 540000 : return in == DecompressAmount(CompressAmount(in));
30 : : }
31 : :
32 : 100000 : bool static TestDecode(uint64_t in) {
33 : 100000 : return in == CompressAmount(DecompressAmount(in));
34 : : }
35 : :
36 : 6 : bool static TestPair(uint64_t dec, uint64_t enc) {
37 [ + - - + ]: 12 : return CompressAmount(dec) == enc &&
38 : 6 : DecompressAmount(enc) == dec;
39 : : }
40 : :
41 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(compress_amounts)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
42 : : {
43 [ + - + - ]: 2 : BOOST_CHECK(TestPair( 0, 0x0));
44 [ + - + - ]: 2 : BOOST_CHECK(TestPair( 1, 0x1));
45 [ + - + - ]: 2 : BOOST_CHECK(TestPair( CENT, 0x7));
46 [ + - + - ]: 2 : BOOST_CHECK(TestPair( COIN, 0x9));
47 [ + - + - ]: 2 : BOOST_CHECK(TestPair( 50*COIN, 0x32));
48 [ + - + - ]: 2 : BOOST_CHECK(TestPair(21000000*COIN, 0x1406f40));
49 : :
50 [ + + ]: 100001 : for (uint64_t i = 1; i <= NUM_MULTIPLES_UNIT; i++)
51 [ + - + - ]: 200000 : BOOST_CHECK(TestEncode(i));
52 : :
53 [ + + ]: 10001 : for (uint64_t i = 1; i <= NUM_MULTIPLES_CENT; i++)
54 [ + - + - ]: 20000 : BOOST_CHECK(TestEncode(i * CENT));
55 : :
56 [ + + ]: 10001 : for (uint64_t i = 1; i <= NUM_MULTIPLES_1BTC; i++)
57 [ + - + - ]: 20000 : BOOST_CHECK(TestEncode(i * COIN));
58 : :
59 [ + + ]: 420001 : for (uint64_t i = 1; i <= NUM_MULTIPLES_50BTC; i++)
60 [ + - + - ]: 840000 : BOOST_CHECK(TestEncode(i * 50 * COIN));
61 : :
62 [ + + ]: 100001 : for (uint64_t i = 0; i < 100000; i++)
63 [ + - + - ]: 200000 : BOOST_CHECK(TestDecode(i));
64 : 1 : }
65 : :
66 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(compress_script_to_ckey_id)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
67 : : {
68 : : // case CKeyID
69 : 1 : CKey key = GenerateRandomKey();
70 [ + - ]: 1 : CPubKey pubkey = key.GetPubKey();
71 : :
72 [ + - + - : 1 : CScript script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ - + - +
- + - ]
73 [ + - - + : 1 : BOOST_CHECK_EQUAL(script.size(), 25U);
+ - ]
74 : :
75 : 1 : CompressedScript out;
76 [ + - ]: 1 : bool done = CompressScript(script, out);
77 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(done, true);
78 : :
79 : : // Check compressed script
80 [ + - - + : 1 : BOOST_CHECK_EQUAL(out.size(), 21U);
+ - ]
81 [ + - - + : 1 : BOOST_CHECK_EQUAL(out[0], 0x00);
+ - ]
82 [ + - - + : 1 : BOOST_CHECK_EQUAL(memcmp(out.data() + 1, script.data() + 3, 20), 0); // compare the 20 relevant chars of the CKeyId in the script
- + + - ]
83 : 1 : }
84 : :
85 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(compress_script_to_cscript_id)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
86 : : {
87 : : // case CScriptID
88 : 1 : CScript script, redeemScript;
89 [ + - + - : 2 : script << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ - + - ]
90 [ + - - + : 1 : BOOST_CHECK_EQUAL(script.size(), 23U);
+ - ]
91 : :
92 : 1 : CompressedScript out;
93 [ + - ]: 1 : bool done = CompressScript(script, out);
94 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(done, true);
95 : :
96 : : // Check compressed script
97 [ + - - + : 1 : BOOST_CHECK_EQUAL(out.size(), 21U);
+ - ]
98 [ + - - + : 1 : BOOST_CHECK_EQUAL(out[0], 0x01);
+ - ]
99 [ + - - + : 1 : BOOST_CHECK_EQUAL(memcmp(out.data() + 1, script.data() + 2, 20), 0); // compare the 20 relevant chars of the CScriptId in the script
- + + - ]
100 : 1 : }
101 : :
102 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(compress_script_to_compressed_pubkey_id)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
103 : : {
104 : 1 : CKey key = GenerateRandomKey(); // case compressed PubKeyID
105 : :
106 [ + - + - : 1 : CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // COMPRESSED_PUBLIC_KEY_SIZE (33)
+ - ]
107 [ + - + - : 2 : BOOST_CHECK_EQUAL(script.size(), 35U);
+ - ]
108 : :
109 : 1 : CompressedScript out;
110 [ + - ]: 1 : bool done = CompressScript(script, out);
111 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(done, true);
112 : :
113 : : // Check compressed script
114 [ + - - + : 1 : BOOST_CHECK_EQUAL(out.size(), 33U);
+ - ]
115 [ + - - + : 2 : BOOST_CHECK_EQUAL(memcmp(out.data(), script.data() + 1, 1), 0);
+ - + - ]
116 [ + - + - : 2 : BOOST_CHECK_EQUAL(memcmp(out.data() + 1, script.data() + 2, 32), 0); // compare the 32 chars of the compressed CPubKey
- + + - ]
117 : 1 : }
118 : :
119 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(compress_script_to_uncompressed_pubkey_id)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
120 : : {
121 : 1 : CKey key = GenerateRandomKey(/*compressed=*/false); // case uncompressed PubKeyID
122 [ + - + - : 1 : CScript script = CScript() << ToByteVector(key.GetPubKey()) << OP_CHECKSIG; // PUBLIC_KEY_SIZE (65)
+ - ]
123 [ + - + - : 2 : BOOST_CHECK_EQUAL(script.size(), 67U); // 1 char code + 65 char pubkey + OP_CHECKSIG
+ - ]
124 : :
125 : 1 : CompressedScript out;
126 [ + - ]: 1 : bool done = CompressScript(script, out);
127 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(done, true);
128 : :
129 : : // Check compressed script
130 [ + - - + : 1 : BOOST_CHECK_EQUAL(out.size(), 33U);
+ - ]
131 [ + - + - : 2 : BOOST_CHECK_EQUAL(memcmp(out.data() + 1, script.data() + 2, 32), 0); // first 32 chars of CPubKey are copied into out[1:]
- + + - ]
132 [ + - + - : 2 : BOOST_CHECK_EQUAL(out[0], 0x04 | (script[65] & 0x01)); // least significant bit (lsb) of last char of pubkey is mapped into out[0]
- + + - ]
133 : 1 : }
134 : :
135 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(compress_p2pk_scripts_not_on_curve)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
136 : : {
137 : 1 : XOnlyPubKey x_not_on_curve;
138 : 1 : do {
139 : 1 : x_not_on_curve = XOnlyPubKey(m_rng.randbytes(32));
140 [ - + ]: 1 : } while (x_not_on_curve.IsFullyValid());
141 : :
142 : : // Check that P2PK script with uncompressed pubkey [=> OP_PUSH65 <0x04 .....> OP_CHECKSIG]
143 : : // which is not fully valid (i.e. point is not on curve) can't be compressed
144 : 1 : std::vector<unsigned char> pubkey_raw(65, 0);
145 : 1 : pubkey_raw[0] = 4;
146 : 1 : std::copy(x_not_on_curve.begin(), x_not_on_curve.end(), &pubkey_raw[1]);
147 : 1 : CPubKey pubkey_not_on_curve(pubkey_raw);
148 [ - + ]: 1 : assert(pubkey_not_on_curve.IsValid());
149 [ + - - + ]: 1 : assert(!pubkey_not_on_curve.IsFullyValid());
150 [ + - + - ]: 1 : CScript script = CScript() << ToByteVector(pubkey_not_on_curve) << OP_CHECKSIG;
151 [ + - + - : 2 : BOOST_CHECK_EQUAL(script.size(), 67U);
+ - ]
152 : :
153 : 1 : CompressedScript out;
154 [ + - ]: 1 : bool done = CompressScript(script, out);
155 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(done, false);
156 : :
157 : : // Check that compressed P2PK script with uncompressed pubkey that is not fully
158 : : // valid (i.e. x coordinate of the pubkey is not on curve) can't be decompressed
159 : 1 : CompressedScript compressed_script(x_not_on_curve.begin(), x_not_on_curve.end());
160 [ + + ]: 3 : for (unsigned int compression_id : {4, 5}) {
161 : 2 : CScript uncompressed_script;
162 [ + - ]: 2 : bool success = DecompressScript(uncompressed_script, compression_id, compressed_script);
163 [ + - + - ]: 2 : BOOST_CHECK_EQUAL(success, false);
164 : 2 : }
165 : 1 : }
166 : :
167 : : BOOST_AUTO_TEST_SUITE_END()
|