LCOV - code coverage report
Current view: top level - src - compressor.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 101 102 99.0 %
Date: 2015-10-12 22:39:14 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "hash.h"
       9             : #include "pubkey.h"
      10             : #include "script/standard.h"
      11             : 
      12       16498 : bool CScriptCompressor::IsToKeyID(CKeyID &hash) const
      13             : {
      14       37077 :     if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160
      15        4081 :                             && script[2] == 20 && script[23] == OP_EQUALVERIFY
      16       20579 :                             && script[24] == OP_CHECKSIG) {
      17        8162 :         memcpy(&hash, &script[3], 20);
      18        4081 :         return true;
      19             :     }
      20             :     return false;
      21             : }
      22             : 
      23       12417 : bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
      24             : {
      25       24924 :     if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20
      26       12507 :                             && script[22] == OP_EQUAL) {
      27         180 :         memcpy(&hash, &script[2], 20);
      28          90 :         return true;
      29             :     }
      30             :     return false;
      31             : }
      32             : 
      33       12327 : bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
      34             : {
      35       36652 :     if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
      36       24325 :                             && (script[1] == 0x02 || script[1] == 0x03)) {
      37       35994 :         pubkey.Set(&script[1], &script[34]);
      38       11998 :         return true;
      39             :     }
      40         907 :     if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
      41         578 :                             && script[1] == 0x04) {
      42         747 :         pubkey.Set(&script[1], &script[66]);
      43         249 :         return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
      44             :     }
      45             :     return false;
      46             : }
      47             : 
      48       16498 : bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
      49             : {
      50             :     CKeyID keyID;
      51       16498 :     if (IsToKeyID(keyID)) {
      52        4081 :         out.resize(21);
      53        4081 :         out[0] = 0x00;
      54        8162 :         memcpy(&out[1], &keyID, 20);
      55        4081 :         return true;
      56             :     }
      57             :     CScriptID scriptID;
      58       12417 :     if (IsToScriptID(scriptID)) {
      59          90 :         out.resize(21);
      60          90 :         out[0] = 0x01;
      61         180 :         memcpy(&out[1], &scriptID, 20);
      62          90 :         return true;
      63             :     }
      64             :     CPubKey pubkey;
      65       12327 :     if (IsToPubKey(pubkey)) {
      66       12247 :         out.resize(33);
      67       24494 :         memcpy(&out[1], &pubkey[1], 32);
      68       12247 :         if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
      69       11998 :             out[0] = pubkey[0];
      70       11998 :             return true;
      71         249 :         } else if (pubkey[0] == 0x04) {
      72         249 :             out[0] = 0x04 | (pubkey[64] & 0x01);
      73         249 :             return true;
      74             :         }
      75             :     }
      76             :     return false;
      77             : }
      78             : 
      79       12341 : unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const
      80             : {
      81       12341 :     if (nSize == 0 || nSize == 1)
      82             :         return 20;
      83       11538 :     if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)
      84             :         return 32;
      85           0 :     return 0;
      86             : }
      87             : 
      88       12341 : bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in)
      89             : {
      90       12341 :     switch(nSize) {
      91             :     case 0x00:
      92         779 :         script.resize(25);
      93         779 :         script[0] = OP_DUP;
      94         779 :         script[1] = OP_HASH160;
      95         779 :         script[2] = 20;
      96        1558 :         memcpy(&script[3], &in[0], 20);
      97         779 :         script[23] = OP_EQUALVERIFY;
      98         779 :         script[24] = OP_CHECKSIG;
      99         779 :         return true;
     100             :     case 0x01:
     101          24 :         script.resize(23);
     102          24 :         script[0] = OP_HASH160;
     103          24 :         script[1] = 20;
     104          48 :         memcpy(&script[2], &in[0], 20);
     105          24 :         script[22] = OP_EQUAL;
     106          24 :         return true;
     107             :     case 0x02:
     108             :     case 0x03:
     109       11531 :         script.resize(35);
     110       11531 :         script[0] = 33;
     111       11531 :         script[1] = nSize;
     112       23062 :         memcpy(&script[2], &in[0], 32);
     113       11531 :         script[34] = OP_CHECKSIG;
     114       11531 :         return true;
     115             :     case 0x04:
     116             :     case 0x05:
     117           7 :         unsigned char vch[33] = {};
     118           7 :         vch[0] = nSize - 2;
     119           7 :         memcpy(&vch[1], &in[0], 32);
     120             :         CPubKey pubkey(&vch[0], &vch[33]);
     121           7 :         if (!pubkey.Decompress())
     122             :             return false;
     123          14 :         assert(pubkey.size() == 65);
     124           7 :         script.resize(67);
     125           7 :         script[0] = 65;
     126          14 :         memcpy(&script[1], pubkey.begin(), 65);
     127           7 :         script[66] = OP_CHECKSIG;
     128           7 :         return true;
     129             :     }
     130             :     return false;
     131             : }
     132             : 
     133             : // Amount compression:
     134             : // * If the amount is 0, output 0
     135             : // * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
     136             : // * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)
     137             : //   * call the result n
     138             : //   * output 1 + 10*(9*n + d - 1) + e
     139             : // * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
     140             : // (this is decodable, as d is in [1-9] and e is in [0-9])
     141             : 
     142      656504 : uint64_t CTxOutCompressor::CompressAmount(uint64_t n)
     143             : {
     144      656504 :     if (n == 0)
     145             :         return 0;
     146             :     int e = 0;
     147     5160696 :     while (((n % 10) == 0) && e < 9) {
     148     4504262 :         n /= 10;
     149     4504262 :         e++;
     150             :     }
     151      656434 :     if (e < 9) {
     152      215287 :         int d = (n % 10);
     153      215287 :         assert(d >= 1 && d <= 9);
     154      215287 :         n /= 10;
     155      215287 :         return 1 + (n*9 + d - 1)*10 + e;
     156             :     } else {
     157      441147 :         return 1 + (n - 1)*10 + 9;
     158             :     }
     159             : }
     160             : 
     161      652347 : uint64_t CTxOutCompressor::DecompressAmount(uint64_t x)
     162             : {
     163             :     // x = 0  OR  x = 1+10*(9*n + d - 1) + e  OR  x = 1+10*(n - 1) + 9
     164      652347 :     if (x == 0)
     165             :         return 0;
     166      652339 :     x--;
     167             :     // x = 10*(9*n + d - 1) + e
     168      652339 :     int e = x % 10;
     169      652339 :     x /= 10;
     170      652339 :     uint64_t n = 0;
     171      652339 :     if (e < 9) {
     172             :         // x = 9*n + d - 1
     173      212605 :         int d = (x % 9) + 1;
     174      212605 :         x /= 9;
     175             :         // x = n
     176      212605 :         n = x*10 + d;
     177             :     } else {
     178      439734 :         n = x+1;
     179             :     }
     180     5139062 :     while (e) {
     181     4486723 :         n *= 10;
     182     4486723 :         e--;
     183             :     }
     184      652339 :     return n;
     185             : }

Generated by: LCOV version 1.11