/Users/eugenesiegel/btc/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 | 324k | { | 
| 21 | 324k |     if (script.size() == 25 && script[0] == OP_DUP0&& script[1] == OP_HASH1600 | 
| 22 | 324k |                             && script[2] == 200&& script[23] == OP_EQUALVERIFY0 | 
| 23 | 324k |                             && script[24] == OP_CHECKSIG0) { | 
| 24 | 0 |         memcpy(&hash, &script[3], 20); | 
| 25 | 0 |         return true; | 
| 26 | 0 |     } | 
| 27 | 324k |     return false; | 
| 28 | 324k | } | 
| 29 |  |  | 
| 30 |  | static bool IsToScriptID(const CScript& script, CScriptID &hash) | 
| 31 | 324k | { | 
| 32 | 324k |     if (script.size() == 23 && script[0] == OP_HASH1600&& script[1] == 200 | 
| 33 | 324k |                             && script[22] == OP_EQUAL0) { | 
| 34 | 0 |         memcpy(&hash, &script[2], 20); | 
| 35 | 0 |         return true; | 
| 36 | 0 |     } | 
| 37 | 324k |     return false; | 
| 38 | 324k | } | 
| 39 |  |  | 
| 40 |  | static bool IsToPubKey(const CScript& script, CPubKey &pubkey) | 
| 41 | 324k | { | 
| 42 | 324k |     if (script.size() == 35 && script[0] == 330&& script[34] == OP_CHECKSIG0 | 
| 43 | 324k |                             && (0 script[1] == 0x020|| script[1] == 0x030)) { | 
| 44 | 0 |         pubkey.Set(&script[1], &script[34]); | 
| 45 | 0 |         return true; | 
| 46 | 0 |     } | 
| 47 | 324k |     if (script.size() == 67 && script[0] == 650&& script[66] == OP_CHECKSIG0 | 
| 48 | 324k |                             && script[1] == 0x040) { | 
| 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 | 324k |     return false; | 
| 53 | 324k | } | 
| 54 |  |  | 
| 55 |  | bool CompressScript(const CScript& script, CompressedScript& out) | 
| 56 | 324k | { | 
| 57 | 324k |     CKeyID keyID; | 
| 58 | 324k |     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 | 324k |     CScriptID scriptID; | 
| 65 | 324k |     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 | 324k |     CPubKey pubkey; | 
| 72 | 324k |     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 | 324k |     return false; | 
| 84 | 324k | } | 
| 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 | 324k | { | 
| 151 | 324k |     if (n == 0) | 
| 152 | 0 |         return 0; | 
| 153 | 324k |     int e = 0; | 
| 154 | 2.14M |     while (((n % 10) == 0) && e < 91.81M) { | 
| 155 | 1.81M |         n /= 10; | 
| 156 | 1.81M |         e++; | 
| 157 | 1.81M |     } | 
| 158 | 324k |     if (e < 9) { | 
| 159 | 186k |         int d = (n % 10); | 
| 160 | 186k |         assert(d >= 1 && d <= 9); | 
| 161 | 186k |         n /= 10; | 
| 162 | 186k |         return 1 + (n*9 + d - 1)*10 + e; | 
| 163 | 186k |     } else { | 
| 164 | 138k |         return 1 + (n - 1)*10 + 9; | 
| 165 | 138k |     } | 
| 166 | 324k | } | 
| 167 |  |  | 
| 168 |  | uint64_t DecompressAmount(uint64_t x) | 
| 169 | 1.34M | { | 
| 170 |  |     // x = 0  OR  x = 1+10*(9*n + d - 1) + e  OR  x = 1+10*(n - 1) + 9 | 
| 171 | 1.34M |     if (x == 0) | 
| 172 | 0 |         return 0; | 
| 173 | 1.34M |     x--; | 
| 174 |  |     // x = 10*(9*n + d - 1) + e | 
| 175 | 1.34M |     int e = x % 10; | 
| 176 | 1.34M |     x /= 10; | 
| 177 | 1.34M |     uint64_t n = 0; | 
| 178 | 1.34M |     if (e < 9) { | 
| 179 |  |         // x = 9*n + d - 1 | 
| 180 | 307k |         int d = (x % 9) + 1; | 
| 181 | 307k |         x /= 9; | 
| 182 |  |         // x = n | 
| 183 | 307k |         n = x*10 + d; | 
| 184 | 1.03M |     } else { | 
| 185 | 1.03M |         n = x+1; | 
| 186 | 1.03M |     } | 
| 187 | 13.1M |     while (e) { | 
| 188 | 11.7M |         n *= 10; | 
| 189 | 11.7M |         e--; | 
| 190 | 11.7M |     } | 
| 191 | 1.34M |     return n; | 
| 192 | 1.34M | } |