Bitcoin ABC 0.30.5
P2P Digital Currency
compressor.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2014 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/standard.h>
10
11/*
12 * These check for scripts for which a special case with a shorter encoding is
13 * defined. They are implemented separately from the CScript test, as these test
14 * for exact byte sequence correspondences, and are more strict. For example,
15 * IsToPubKey also verifies whether the public key is valid (as invalid ones
16 * cannot be represented in compressed form).
17 */
18
19static bool IsToKeyID(const CScript &script, CKeyID &hash) {
20 if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 &&
21 script[2] == 20 && script[23] == OP_EQUALVERIFY &&
22 script[24] == OP_CHECKSIG) {
23 memcpy(&hash, &script[3], 20);
24 return true;
25 }
26 return false;
27}
28
29static bool IsToScriptID(const CScript &script, CScriptID &hash) {
30 if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 &&
31 script[22] == OP_EQUAL) {
32 memcpy(&hash, &script[2], 20);
33 return true;
34 }
35 return false;
36}
37
38static bool IsToPubKey(const CScript &script, CPubKey &pubkey) {
39 if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG &&
40 (script[1] == 0x02 || script[1] == 0x03)) {
41 pubkey.Set(&script[1], &script[34]);
42 return true;
43 }
44 if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG &&
45 script[1] == 0x04) {
46 pubkey.Set(&script[1], &script[66]);
47 // if not fully valid, a case that would not be compressible
48 return pubkey.IsFullyValid();
49 }
50 return false;
51}
52
53bool CompressScript(const CScript &script, std::vector<uint8_t> &out) {
54 CKeyID keyID;
55 if (IsToKeyID(script, keyID)) {
56 out.resize(21);
57 out[0] = 0x00;
58 memcpy(&out[1], &keyID, 20);
59 return true;
60 }
61 CScriptID scriptID;
62 if (IsToScriptID(script, scriptID)) {
63 out.resize(21);
64 out[0] = 0x01;
65 memcpy(&out[1], &scriptID, 20);
66 return true;
67 }
68 CPubKey pubkey;
69 if (IsToPubKey(script, pubkey)) {
70 out.resize(33);
71 memcpy(&out[1], &pubkey[1], 32);
72 if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
73 out[0] = pubkey[0];
74 return true;
75 } else if (pubkey[0] == 0x04) {
76 out[0] = 0x04 | (pubkey[64] & 0x01);
77 return true;
78 }
79 }
80 return false;
81}
82
83unsigned int GetSpecialScriptSize(unsigned int nSize) {
84 if (nSize == 0 || nSize == 1) {
85 return 20;
86 }
87 if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5) {
88 return 32;
89 }
90 return 0;
91}
92
93bool DecompressScript(CScript &script, unsigned int nSize,
94 const std::vector<uint8_t> &in) {
95 switch (nSize) {
96 case 0x00:
97 script.resize(25);
98 script[0] = OP_DUP;
99 script[1] = OP_HASH160;
100 script[2] = 20;
101 memcpy(&script[3], in.data(), 20);
102 script[23] = OP_EQUALVERIFY;
103 script[24] = OP_CHECKSIG;
104 return true;
105 case 0x01:
106 script.resize(23);
107 script[0] = OP_HASH160;
108 script[1] = 20;
109 memcpy(&script[2], in.data(), 20);
110 script[22] = OP_EQUAL;
111 return true;
112 case 0x02:
113 case 0x03:
114 script.resize(35);
115 script[0] = 33;
116 script[1] = nSize;
117 memcpy(&script[2], in.data(), 32);
118 script[34] = OP_CHECKSIG;
119 return true;
120 case 0x04:
121 case 0x05:
122 uint8_t vch[33] = {};
123 vch[0] = nSize - 2;
124 memcpy(&vch[1], in.data(), 32);
125 CPubKey pubkey{vch};
126 if (!pubkey.Decompress()) {
127 return false;
128 }
129 assert(pubkey.size() == 65);
130 script.resize(67);
131 script[0] = 65;
132 memcpy(&script[1], pubkey.begin(), 65);
133 script[66] = OP_CHECKSIG;
134 return true;
135 }
136 return false;
137}
138
139// Amount compression:
140// * If the amount is 0, output 0
141// * first, divide the amount (in base units) by the largest power of 10
142// 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,
144// and drop it (divide by 10)
145// * call the result n
146// * output 1 + 10*(9*n + d - 1) + e
147// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n
148// - 1) + 9
149// (this is decodable, as d is in [1-9] and e is in [0-9])
150uint64_t CompressAmount(Amount amt) {
151 uint64_t n = amt / SATOSHI;
152 if (n == 0) {
153 return 0;
154 }
155 int e = 0;
156 while (((n % 10) == 0) && e < 9) {
157 n /= 10;
158 e++;
159 }
160 if (e < 9) {
161 int d = (n % 10);
162 assert(d >= 1 && d <= 9);
163 n /= 10;
164 return 1 + (n * 9 + d - 1) * 10 + e;
165 } else {
166 return 1 + (n - 1) * 10 + 9;
167 }
168}
169
171 // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9
172 if (x == 0) {
173 return Amount::zero();
174 }
175 x--;
176 // x = 10*(9*n + d - 1) + e
177 int e = x % 10;
178 x /= 10;
179 uint64_t n = 0;
180 if (e < 9) {
181 // x = 9*n + d - 1
182 int d = (x % 9) + 1;
183 x /= 9;
184 // x = n
185 n = x * 10 + d;
186 } else {
187 n = x + 1;
188 }
189 while (e) {
190 n *= 10;
191 e--;
192 }
193 return int64_t(n) * SATOSHI;
194}
static constexpr Amount SATOSHI
Definition: amount.h:143
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:22
An encapsulated public key.
Definition: pubkey.h:31
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
Definition: pubkey.cpp:256
void Set(const T pbegin, const T pend)
Initialize a public key using begin/end iterators to byte data.
Definition: pubkey.h:78
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:431
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:24
size_type size() const
Definition: prevector.h:394
value_type * data()
Definition: prevector.h:618
iterator begin()
Definition: prevector.h:398
void resize(size_type new_size)
Definition: prevector.h:424
static bool IsToPubKey(const CScript &script, CPubKey &pubkey)
Definition: compressor.cpp:38
static bool IsToKeyID(const CScript &script, CKeyID &hash)
Definition: compressor.cpp:19
Amount DecompressAmount(uint64_t x)
Definition: compressor.cpp:170
static bool IsToScriptID(const CScript &script, CScriptID &hash)
Definition: compressor.cpp:29
uint64_t CompressAmount(Amount amt)
Compress amount.
Definition: compressor.cpp:150
unsigned int GetSpecialScriptSize(unsigned int nSize)
Definition: compressor.cpp:83
bool CompressScript(const CScript &script, std::vector< uint8_t > &out)
Definition: compressor.cpp:53
bool DecompressScript(CScript &script, unsigned int nSize, const std::vector< uint8_t > &in)
Definition: compressor.cpp:93
@ OP_CHECKSIG
Definition: script.h:163
@ OP_EQUAL
Definition: script.h:119
@ OP_DUP
Definition: script.h:98
@ OP_HASH160
Definition: script.h:160
@ OP_EQUALVERIFY
Definition: script.h:120
Definition: amount.h:19
static constexpr Amount zero() noexcept
Definition: amount.h:32
assert(!tx.IsCoinBase())