1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 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 "bitcoinconsensus.h"
7 
8 #include "primitives/transaction.h"
9 #include "pubkey.h"
10 #include "script/interpreter.h"
11 #include "version.h"
12 
13 namespace {
14 
15 /** A class that deserializes a single CTransaction one time. */
16 class TxInputStream
17 {
18 public:
TxInputStream(int nTypeIn,int nVersionIn,const unsigned char * txTo,size_t txToLen)19     TxInputStream(int nTypeIn, int nVersionIn, const unsigned char *txTo, size_t txToLen) :
20     m_type(nTypeIn),
21     m_version(nVersionIn),
22     m_data(txTo),
23     m_remaining(txToLen)
24     {}
25 
read(char * pch,size_t nSize)26     TxInputStream& read(char* pch, size_t nSize)
27     {
28         if (nSize > m_remaining)
29             throw std::ios_base::failure(std::string(__func__) + ": end of data");
30 
31         if (pch == NULL)
32             throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer");
33 
34         if (m_data == NULL)
35             throw std::ios_base::failure(std::string(__func__) + ": bad source buffer");
36 
37         memcpy(pch, m_data, nSize);
38         m_remaining -= nSize;
39         m_data += nSize;
40         return *this;
41     }
42 
43     template<typename T>
operator >>(T & obj)44     TxInputStream& operator>>(T& obj)
45     {
46         ::Unserialize(*this, obj, m_type, m_version);
47         return *this;
48     }
49 
50 private:
51     const int m_type;
52     const int m_version;
53     const unsigned char* m_data;
54     size_t m_remaining;
55 };
56 
set_error(bitcoinconsensus_error * ret,bitcoinconsensus_error serror)57 inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
58 {
59     if (ret)
60         *ret = serror;
61     return 0;
62 }
63 
64 struct ECCryptoClosure
65 {
66     ECCVerifyHandle handle;
67 };
68 
69 ECCryptoClosure instance_of_eccryptoclosure;
70 }
71 
verify_script(const unsigned char * scriptPubKey,unsigned int scriptPubKeyLen,CAmount amount,const unsigned char * txTo,unsigned int txToLen,unsigned int nIn,unsigned int flags,bitcoinconsensus_error * err)72 static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
73                                     const unsigned char *txTo        , unsigned int txToLen,
74                                     unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
75 {
76     try {
77         TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen);
78         CTransaction tx;
79         stream >> tx;
80         if (nIn >= tx.vin.size())
81             return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
82         if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen)
83             return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
84 
85         // Regardless of the verification result, the tx did not error.
86         set_error(err, bitcoinconsensus_ERR_OK);
87         PrecomputedTransactionData txdata(tx);
88         return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
89     } catch (const std::exception&) {
90         return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
91     }
92 }
93 
bitcoinconsensus_verify_script_with_amount(const unsigned char * scriptPubKey,unsigned int scriptPubKeyLen,int64_t amount,const unsigned char * txTo,unsigned int txToLen,unsigned int nIn,unsigned int flags,bitcoinconsensus_error * err)94 int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
95                                     const unsigned char *txTo        , unsigned int txToLen,
96                                     unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
97 {
98     CAmount am(amount);
99     return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
100 }
101 
102 
bitcoinconsensus_verify_script(const unsigned char * scriptPubKey,unsigned int scriptPubKeyLen,const unsigned char * txTo,unsigned int txToLen,unsigned int nIn,unsigned int flags,bitcoinconsensus_error * err)103 int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
104                                    const unsigned char *txTo        , unsigned int txToLen,
105                                    unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
106 {
107     if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
108         return set_error(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
109     }
110 
111     CAmount am(0);
112     return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
113 }
114 
bitcoinconsensus_version()115 unsigned int bitcoinconsensus_version()
116 {
117     // Just use the API version for now
118     return BITCOINCONSENSUS_API_VER;
119 }
120