Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2014 The Bitcoin developers
3 : // Copyright (c) 2017-2019 The PIVX Core developers
4 : // Distributed under the MIT software license, see the accompanying
5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 :
7 : #include "compressor.h"
8 :
9 : #include "hash.h"
10 : #include "pubkey.h"
11 : #include "script/standard.h"
12 :
13 : /*
14 : * These check for scripts for which a special case with a shorter encoding is defined.
15 : * They are implemented separately from the CScript test, as these test for exact byte
16 : * sequence correspondences, and are more strict. For example, IsToPubKey also verifies
17 : * whether the public key is valid (as invalid ones cannot be represented in compressed
18 : * form).
19 : */
20 :
21 1862857 : static bool IsToKeyID(const CScript& script, CKeyID &hash)
22 : {
23 9805450 : if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
24 3176554 : memcpy(&hash, &script[3], 20);
25 1588277 : return true;
26 : }
27 : return false;
28 : }
29 :
30 274583 : static bool IsToScriptID(const CScript& script, CScriptID &hash)
31 : {
32 729318 : if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 && script[22] == OP_EQUAL) {
33 302354 : memcpy(&hash, &script[2], 20);
34 151177 : return true;
35 : }
36 : return false;
37 : }
38 :
39 123406 : static bool IsToPubKey(const CScript& script, CPubKey &pubkey)
40 : {
41 127376 : if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && (script[1] == 0x02 || script[1] == 0x03)) {
42 922 : pubkey.Set(&script[1], &script[34]);
43 922 : return true;
44 : }
45 122484 : if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG && script[1] == 0x04) {
46 0 : pubkey.Set(&script[1], &script[66]);
47 0 : return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
48 : }
49 : return false;
50 : }
51 :
52 1862857 : bool CompressScript(const CScript& script, std::vector<unsigned char> &out)
53 : {
54 1862857 : CKeyID keyID;
55 1862857 : if (IsToKeyID(script, keyID)) {
56 1588277 : out.resize(21);
57 1588277 : out[0] = 0x00;
58 1588277 : memcpy(&out[1], &keyID, 20);
59 1588277 : return true;
60 : }
61 274583 : CScriptID scriptID;
62 274583 : if (IsToScriptID(script, scriptID)) {
63 151177 : out.resize(21);
64 151177 : out[0] = 0x01;
65 151177 : memcpy(&out[1], &scriptID, 20);
66 151177 : return true;
67 : }
68 123406 : CPubKey pubkey;
69 123406 : if (IsToPubKey(script, pubkey)) {
70 922 : out.resize(33);
71 922 : memcpy(&out[1], &pubkey[1], 32);
72 922 : if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
73 922 : out[0] = pubkey[0];
74 922 : return true;
75 0 : } else if (pubkey[0] == 0x04) {
76 0 : out[0] = 0x04 | (pubkey[64] & 0x01);
77 0 : return true;
78 : }
79 : }
80 : return false;
81 : }
82 :
83 6585868 : unsigned int GetSpecialScriptSize(unsigned int nSize)
84 : {
85 6585868 : if (nSize == 0 || nSize == 1)
86 : return 20;
87 633 : if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)
88 633 : return 32;
89 : return 0;
90 : }
91 :
92 6585868 : bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &in)
93 : {
94 6585868 : switch (nSize) {
95 6578563 : case 0x00:
96 6578563 : script.resize(25);
97 6578563 : script[0] = OP_DUP;
98 6578563 : script[1] = OP_HASH160;
99 6578563 : script[2] = 20;
100 13157166 : memcpy(&script[3], in.data(), 20);
101 6578563 : script[23] = OP_EQUALVERIFY;
102 6578563 : script[24] = OP_CHECKSIG;
103 6578563 : return true;
104 6671 : case 0x01:
105 6671 : script.resize(23);
106 6671 : script[0] = OP_HASH160;
107 6671 : script[1] = 20;
108 13342 : memcpy(&script[2], in.data(), 20);
109 6671 : script[22] = OP_EQUAL;
110 6671 : return true;
111 633 : case 0x02:
112 633 : case 0x03:
113 633 : script.resize(35);
114 633 : script[0] = 33;
115 633 : script[1] = nSize;
116 1266 : memcpy(&script[2], in.data(), 32);
117 633 : script[34] = OP_CHECKSIG;
118 633 : return true;
119 0 : case 0x04:
120 0 : case 0x05:
121 0 : unsigned char vch[33] = {};
122 0 : vch[0] = nSize - 2;
123 0 : memcpy(&vch[1], in.data(), 32);
124 0 : CPubKey pubkey(&vch[0], &vch[33]);
125 0 : if (!pubkey.Decompress())
126 : return false;
127 0 : assert(pubkey.size() == 65);
128 0 : script.resize(67);
129 0 : script[0] = 65;
130 0 : memcpy(&script[1], pubkey.begin(), 65);
131 0 : script[66] = OP_CHECKSIG;
132 0 : return true;
133 : }
134 : return false;
135 : }
136 :
137 : // Amount compression:
138 : // * If the amount is 0, output 0
139 : // * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
140 : // * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)
141 : // * call the result n
142 : // * output 1 + 10*(9*n + d - 1) + e
143 : // * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
144 : // (this is decodable, as d is in [1-9] and e is in [0-9])
145 :
146 2502863 : uint64_t CompressAmount(uint64_t n)
147 : {
148 2502863 : if (n == 0)
149 : return 0;
150 : int e = 0;
151 8035010 : while (((n % 10) == 0) && e < 9) {
152 5541540 : n /= 10;
153 5541540 : e++;
154 : }
155 2493469 : if (e < 9) {
156 2005155 : int d = (n % 10);
157 2005155 : assert(d >= 1 && d <= 9);
158 2005155 : n /= 10;
159 2005155 : return 1 + (n * 9 + d - 1) * 10 + e;
160 : } else {
161 488311 : return 1 + (n - 1) * 10 + 9;
162 : }
163 : }
164 :
165 7233119 : uint64_t DecompressAmount(uint64_t x)
166 : {
167 : // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9
168 7233119 : if (x == 0)
169 : return 0;
170 7232562 : x--;
171 : // x = 10*(9*n + d - 1) + e
172 7232562 : int e = x % 10;
173 7232562 : x /= 10;
174 7232562 : uint64_t n = 0;
175 7232562 : if (e < 9) {
176 : // x = 9*n + d - 1
177 6736786 : int d = (x % 9) + 1;
178 6736786 : x /= 9;
179 : // x = n
180 6736786 : n = x * 10 + d;
181 : } else {
182 495776 : n = x + 1;
183 : }
184 12960680 : while (e) {
185 5728120 : n *= 10;
186 5728120 : e--;
187 : }
188 : return n;
189 : }
|