Skip to content

Commit

Permalink
[zPIV] PublicCoinSpend v4 definition
Browse files Browse the repository at this point in the history
  • Loading branch information
random-zebra committed Oct 21, 2019
1 parent 0f1f881 commit ecd9bcd
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 39 deletions.
14 changes: 13 additions & 1 deletion src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4214,6 +4214,17 @@ bool CWallet::MintsToInputVectorPublicSpend(std::map<CBigNum, CZerocoinMint>& ma
// Default error status if not changed below
receipt.SetStatus(_("Transaction Mint Started"), ZPIV_TXMINT_GENERAL);

// Get the chain tip to determine the active public spend version
int nHeight = 0;
{
LOCK(cs_main);
nHeight = chainActive.Height();
}
if (!nHeight)
return error("%s: Unable to get chain tip height", __func__);

int spendVersion = Params().Zerocoin_PublicSpendVersion(nHeight);

int nLockAttempts = 0;
while (nLockAttempts < 100) {
TRY_LOCK(zpivTracker->cs_spendcache, lockSpendcache);
Expand Down Expand Up @@ -4263,7 +4274,7 @@ bool CWallet::MintsToInputVectorPublicSpend(std::map<CBigNum, CZerocoinMint>& ma

mint.SetOutputIndex(outputIndex);
CTxIn in;
if(!ZPIVModule::createInput(in, mint, hashTxOut)){
if(!ZPIVModule::createInput(in, mint, hashTxOut, spendVersion)) {
receipt.SetStatus(_("Cannot create public spend input"), ZPIV_TXMINT_GENERAL);
return false;
}
Expand Down Expand Up @@ -4485,6 +4496,7 @@ bool CWallet::CreateZerocoinSpendTransaction(
}

//hash with only the output info in it to be used in Signature of Knowledge
// and in CoinRandomness Schnorr Signature
uint256 hashTxOut = txNew.GetHash();

CBlockIndex* pindexCheckpoint = nullptr;
Expand Down
106 changes: 84 additions & 22 deletions src/zpiv/zpivmodule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,66 @@
#include "main.h"
#include "iostream"

PublicCoinSpend::PublicCoinSpend(libzerocoin::ZerocoinParams* params, const uint8_t version,
const CBigNum& serial, const CBigNum& randomness, const uint256& ptxHash, CPubKey* pubkey):
pubCoin(params)
{
this->coinSerialNumber = serial;
this->version = version;
this->spendType = libzerocoin::SpendType::SPEND;
this->ptxHash = ptxHash;

const int coinVersion = getCoinVersion();

if (coinVersion < libzerocoin::PrivateCoin::PUBKEY_VERSION) {
// v1 coins need at least version 4 spends
if (version < PUBSPEND_SCHNORR) {
std::string errMsg = strprintf("Unable to create PublicCoinSpend version %d with coin version 1. "
"Minimum spend version required: %d", version, PUBSPEND_SCHNORR);
throw std::runtime_error(errMsg);
}

} else {
// pubkey available only from v2 coins onwards
this->pubkey = *pubkey;
}

if (version < PUBSPEND_SCHNORR)
this->randomness = randomness;
else
this->schnorrSig = libzerocoin::CoinRandomnessSchnorrSignature(params, randomness, ptxHash);

}

bool PublicCoinSpend::Verify(const libzerocoin::Accumulator& a, bool verifyParams) const {
return validate();
}

bool PublicCoinSpend::validate() const {
libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false);
// Check that it opens to the input values
libzerocoin::Commitment commitment(
&params->coinCommitmentGroup, getCoinSerialNumber(), randomness);
bool fUseV1Params = getCoinVersion() < libzerocoin::PrivateCoin::PUBKEY_VERSION;
if (version < PUBSPEND_SCHNORR) {
// spend contains the randomness of the coin
if (fUseV1Params) {
// Only v2+ coins can publish the randomness
std::string errMsg = strprintf("PublicCoinSpend version %d with coin version 1 not allowed. "
"Minimum spend version required: %d", version, PUBSPEND_SCHNORR);
return error("%s: %s", __func__, errMsg);
}

if (commitment.getCommitmentValue() != pubCoin.getValue()){
return error("%s: commitments values are not equal", __func__);
// Check that the coin is a commitment to serial and randomness.
libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false);
libzerocoin::Commitment comm(&params->coinCommitmentGroup, getCoinSerialNumber(), randomness);
if (comm.getCommitmentValue() != pubCoin.getValue()) {
return error("%s: commitments values are not equal", __func__);
}
} else {
// spend contains a shnorr signature of ptxHash with the randomness of the coin
libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(fUseV1Params);
if (!schnorrSig.Verify(params, getCoinSerialNumber(), pubCoin.getValue(), getTxOutHash())) {
return error("%s: schnorr signature does not verify", __func__);
}
}

// Now check that the signature validates with the serial
if (!HasValidSignature()) {
return error("%s: signature invalid", __func__);;
Expand All @@ -39,29 +86,41 @@ const uint256 PublicCoinSpend::signatureHash() const

namespace ZPIVModule {

bool createInput(CTxIn &in, CZerocoinMint &mint, uint256 hashTxOut) {
libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(false);
uint8_t nVersion = mint.GetVersion();
if (nVersion < libzerocoin::PrivateCoin::PUBKEY_VERSION) {
// No v1 serials accepted anymore.
return error("%s: failed to set zPIV privkey mint version=%d", __func__, nVersion);
bool createInput(CTxIn &in, CZerocoinMint &mint, uint256 hashTxOut, const int spendVersion) {
bool fUseV1Params = mint.GetVersion() < libzerocoin::PrivateCoin::PUBKEY_VERSION;
libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(fUseV1Params);
if (fUseV1Params && spendVersion < PUBSPEND_SCHNORR) {
// v1 coins need at least version 4 spends
std::string errMsg = strprintf("Unable to create PublicCoinSpend version %d with coin version 1. "
"Minimum spend version required: %d", spendVersion, PUBSPEND_SCHNORR);
return error("%s: %s", __func__, errMsg);
}

CKey key;
if (!mint.GetKeyPair(key))
return error("%s: failed to set zPIV privkey mint version=%d", __func__, nVersion);

PublicCoinSpend spend(params, mint.GetSerialNumber(), mint.GetRandomness(), key.GetPubKey());
spend.setTxOutHash(hashTxOut);
CPubKey pk;
CPubKey* pk_ptr = nullptr;
if (!fUseV1Params) {
if (!mint.GetKeyPair(key))
return error("%s: failed to set zPIV privkey mint.", __func__);
pk = key.GetPubKey();
pk_ptr = &pk;
}

PublicCoinSpend spend(params, spendVersion, mint.GetSerialNumber(),
mint.GetRandomness(), hashTxOut, pk_ptr);

spend.outputIndex = mint.GetOutputIndex();
spend.txHash = mint.GetTxHash();
spend.setDenom(mint.GetDenomination());

std::vector<unsigned char> vchSig;
if (!key.Sign(spend.signatureHash(), vchSig))
throw std::runtime_error("ZPIVModule failed to sign signatureHash\n");
if (!fUseV1Params) {
if (!key.Sign(spend.signatureHash(), vchSig))
throw std::runtime_error("ZPIVModule failed to sign signatureHash\n");

spend.setVchSig(vchSig);
spend.setVchSig(vchSig);
}

CDataStream ser(SER_NETWORK, PROTOCOL_VERSION);
ser << spend;
Expand All @@ -75,10 +134,14 @@ namespace ZPIVModule {
}

PublicCoinSpend parseCoinSpend(const CTxIn &in) {
libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(false);
// skip opcode and data-len
uint8_t byteskip(in.scriptSig[1]);
byteskip += 2;
std::vector<char, zero_after_free_allocator<char> > data;
data.insert(data.end(), in.scriptSig.begin() + 4, in.scriptSig.end());
data.insert(data.end(), in.scriptSig.begin() + byteskip, in.scriptSig.end());
CDataStream serializedCoinSpend(data, SER_NETWORK, PROTOCOL_VERSION);
libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(false);

return PublicCoinSpend(params, serializedCoinSpend);
}

Expand Down Expand Up @@ -112,7 +175,6 @@ namespace ZPIVModule {
libzerocoin::IntToZerocoinDenomination(in.nSequence)) != prevOut.nValue) {
return error("PublicCoinSpend validateInput :: input nSequence different to prevout value");
}

return publicSpend.validate();
}

Expand Down
32 changes: 16 additions & 16 deletions src/zpiv/zpivmodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "libzerocoin/Denominations.h"
#include "libzerocoin/CoinSpend.h"
#include "libzerocoin/Coin.h"
#include "libzerocoin/CoinRandomnessSchnorrSignature.h"
#include "libzerocoin/SpendType.h"
#include "primitives/transaction.h"
#include "script/script.h"
Expand All @@ -19,28 +20,21 @@
#include "zpiv/zerocoin.h"
#include "chainparams.h"

static int const COIN_SPEND_PUBLIC_SPEND_VERSION = 3;
static int const PUBSPEND_SCHNORR = 4;

class PublicCoinSpend : public libzerocoin::CoinSpend{
class PublicCoinSpend : public libzerocoin::CoinSpend {
public:

PublicCoinSpend(libzerocoin::ZerocoinParams* params):pubCoin(params){};
PublicCoinSpend(libzerocoin::ZerocoinParams* params): pubCoin(params) {};

PublicCoinSpend(libzerocoin::ZerocoinParams* params,
CBigNum serial, CBigNum randomness, CPubKey pubkey):pubCoin(params){
this->coinSerialNumber = serial;
this->randomness = randomness;
this->pubkey = pubkey;
this->spendType = libzerocoin::SpendType::SPEND;
this->version = COIN_SPEND_PUBLIC_SPEND_VERSION;
};
PublicCoinSpend(libzerocoin::ZerocoinParams* params, const uint8_t version, const CBigNum& serial, const CBigNum& randomness, const uint256& ptxHash, CPubKey* pubkey);

~PublicCoinSpend(){};

template <typename Stream>
PublicCoinSpend(
libzerocoin::ZerocoinParams* params,
Stream& strm):pubCoin(params){
Stream& strm): pubCoin(params) {
strm >> *this;
this->spendType = libzerocoin::SpendType::SPEND;
}
Expand All @@ -52,6 +46,7 @@ class PublicCoinSpend : public libzerocoin::CoinSpend{

// Members
CBigNum randomness;
libzerocoin::CoinRandomnessSchnorrSignature schnorrSig;
// prev out values
uint256 txHash = 0;
unsigned int outputIndex = -1;
Expand All @@ -63,17 +58,22 @@ class PublicCoinSpend : public libzerocoin::CoinSpend{
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(version);
READWRITE(coinSerialNumber);
READWRITE(randomness);
READWRITE(pubkey);
READWRITE(vchSig);
if (version < PUBSPEND_SCHNORR)
READWRITE(randomness);
else
READWRITE(schnorrSig);
if (libzerocoin::ExtractVersionFromSerial(coinSerialNumber) >= libzerocoin::PrivateCoin::PUBKEY_VERSION) {
READWRITE(pubkey);
READWRITE(vchSig);
}
}
};


class CValidationState;

namespace ZPIVModule {
bool createInput(CTxIn &in, CZerocoinMint& mint, uint256 hashTxOut);
bool createInput(CTxIn &in, CZerocoinMint& mint, uint256 hashTxOut, const int spendVersion);
PublicCoinSpend parseCoinSpend(const CTxIn &in);
bool parseCoinSpend(const CTxIn &in, const CTransaction& tx, const CTxOut &prevOut, PublicCoinSpend& publicCoinSpend);
bool validateInput(const CTxIn &in, const CTxOut &prevOut, const CTransaction& tx, PublicCoinSpend& ret);
Expand Down

0 comments on commit ecd9bcd

Please sign in to comment.