PIVX Core  5.6.99
P2P Digital Currency
zpivmodule.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2021 The PIVX Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "zpiv/zpivmodule.h"
6 
7 #include "hash.h"
9 #include "libzerocoin/Coin.h"
10 #include "validation.h"
11 
12 template <typename Stream>
13 PublicCoinSpend::PublicCoinSpend(libzerocoin::ZerocoinParams* params, Stream& strm): pubCoin(params) {
14  strm >> *this;
16 
17  if (this->version < PUBSPEND_SCHNORR) {
18  // coinVersion is serialized only from v4 spends
20 
21  } else {
22  // from v4 spends, serialNumber is not serialized for v2 coins anymore.
23  // in this case, we extract it from the coin public key
24  if (this->coinVersion >= libzerocoin::PUBKEY_VERSION)
26 
27  }
28 
29 }
30 
32  bool fUseV1Params = getCoinVersion() < libzerocoin::PUBKEY_VERSION;
33  if (version < PUBSPEND_SCHNORR) {
34  // spend contains the randomness of the coin
35  if (fUseV1Params) {
36  // Only v2+ coins can publish the randomness
37  std::string errMsg = strprintf("PublicCoinSpend version %d with coin version 1 not allowed. "
38  "Minimum spend version required: %d", version, PUBSPEND_SCHNORR);
39  return error("%s: %s", __func__, errMsg);
40  }
41 
42  // Check that the coin is a commitment to serial and randomness.
45  if (comm.getCommitmentValue() != pubCoin.getValue()) {
46  return error("%s: commitments values are not equal", __func__);
47  }
48 
49  } else {
50  // for v1 coins, double check that the serialized coin serial is indeed a v1 serial
51  if (coinVersion < libzerocoin::PUBKEY_VERSION &&
53  return error("%s: invalid coin version", __func__);
54  }
55 
56  // spend contains a shnorr signature of ptxHash with the randomness of the coin
59  return error("%s: schnorr signature does not verify", __func__);
60  }
61 
62  }
63 
64  // Now check that the signature validates with the serial
65  if (!HasValidSignature()) {
66  return error("%s: signature invalid", __func__);;
67  }
68 
69  return true;
70 }
71 
73 {
74  if (coinVersion < libzerocoin::PUBKEY_VERSION)
75  return true;
76 
77  // for spend version 3 we must check that the provided pubkey and serial number match
78  if (version < PUBSPEND_SCHNORR) {
79  CBigNum extractedSerial = libzerocoin::ExtractSerialFromPubKey(this->pubkey);
80  if (extractedSerial != this->coinSerialNumber)
81  return error("%s: hashedpubkey is not equal to the serial!", __func__);
82  }
83 
84  return pubkey.Verify(signatureHash(), vchSig);
85 }
86 
87 
89 {
90  CHashWriter h(0, 0);
92  return h.GetHash();
93 }
94 
95 // 6 comes from OPCODE (1) + vch.size() (1) + BIGNUM size (4)
96 #define SCRIPT_OFFSET 6
97 
98 static bool TxOutToPublicCoin(const CTxOut& txout, libzerocoin::PublicCoin& pubCoin, CValidationState& state)
99 {
100  CBigNum publicZerocoin;
101  std::vector<unsigned char> vchZeroMint;
102  vchZeroMint.insert(vchZeroMint.end(), txout.scriptPubKey.begin() + SCRIPT_OFFSET,
103  txout.scriptPubKey.begin() + txout.scriptPubKey.size());
104  publicZerocoin.setvch(vchZeroMint);
105 
107  LogPrint(BCLog::LEGACYZC, "%s : denomination %d for pubcoin %s\n", __func__, denomination, publicZerocoin.GetHex());
108  if (denomination == libzerocoin::ZQ_ERROR)
109  return state.DoS(100, error("%s: txout.nValue is not correct", __func__));
110 
111  libzerocoin::PublicCoin checkPubCoin(Params().GetConsensus().Zerocoin_Params(false), publicZerocoin, denomination);
112  pubCoin = checkPubCoin;
113 
114  return true;
115 }
116 
117 // TODO: do not create g_coinspends_cache if the node passed the last zc checkpoint.
119 private:
120  mutable Mutex cs;
121  std::map<CScript, libzerocoin::CoinSpend> cache_coinspend;
122  std::map<CScript, PublicCoinSpend> cache_public_coinspend;
123 
124  template<typename T>
125  Optional<T> Get(const CScript& in, const std::map<CScript, T>& map) const {
126  LOCK(cs);
127  auto it = map.find(in);
128  return it != map.end() ? Optional<T>{it->second} : nullopt;
129  }
130 
131 public:
132  void Add(const CScript& in, libzerocoin::CoinSpend& spend) { WITH_LOCK(cs, cache_coinspend.emplace(in, spend)); }
133  void AddPub(const CScript& in, PublicCoinSpend& spend) { WITH_LOCK(cs, cache_public_coinspend.emplace(in, spend)); }
134 
135  Optional<libzerocoin::CoinSpend> Get(const CScript& in) const { return Get<libzerocoin::CoinSpend>(in, cache_coinspend); }
136  Optional<PublicCoinSpend> GetPub(const CScript& in) const { return Get<PublicCoinSpend>(in, cache_public_coinspend); }
137  void Clear() {
138  LOCK(cs);
139  cache_coinspend.clear();
140  cache_public_coinspend.clear();
141  }
142 };
143 std::unique_ptr<CoinSpendCache> g_coinspends_cache = std::make_unique<CoinSpendCache>();
144 
145 namespace ZPIVModule {
146 
147  // Return stream of CoinSpend from tx input scriptsig
149  {
150  std::vector<char, zero_after_free_allocator<char> > data;
151  // skip opcode and data-len
152  uint8_t byteskip = ((uint8_t) scriptSig[1] + 2);
153  data.insert(data.end(), scriptSig.begin() + byteskip, scriptSig.end());
154  return CDataStream(data, SER_NETWORK, PROTOCOL_VERSION);
155  }
156 
158  {
160  CDataStream serializedCoinSpend = ScriptSigToSerializedSpend(in.scriptSig);
161  return PublicCoinSpend(params, serializedCoinSpend);
162  }
163 
164  bool parseCoinSpend(const CTxIn &in, const CTransaction &tx, const CTxOut &prevOut, PublicCoinSpend &publicCoinSpend) {
165  if (auto op = g_coinspends_cache->GetPub(in.scriptSig)) {
166  publicCoinSpend = *op;
167  return true;
168  }
169 
170  if (!in.IsZerocoinPublicSpend() || !prevOut.IsZerocoinMint())
171  return error("%s: invalid argument/s", __func__);
172 
173  PublicCoinSpend spend = parseCoinSpend(in);
174  spend.outputIndex = in.prevout.n;
175  spend.txHash = in.prevout.hash;
176  CMutableTransaction txNew(tx);
177  txNew.vin.clear();
178  spend.setTxOutHash(txNew.GetHash());
179 
180  // Check prev out now
181  CValidationState state;
182  if (!TxOutToPublicCoin(prevOut, spend.pubCoin, state))
183  return error("%s: cannot get mint from output", __func__);
184 
185  spend.setDenom(spend.pubCoin.getDenomination());
186  publicCoinSpend = spend;
187  g_coinspends_cache->AddPub(in.scriptSig, publicCoinSpend);
188  return true;
189  }
190 
192  {
193  if (auto op = g_coinspends_cache->Get(txin.scriptSig)) return *op;
194  CDataStream serializedCoinSpend = ScriptSigToSerializedSpend(txin.scriptSig);
195  libzerocoin::CoinSpend spend(serializedCoinSpend);
196  g_coinspends_cache->Add(txin.scriptSig, spend);
197  return spend;
198  }
199 
200  bool validateInput(const CTxIn &in, const CTxOut &prevOut, const CTransaction &tx, PublicCoinSpend &publicSpend) {
201  // Now prove that the commitment value opens to the input
202  if (!parseCoinSpend(in, tx, prevOut, publicSpend)) {
203  return false;
204  }
207  return error("PublicCoinSpend validateInput :: input nSequence different to prevout value");
208  }
209  return publicSpend.Verify();
210  }
211 
212  bool ParseZerocoinPublicSpend(const CTxIn &txIn, const CTransaction& tx, CValidationState& state, PublicCoinSpend& publicSpend)
213  {
214  CTxOut prevOut;
215  if(!GetOutput(txIn.prevout.hash, txIn.prevout.n ,state, prevOut)){
216  return state.DoS(100, error("%s: public zerocoin spend prev output not found, prevTx %s, index %d",
217  __func__, txIn.prevout.hash.GetHex(), txIn.prevout.n));
218  }
219  if (!ZPIVModule::parseCoinSpend(txIn, tx, prevOut, publicSpend)) {
220  return state.Invalid(error("%s: invalid public coin spend parse %s\n", __func__,
221  tx.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-zpiv");
222  }
223  return true;
224  }
225 
227  {
228  g_coinspends_cache->Clear();
229  }
230 }
PublicCoin class for the Zerocoin library.
Commitment and CommitmentProof classes for the Zerocoin library.
const CChainParams & Params()
Return the currently selected parameters.
uint256 hash
Definition: transaction.h:35
uint32_t n
Definition: transaction.h:36
iterator insert(iterator it, const char x=char())
Definition: streams.h:176
C++ wrapper for BIGNUM.
Definition: bignum.h:35
std::string GetHex() const
Definition: bignum.cpp:321
void setvch(const std::vector< unsigned char > &vch)
Definition: bignum.cpp:123
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:216
uint256 GetHash()
Definition: hash.h:236
bool Verify(const uint256 &hash, const std::vector< unsigned char > &vchSig) const
Verify a DER signature (~72 bytes).
Definition: pubkey.cpp:169
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
const uint256 & GetHash() const
Definition: transaction.h:301
An input of a transaction.
Definition: transaction.h:94
uint32_t nSequence
Definition: transaction.h:98
bool IsZerocoinPublicSpend() const
Definition: transaction.cpp:48
CScript scriptSig
Definition: transaction.h:97
COutPoint prevout
Definition: transaction.h:96
An output of a transaction.
Definition: transaction.h:137
CScript scriptPubKey
Definition: transaction.h:140
bool IsZerocoinMint() const
Definition: transaction.cpp:83
CAmount nValue
Definition: transaction.h:139
Capture information about block/transaction validation.
Definition: validation.h:24
bool Invalid(bool ret=false, unsigned int _chRejectCode=0, const std::string &_strRejectReason="", const std::string &_strDebugMessage="")
Definition: validation.h:55
bool DoS(int level, bool ret=false, unsigned int chRejectCodeIn=0, std::string strRejectReasonIn="", bool corruptionIn=false, const std::string &strDebugMessageIn="")
Definition: validation.h:39
std::map< CScript, libzerocoin::CoinSpend > cache_coinspend
Definition: zpivmodule.cpp:121
Optional< libzerocoin::CoinSpend > Get(const CScript &in) const
Definition: zpivmodule.cpp:135
Optional< PublicCoinSpend > GetPub(const CScript &in) const
Definition: zpivmodule.cpp:136
std::map< CScript, PublicCoinSpend > cache_public_coinspend
Definition: zpivmodule.cpp:122
Optional< T > Get(const CScript &in, const std::map< CScript, T > &map) const
Definition: zpivmodule.cpp:125
void AddPub(const CScript &in, PublicCoinSpend &spend)
Definition: zpivmodule.cpp:133
void Add(const CScript &in, libzerocoin::CoinSpend &spend)
Definition: zpivmodule.cpp:132
uint256 txHash
Definition: zpivmodule.h:42
CBigNum randomness
Definition: zpivmodule.h:39
const uint256 signatureHash() const override
Definition: zpivmodule.cpp:88
int getCoinVersion() const
Definition: zpivmodule.h:35
bool HasValidSignature() const
Definition: zpivmodule.cpp:72
PublicCoinSpend(libzerocoin::ZerocoinParams *params)
Definition: zpivmodule.h:27
libzerocoin::PublicCoin pubCoin
Definition: zpivmodule.h:44
bool Verify() const
Definition: zpivmodule.cpp:31
libzerocoin::CoinRandomnessSchnorrSignature schnorrSig
Definition: zpivmodule.h:40
unsigned int outputIndex
Definition: zpivmodule.h:43
std::string GetHex() const
Definition: uint256.cpp:21
bool Verify(const ZerocoinParams *zcparams, const CBigNum &S, const CBigNum &C, const uint256 msghash) const
Verifies the Schnorr signature on message msghash with public key pk = Cg^-S mod p.
The complete proof needed to spend a zerocoin.
Definition: CoinSpend.h:79
const CBigNum & getCoinSerialNumber() const
Definition: CoinSpend.h:86
void setDenom(libzerocoin::CoinDenomination denom)
Definition: CoinSpend.h:104
void setTxOutHash(uint256 txOutHash)
Definition: CoinSpend.h:103
uint256 getTxOutHash() const
Definition: CoinSpend.h:89
SpendType getSpendType() const
Definition: CoinSpend.h:95
CoinDenomination denomination
Definition: CoinSpend.h:123
std::vector< unsigned char > vchSig
Definition: CoinSpend.h:128
A commitment, complete with contents and opening randomness.
Definition: Commitment.h:33
const CBigNum & getCommitmentValue() const
Definition: Commitment.h:47
A Public coin is the part of a coin that is published to the network and what is handled by other cli...
Definition: Coin.h:49
CoinDenomination getDenomination() const
Definition: Coin.h:68
const CBigNum & getValue() const
Definition: Coin.h:66
IntegerGroupParams coinCommitmentGroup
The Quadratic Residue group from which we form a coin as a commitment to a serial number.
Definition: Params.h:169
size_type size() const
Definition: prevector.h:277
iterator begin()
Definition: prevector.h:285
iterator end()
Definition: prevector.h:287
256-bit opaque blob.
Definition: uint256.h:138
@ LOCK
Definition: lockunlock.h:16
#define LogPrint(category,...)
Definition: logging.h:163
@ LEGACYZC
Definition: logging.h:62
bool validateInput(const CTxIn &in, const CTxOut &prevOut, const CTransaction &tx, PublicCoinSpend &publicSpend)
Definition: zpivmodule.cpp:200
libzerocoin::CoinSpend TxInToZerocoinSpend(const CTxIn &txin)
Definition: zpivmodule.cpp:191
void CleanCoinSpendsCache()
Definition: zpivmodule.cpp:226
bool ParseZerocoinPublicSpend(const CTxIn &txIn, const CTransaction &tx, CValidationState &state, PublicCoinSpend &publicSpend)
Definition: zpivmodule.cpp:212
PublicCoinSpend parseCoinSpend(const CTxIn &in)
Definition: zpivmodule.cpp:157
CDataStream ScriptSigToSerializedSpend(const CScript &scriptSig)
Definition: zpivmodule.cpp:148
CoinDenomination AmountToZerocoinDenomination(CAmount amount)
CoinDenomination IntToZerocoinDenomination(int64_t amount)
CAmount ZerocoinDenominationToAmount(const CoinDenomination &denomination)
int ExtractVersionFromSerial(const CBigNum &bnSerial)
Definition: Coin.cpp:61
CBigNum ExtractSerialFromPubKey(const CPubKey pubkey)
Definition: Coin.cpp:108
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:12
@ SER_NETWORK
Definition: serialize.h:174
A mutable version of CTransaction.
Definition: transaction.h:409
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:96
std::vector< CTxIn > vin
Definition: transaction.h:410
libzerocoin::ZerocoinParams * Zerocoin_Params(bool useModulusV1) const
Definition: params.h:260
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:247
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
#define strprintf
Definition: tinyformat.h:1056
bool GetOutput(const uint256 &hash, unsigned int index, CValidationState &state, CTxOut &out)
Retrieve an output (from memory pool, or from disk, if possible)
Definition: validation.cpp:656
#define SCRIPT_OFFSET
Definition: zpivmodule.cpp:96
std::unique_ptr< CoinSpendCache > g_coinspends_cache
Definition: zpivmodule.cpp:143