PIVX Core  5.6.99
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 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 static bool IsToKeyID(const CScript& script, CKeyID &hash)
22 {
23  if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
24  memcpy(&hash, &script[3], 20);
25  return true;
26  }
27  return false;
28 }
29 
30 static bool IsToScriptID(const CScript& script, CScriptID &hash)
31 {
32  if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 && script[22] == OP_EQUAL) {
33  memcpy(&hash, &script[2], 20);
34  return true;
35  }
36  return false;
37 }
38 
39 static bool IsToPubKey(const CScript& script, CPubKey &pubkey)
40 {
41  if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && (script[1] == 0x02 || script[1] == 0x03)) {
42  pubkey.Set(&script[1], &script[34]);
43  return true;
44  }
45  if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG && script[1] == 0x04) {
46  pubkey.Set(&script[1], &script[66]);
47  return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
48  }
49  return false;
50 }
51 
52 bool CompressScript(const CScript& script, std::vector<unsigned char> &out)
53 {
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 
83 unsigned int GetSpecialScriptSize(unsigned int nSize)
84 {
85  if (nSize == 0 || nSize == 1)
86  return 20;
87  if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)
88  return 32;
89  return 0;
90 }
91 
92 bool DecompressScript(CScript& script, unsigned int nSize, const std::vector<unsigned char> &in)
93 {
94  switch (nSize) {
95  case 0x00:
96  script.resize(25);
97  script[0] = OP_DUP;
98  script[1] = OP_HASH160;
99  script[2] = 20;
100  memcpy(&script[3], in.data(), 20);
101  script[23] = OP_EQUALVERIFY;
102  script[24] = OP_CHECKSIG;
103  return true;
104  case 0x01:
105  script.resize(23);
106  script[0] = OP_HASH160;
107  script[1] = 20;
108  memcpy(&script[2], in.data(), 20);
109  script[22] = OP_EQUAL;
110  return true;
111  case 0x02:
112  case 0x03:
113  script.resize(35);
114  script[0] = 33;
115  script[1] = nSize;
116  memcpy(&script[2], in.data(), 32);
117  script[34] = OP_CHECKSIG;
118  return true;
119  case 0x04:
120  case 0x05:
121  unsigned char vch[33] = {};
122  vch[0] = nSize - 2;
123  memcpy(&vch[1], in.data(), 32);
124  CPubKey pubkey(&vch[0], &vch[33]);
125  if (!pubkey.Decompress())
126  return false;
127  assert(pubkey.size() == 65);
128  script.resize(67);
129  script[0] = 65;
130  memcpy(&script[1], pubkey.begin(), 65);
131  script[66] = OP_CHECKSIG;
132  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 uint64_t CompressAmount(uint64_t n)
147 {
148  if (n == 0)
149  return 0;
150  int e = 0;
151  while (((n % 10) == 0) && e < 9) {
152  n /= 10;
153  e++;
154  }
155  if (e < 9) {
156  int d = (n % 10);
157  assert(d >= 1 && d <= 9);
158  n /= 10;
159  return 1 + (n * 9 + d - 1) * 10 + e;
160  } else {
161  return 1 + (n - 1) * 10 + 9;
162  }
163 }
164 
165 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  if (x == 0)
169  return 0;
170  x--;
171  // x = 10*(9*n + d - 1) + e
172  int e = x % 10;
173  x /= 10;
174  uint64_t n = 0;
175  if (e < 9) {
176  // x = 9*n + d - 1
177  int d = (x % 9) + 1;
178  x /= 9;
179  // x = n
180  n = x * 10 + d;
181  } else {
182  n = x + 1;
183  }
184  while (e) {
185  n *= 10;
186  e--;
187  }
188  return n;
189 }
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:21
An encapsulated public key.
Definition: pubkey.h:44
bool Decompress()
Turn this public key into an uncompressed public key.
Definition: pubkey.cpp:219
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
Definition: pubkey.cpp:210
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
Definition: pubkey.h:121
const unsigned char * begin() const
Definition: pubkey.h:123
void Set(const T pbegin, const T pend)
Initialize a public key using begin/end iterators to byte data.
Definition: pubkey.h:98
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:24
size_type size() const
Definition: prevector.h:277
value_type * data()
Definition: prevector.h:526
void resize(size_type new_size)
Definition: prevector.h:311
bool DecompressScript(CScript &script, unsigned int nSize, const std::vector< unsigned char > &in)
Definition: compressor.cpp:92
bool CompressScript(const CScript &script, std::vector< unsigned char > &out)
Definition: compressor.cpp:52
uint64_t DecompressAmount(uint64_t x)
Definition: compressor.cpp:165
uint64_t CompressAmount(uint64_t n)
Definition: compressor.cpp:146
unsigned int GetSpecialScriptSize(unsigned int nSize)
Definition: compressor.cpp:83
void * memcpy(void *a, const void *b, size_t c)
@ OP_CHECKSIG
Definition: script.h:166
@ OP_EQUAL
Definition: script.h:122
@ OP_DUP
Definition: script.h:101
@ OP_HASH160
Definition: script.h:163
@ OP_EQUALVERIFY
Definition: script.h:123