jtimon
10 years ago
committed by
Pieter Wuille
6 changed files with 215 additions and 195 deletions
@ -0,0 +1,127 @@
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "compressor.h" |
||||
|
||||
bool CScriptCompressor::IsToKeyID(CKeyID &hash) const |
||||
{ |
||||
if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 |
||||
&& script[2] == 20 && script[23] == OP_EQUALVERIFY |
||||
&& script[24] == OP_CHECKSIG) { |
||||
memcpy(&hash, &script[3], 20); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
bool CScriptCompressor::IsToScriptID(CScriptID &hash) const |
||||
{ |
||||
if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20 |
||||
&& script[22] == OP_EQUAL) { |
||||
memcpy(&hash, &script[2], 20); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const |
||||
{ |
||||
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG |
||||
&& (script[1] == 0x02 || script[1] == 0x03)) { |
||||
pubkey.Set(&script[1], &script[34]); |
||||
return true; |
||||
} |
||||
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG |
||||
&& script[1] == 0x04) { |
||||
pubkey.Set(&script[1], &script[66]); |
||||
return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
|
||||
} |
||||
return false; |
||||
} |
||||
|
||||
bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const |
||||
{ |
||||
CKeyID keyID; |
||||
if (IsToKeyID(keyID)) { |
||||
out.resize(21); |
||||
out[0] = 0x00; |
||||
memcpy(&out[1], &keyID, 20); |
||||
return true; |
||||
} |
||||
CScriptID scriptID; |
||||
if (IsToScriptID(scriptID)) { |
||||
out.resize(21); |
||||
out[0] = 0x01; |
||||
memcpy(&out[1], &scriptID, 20); |
||||
return true; |
||||
} |
||||
CPubKey pubkey; |
||||
if (IsToPubKey(pubkey)) { |
||||
out.resize(33); |
||||
memcpy(&out[1], &pubkey[1], 32); |
||||
if (pubkey[0] == 0x02 || pubkey[0] == 0x03) { |
||||
out[0] = pubkey[0]; |
||||
return true; |
||||
} else if (pubkey[0] == 0x04) { |
||||
out[0] = 0x04 | (pubkey[64] & 0x01); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const |
||||
{ |
||||
if (nSize == 0 || nSize == 1) |
||||
return 20; |
||||
if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5) |
||||
return 32; |
||||
return 0; |
||||
} |
||||
|
||||
bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in) |
||||
{ |
||||
switch(nSize) { |
||||
case 0x00: |
||||
script.resize(25); |
||||
script[0] = OP_DUP; |
||||
script[1] = OP_HASH160; |
||||
script[2] = 20; |
||||
memcpy(&script[3], &in[0], 20); |
||||
script[23] = OP_EQUALVERIFY; |
||||
script[24] = OP_CHECKSIG; |
||||
return true; |
||||
case 0x01: |
||||
script.resize(23); |
||||
script[0] = OP_HASH160; |
||||
script[1] = 20; |
||||
memcpy(&script[2], &in[0], 20); |
||||
script[22] = OP_EQUAL; |
||||
return true; |
||||
case 0x02: |
||||
case 0x03: |
||||
script.resize(35); |
||||
script[0] = 33; |
||||
script[1] = nSize; |
||||
memcpy(&script[2], &in[0], 32); |
||||
script[34] = OP_CHECKSIG; |
||||
return true; |
||||
case 0x04: |
||||
case 0x05: |
||||
unsigned char vch[33] = {}; |
||||
vch[0] = nSize - 2; |
||||
memcpy(&vch[1], &in[0], 32); |
||||
CPubKey pubkey(&vch[0], &vch[33]); |
||||
if (!pubkey.Decompress()) |
||||
return false; |
||||
assert(pubkey.size() == 65); |
||||
script.resize(67); |
||||
script[0] = 65; |
||||
memcpy(&script[1], pubkey.begin(), 65); |
||||
script[66] = OP_CHECKSIG; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef H_BITCOIN_SCRIPT_COMPRESSOR |
||||
#define H_BITCOIN_SCRIPT_COMPRESSOR |
||||
|
||||
#include "script/script.h" |
||||
|
||||
/** Compact serializer for scripts.
|
||||
* |
||||
* It detects common cases and encodes them much more efficiently. |
||||
* 3 special cases are defined: |
||||
* * Pay to pubkey hash (encoded as 21 bytes) |
||||
* * Pay to script hash (encoded as 21 bytes) |
||||
* * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) |
||||
* |
||||
* Other scripts up to 121 bytes require 1 byte + script length. Above |
||||
* that, scripts up to 16505 bytes require 2 bytes + script length. |
||||
*/ |
||||
class CScriptCompressor |
||||
{ |
||||
private: |
||||
// make this static for now (there are only 6 special scripts defined)
|
||||
// this can potentially be extended together with a new nVersion for
|
||||
// transactions, in which case this value becomes dependent on nVersion
|
||||
// and nHeight of the enclosing transaction.
|
||||
static const unsigned int nSpecialScripts = 6; |
||||
|
||||
CScript &script; |
||||
protected: |
||||
// These check for scripts for which a special case with a shorter encoding is defined.
|
||||
// They are implemented separately from the CScript test, as these test for exact byte
|
||||
// sequence correspondences, and are more strict. For example, IsToPubKey also verifies
|
||||
// whether the public key is valid (as invalid ones cannot be represented in compressed
|
||||
// form).
|
||||
bool IsToKeyID(CKeyID &hash) const; |
||||
bool IsToScriptID(CScriptID &hash) const; |
||||
bool IsToPubKey(CPubKey &pubkey) const; |
||||
|
||||
bool Compress(std::vector<unsigned char> &out) const; |
||||
unsigned int GetSpecialSize(unsigned int nSize) const; |
||||
bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out); |
||||
public: |
||||
CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } |
||||
|
||||
unsigned int GetSerializeSize(int nType, int nVersion) const { |
||||
std::vector<unsigned char> compr; |
||||
if (Compress(compr)) |
||||
return compr.size(); |
||||
unsigned int nSize = script.size() + nSpecialScripts; |
||||
return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); |
||||
} |
||||
|
||||
template<typename Stream> |
||||
void Serialize(Stream &s, int nType, int nVersion) const { |
||||
std::vector<unsigned char> compr; |
||||
if (Compress(compr)) { |
||||
s << CFlatData(compr); |
||||
return; |
||||
} |
||||
unsigned int nSize = script.size() + nSpecialScripts; |
||||
s << VARINT(nSize); |
||||
s << CFlatData(script); |
||||
} |
||||
|
||||
template<typename Stream> |
||||
void Unserialize(Stream &s, int nType, int nVersion) { |
||||
unsigned int nSize = 0; |
||||
s >> VARINT(nSize); |
||||
if (nSize < nSpecialScripts) { |
||||
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00); |
||||
s >> REF(CFlatData(vch)); |
||||
Decompress(nSize, vch); |
||||
return; |
||||
} |
||||
nSize -= nSpecialScripts; |
||||
script.resize(nSize); |
||||
s >> REF(CFlatData(script)); |
||||
} |
||||
}; |
||||
|
||||
#endif |
Loading…
Reference in new issue