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 2563127 : static bool IsToKeyID(const CScript& script, CKeyID &hash)
22 : {
23 14001770 : if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
24 4574974 : memcpy(&hash, &script[3], 20);
25 2287487 : return true;
26 : }
27 : return false;
28 : }
29 :
30 275639 : static bool IsToScriptID(const CScript& script, CScriptID &hash)
31 : {
32 733101 : if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 && script[22] == OP_EQUAL) {
33 304172 : memcpy(&hash, &script[2], 20);
34 152086 : return true;
35 : }
36 : return false;
37 : }
38 :
39 123553 : static bool IsToPubKey(const CScript& script, CPubKey &pubkey)
40 : {
41 127523 : 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 122631 : 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 2563127 : bool CompressScript(const CScript& script, std::vector<unsigned char> &out)
53 : {
54 2563127 : CKeyID keyID;
55 2563127 : if (IsToKeyID(script, keyID)) {
56 2287487 : out.resize(21);
57 2287487 : out[0] = 0x00;
58 2287487 : memcpy(&out[1], &keyID, 20);
59 2287487 : return true;
60 : }
61 275639 : CScriptID scriptID;
62 275639 : if (IsToScriptID(script, scriptID)) {
63 152086 : out.resize(21);
64 152086 : out[0] = 0x01;
65 152086 : memcpy(&out[1], &scriptID, 20);
66 152086 : return true;
67 : }
68 123553 : CPubKey pubkey;
69 123553 : 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 7145518 : unsigned int GetSpecialScriptSize(unsigned int nSize)
84 : {
85 7145518 : 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 7145518 : bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &in)
93 : {
94 7145518 : switch (nSize) {
95 7138213 : case 0x00:
96 7138213 : script.resize(25);
97 7138213 : script[0] = OP_DUP;
98 7138213 : script[1] = OP_HASH160;
99 7138213 : script[2] = 20;
100 14276466 : memcpy(&script[3], in.data(), 20);
101 7138213 : script[23] = OP_EQUALVERIFY;
102 7138213 : script[24] = OP_CHECKSIG;
103 7138213 : 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 3203133 : uint64_t CompressAmount(uint64_t n)
147 : {
148 3203133 : if (n == 0)
149 : return 0;
150 : int e = 0;
151 8821160 : while (((n % 10) == 0) && e < 9) {
152 5627580 : n /= 10;
153 5627580 : e++;
154 : }
155 3193589 : if (e < 9) {
156 2704915 : int d = (n % 10);
157 2704915 : assert(d >= 1 && d <= 9);
158 2704915 : n /= 10;
159 2704915 : return 1 + (n * 9 + d - 1) * 10 + e;
160 : } else {
161 488675 : return 1 + (n - 1) * 10 + 9;
162 : }
163 : }
164 :
165 7792769 : 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 7792769 : if (x == 0)
169 : return 0;
170 7792202 : x--;
171 : // x = 10*(9*n + d - 1) + e
172 7792202 : int e = x % 10;
173 7792202 : x /= 10;
174 7792202 : uint64_t n = 0;
175 7792202 : if (e < 9) {
176 : // x = 9*n + d - 1
177 7295246 : int d = (x % 9) + 1;
178 7295246 : x /= 9;
179 : // x = n
180 7295246 : n = x * 10 + d;
181 : } else {
182 496955 : n = x + 1;
183 : }
184 13591480 : while (e) {
185 5799280 : n *= 10;
186 5799280 : e--;
187 : }
188 : return n;
189 : }
|