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